I've got a fairly simple Gulp task that simply scoops some files that match a glob and uploads them to Google Cloud via the gulp-gcloud-publish package as in the following:
const gcloud = require('gulp-gcloud-publish');
function publish() {
return src(dest + '/*/app.*')
.pipe(gcloud({
//options
}));
}
This works fine, but it uploads the files sequentially. There are a few of them, so this takes a little while and I'd rather be able to upload them all in parallel sets.
I tried instead to glob it myself:
const glob = require('glob');
const gcloud = require('gulp-gcloud-publish');
const { src } = require('gulp');
function publish() {
const files = glob.sync(path);
let stream;
files.forEach(function(file) {
stream = src(file)
.pipe(gcloud({
//...
}));
return stream;
});
}
This worked great - the task still runs sequentially, but the uploads start without waiting on the last to complete. However, for whatever reason, while glob captures the relative path to the file, when I put that file path into src, gulp drops it down to just the file name itself (as seen if I tap the pipe before gcloud).
So I tried setting the base option instead:
const glob = require('glob');
const gcloud = require('gulp-gcloud-publish');
const { src } = require('gulp');
function publish() {
const files = glob.sync(path);
let stream;
files.forEach(function(file) {
stream = src(file, {base: '.')
.pipe(gcloud({
//...
}));
return stream;
});
}
Unfortunately, now src captures the absolute path to the file instead of just the file and its relative parent. I also just noticed that my glob is removing periods from file names that contain more than one (e.g. app.map.js is turning into appmap.js), so that's not right either.
Scrapping the last two attempts then, is there any way to run the pipe of an operation that otherwise works perfectly fine and run the pipes within a task in parallel?
Related
I'm new to gulp. Trying to optimize the images and convert them into webp format. I was able to achieve that using gulp-webp. But it seems there are now two version of the images inside my dist/img folder one is the original and a webp version. So how do I get only the webp not the original one inside my dist/img folder?
Here how my project directories look like:
project
|-dist
|-css
|-img
|-js
|-src
|-css
|-img
|-js
gulp.js
...
Here is webp conversion function:
function webpImage() {
return src('dist/img/**/*.{jpg,png}')
.pipe(imagewebp())
.pipe(dest('dist/img'))
}
I would first say you should not delete source file, it is ok to keep them. What you want to do is having to different destinations. One of which should be deployed (the compiled, minified and webp for example) and the other should be version and used in your cdci pipelines perhaps.
But then, if you really want to remove the source file, you can use gulp-clean while being in a gulp script.
Your gulp clean script could look like that :
const { src, task } = require('gulp');
const clean = require("gulp-clean");
const logger = require('node-color-log');
function cleanImagesTask() {
const root = "path/to/images/you/want/to/delete";
logger.color('yellow').log(`Clean images`);
return src(root,{allowEmpty: true},{read: false}).pipe(clean({force:true}));
};
const cleanImagesFolder = task('clean:images', cleanImagesTask);
exports.cleanImagesFolder = cleanImagesFolder;
And if you want to deploy in a different dest, could use something similar to :
const { src, dest, task } = require( 'gulp' );
const logger = require('node-color-log');
function copyImagesToDest(callback) {
const imagesSource = "path/to/your/images/**/*";
const imagesDestination = "path/to/destination/";
logger.color('green').log(`Copy images from ${artifactData} to: ${destination}`);
return src(imagesSource)
.pipe(dest(destination))
.on('end', function () {
logger.color('green').log(`Copy to: ${destination}`);
callback();
});
};
const copyImages = task('copy:images', copyImagesToDest);
exports.copyImages = copyImages ;
I'd like to unzip multiple zip files that are inside a single folder. Every unzipped file will be unpacked into a folder with the same name as the original zip file and added as a sub folder to the original folder containing the original zips.
Something like this:
parent(folder)
-a.zip
-b.zip
-c.zip
would become:
parent(folder)
-a(folder)
--a.zip contents here
-b(folder)
--b.zip contents here
-c(folder)
--c.zip contents here
I believe the code i have so far is a nice try but seems like it's executing asynchronously in the pipeline (i'm obviously not a Gulp expert). All the zip files are being looked at but only the last one seems to get all the content, and then some from other zips. Run it with one zip file in the folder and it works perfectly.
var zipsPath = 'src/';
var currentZipFileName;
function getZips(dir) {
return fs.readdirSync(dir)
.filter(function (file) {
return file.indexOf(".zip") > 0;
});
}
gulp.task('init', function (done) {
var zips = getZips(zipsPath);
var tasks = zips.map(function (zip) {
console.log("zip", zip, path.join(zipsPath, zip));
return gulp.src(path.join(zipsPath, zip), {
base: '.'
})
.pipe(tap(function (file, t) {
currentZipFileName = path.basename(file.path);
}))
.pipe(unzip({ keepEmpty : true }))
.pipe(gulp.dest(function (path) {
var folderName = currentZipFileName.replace(".zip", "");
var destination = "./src/" + folderName;
//console.log("destination", destination);
return destination;
}))
.on('end', function() {
console.log('done');
done();
});
});
return tasks;
});
Expected results: all the zip files should be unpacked.
Actual results: most of the content is being dumped into the last zip file looked at.
Thanks for the help
Your problem lies here:
.pipe(tap(function (file, t) {
currentZipFileName = path.basename(file.path);
}))
You are trying to set a variable in one pipe to use in a later pipe. That doesn't work, there are a few questions here about it, but it just doesn't work - your variable will probably have the last value in it when the gulp.dests start firing or undefined - I think it is based on unpredictable timing.
In any case you don't need to set that variable - you already have the value of the desired folder name in your zips.map(zip) {} the zip item. You can use that in the gulp.dest just fine.
gulp.task('init', function (done) {
var zips = getZips(zipsPath);
var tasks = zips.map(function (zip) {
return gulp.src(zipsPath + "/" + zip)
// .pipe(tap(function (file, t) {
// currentZipFileName = path.basename(file.path);
// }))
.pipe(unzip({ keepEmpty: true }))
.pipe(gulp.dest(path.join("src", path.basename(zip, ".zip"))))
.on('end', function() {
done();
});
});
return tasks;
});
Also avoid using path.join in your gulp.src for the reasons stated here: gulpjs docs on glob separators:
The separator in a glob is always the / character - regardless of the operating system - even in Windows where the path separator is \\. In a glob, \\ is reserved as the escape character.
Avoid using Node's path methods, like path.join, to create globs. On Windows, it produces an invalid glob because Node uses \\ as the separator. Also avoid the __dirname global, __filename global, or process.cwd() for the same reasons.
A lot of examples of gulp setups are using the common JS pattern. Gulp tasks are defined follows:
myGulpTask.js
const gulp = require('gulp');
const paths = {
src = './src',
dest = './dest'
}
const myGulpTask = function() {
return gulp.src(paths.srcFoo)
.pipe() // do stuff
.pipe(gulp.dest(paths.dest));
}
module.exports = myGulpTask;
gulp.task('my-gulp-task', myGulpTask);
This allows you to use this gulp task using:
$ npm run gulp myGulpTask
But since the task is directly assigned, would it make sense to define the export as follows:
//...
const myGulpTask = module.exports = function() {
return gulp.src(paths.srcFoo)
.pipe() // do stuff
.pipe(gulp.dest(paths.dest))
}
gulp.task('my-gulp-task', myGulpTask);
//...
Maybe it's sweating the small stuff, or is there a difference in these two module declarations?
There is no difference in either way, the first one is more friendly and easy to read.
I'm working to copy a file style.scss from specific directory to multiple folders that start with skin-.
In fact, i don't know how to tell gulp to choose folders that start with this string skin-.
Here is my gulp code:
// Copy Files
gulp.task( "copyFiles" , function() {
return gulp.src( "app/scss/style.scss" )
.pipe( gulp.dest( "app/scss/skins/skin-*" ) );
});
At command prompt, it says that the task is running but with no result.
I have searched a lot around for that, but i didn't find a method. I found this question here which near to my question context, but it didn't help! Gulp copy single file (src pipe dest) with wildcarded directory
Modifying only slightly #davidmdem's answer at saving to multiple destinations:
const gulp = require("gulp");
const glob = require("glob");
const destinationFolders = glob.sync("app/scss/skins/skin-*");
gulp.task('copyFiles', function () {
var stream = gulp.src("app/scss/style.scss");
destinationFolders.forEach(function (skinFolder) {
stream = stream.pipe(gulp.dest(skinFolder));
});
return stream;
});
You cannot put a glob into gulp.dest as you are trying in your question.
I have a Gulp task that uses glob-stream to recursively loop through directories and files to perform a task, similar to below, but far more elaborate:
var gs = require('glob-stream');
var config = {
PATH: 'some/path/*.*'
}
function doSomething(filePath) {
var stream = gs.create(filePath);
// Do something
return gs.on('data', doSomething);
}
gulp.task('compile', function() {
var filePath = config.PATH;
return doSomething(filePath);
});
I can have the task achieve the results and compile what I need, but unfortunately Gulp believes the task has finished while it's still running, causing issues in my build process - How can I avoid this? I'm already using run-sequence but to no effect.
Why are you manually walking the directory tree with a recursive function? Why not just let glob-stream do the work for you? Then you only have to take care of the //Do something part:
var config = {
PATH: 'some/path/**' //glob pattern for all subfolder and files
};
function doSomething(filePath) {
//Do something
}
gulp.task('compile', function() {
var stream = gs.create(config.PATH);
stream.on('data', doSomething);
return stream;
});
gulp.task('secondTask', function() {
console.log('secondTask');
});
gulp.task('default', function() {
runSequence('compile', 'secondTask');
});
The some/path/** glob pattern creates a stream of all folders and files below some/path/, so you don't have to implement the recursive tree walk yourself.
Note that the compile task returns the stream. Otherwise gulp can't tell when the compile task has completed and starts running secondTask before compile has finished.