execute tasks synchronously in gulp - gulp

I have read online that 'run-sequence' will make sure all specified tasks will run synchronously. For some reason this is not true in my case. Am I missing something?
'convertSassToCss' is the task that does not work as intended
If I would run tasks 'cleanAllCss' and 'convertSassToCss' seperatelly, it would work.
The idea here is to first remove all css files from directory, then convert all sass files into css and place the into the cleaned dir
/// <binding BeforeBuild='clean, min:css' Clean='clean' />
"use strict";
var gulp = require("gulp"),
rimraf = require("rimraf"),
concat = require("gulp-concat"),
cssmin = require("gulp-cssmin"),
uglify = require("gulp-uglify"),
sass = require('gulp-sass'),
rename = require('gulp-rename'),
del = require('del'),
runSequence = require('run-sequence');
var paths = {
webroot: "./wwwroot/"
};
paths.cssPath = paths.webroot + "css/*.css";
paths.cssOutputPath = paths.webroot + "css";
//sass
paths.sassPath = paths.webroot + "sass/**/*.scss";
paths.sassOutputPath = paths.webroot + "./css/file";
gulp.task("cleanAllCss", function (cb) {
console.log("2 -- Removing all CSS files");
del([paths.cssOutputPath + "/*.css"], cb);
console.log("2 -- DONE - Removed all css files");
});
gulp.task("convertSassToCss", function (cb) {
console.log("3 -- Converting all SASS files into corresponding CSS");
gulp.src(paths.sassPath)
.pipe(sass())
.pipe(gulp.dest(paths.cssOutputPath));
console.log("3 -- DONE - Converting all SASS files into corresponding CSS");
});
//not working, should run in sequence
gulp.task("convertAllSassIntoCssMin", function (callback) {
console.log("1 -- Converting all SASS files into corresponding min CSS files")
runSequence('cleanAllCss', 'convertSassToCss', callback);
console.log("1 -- DONE - Converting all SASS files into corresponding min CSS files")
});

I cannot speak to run-sequence as I haven't used it before.
However, you can run tasks in sequence by using Gulp's task dependency feature, where a task will NOT run until it's dependencies have finished running.
Your new tasks signatures
cleanAllCss stays the same:
gulp.task("cleanAllCss", function (cb) { ... }
convertSassToCss changes to:
gulp.task("convertSassToCss", ['cleanAllCss'], function (cb) { ... }
convertAllSassIntoCssMin changes to:
gulp.task("convertAllSassIntoCssMin", ['convertSassToCss'], function (cb) { ... }
This ensures that convertAllSassIntoCssMin won't run until convertSassToCss has finished which in turn won't run until cleanAllCss has finished.
Refer to gulp deps:
deps
Type: Array
An array of tasks to be executed and completed before your task will
run.
gulp.task('mytask', ['array', 'of', 'task', 'names'], function() {
// Do stuff }); Note: Are your tasks running before the dependencies
are complete? Make sure your dependency tasks are correctly using the
async run hints: take in a callback or return a promise or event
stream.
You can also omit the function if you only want to run a bundle of
dependency tasks:
gulp.task('build', ['array', 'of', 'task', 'names']); Note: The tasks
will run in parallel (all at once), so don't assume that the tasks
will start/finish in order.

The problem is in the cleanAllCss task. The second parameter accepted by del is options, not the callback which you're trying to pass. The callback is never executed. Try running it manually when the removal is finished.
gulp.task("cleanAllCss", function (cb) {
console.log("2 -- Removing all CSS files");
del([paths.cssOutputPath + "/*.css"]).then(paths => {
console.log("2 -- DONE - Removed all css files");
cb();
};
});

Related

only last callback is being called in gulp file

In gulpfile, I've 3 tasks, when I run the following code, it only executes the callback of the last task. I want that if I run the gulp command, after completion of clean task, it should execute callback of copy:db & default task.
Gulp.task('clean', function () {
console.log('Clean');
return Gulp.src("./dbSchema/*")
.pipe(VinylPaths(Del));
})
Gulp.task('copy:db', Gulp.series("clean"), function () {
console.log('Copy DB');
return Gulp.src("./db/*")
.pipe(Gulp.dest("./dbSchema"));
})
Gulp.task('default', Gulp.series("copy:db"), function () {
console.log('defaulp');
return TypeScriptProject.src()
.pipe(TypeScriptProject())
.js.pipe(Gulp.dest('dist'));
});
When I run the command gulp, it shows the following log.
[12:46:37] Starting 'default'...
[12:46:37] Starting 'copy:db'...
[12:46:37] Starting 'clean'...
Clean
[12:46:37] Finished 'clean' after 26 ms
[12:46:37] Finished 'copy:db' after 28 ms
[12:46:37] Finished 'default' after 31 ms
Can anyone tell me where am I going wrong?
To get your code working how you’ve described, the callback functions need to be passed as a paramater to .series(). Eg:
Gulp.task('clean', function () {
console.log('Clean');
return Gulp.src("./dbSchema/*")
.pipe(VinylPaths(Del));
})
Gulp.task('copy:db', Gulp.series(clean, function () {
console.log('Copy DB');
return Gulp.src("./db/*")
.pipe(Gulp.dest("./dbSchema"));
}))
Gulp.task('default', Gulp.series(copy:db, function () {
console.log('defaulp');
return TypeScriptProject.src()
.pipe(TypeScriptProject())
.js.pipe(Gulp.dest('dist'));
}));
IMHO, it would be simpler to have three totally separate tasks:
Gulp.task('clean', function () {
console.log('Clean');
return Gulp.src("./dbSchema/*")
.pipe(VinylPaths(Del));
});
Gulp.task('copy:db', function () {
console.log('Copy DB');
return Gulp.src("./db/*")
.pipe(Gulp.dest("./dbSchema"));
});
Gulp.task('default', function () {
console.log('defaulp');
return TypeScriptProject.src()
.pipe(TypeScriptProject())
.js.pipe(Gulp.dest('dist'));
});
and then call them with either:
Gulp.task('default', gulp.series(clean, copy:db, js));
or
Gulp.task('default', gulp.series(clean, gulp.parallel(copy:db, js)));
Hope that helps :)
Additional Notes:
The naming convention for gulp/vars is normally camelCase, eg: gulp and typeScriptProject not Gulp or TypeScriptProject.
You can totally remove the need to ever write gulp. by using: var {gulp, task, src, dest, watch, series, parallel} = require('gulp');
Rather than defining your tasks directly, you can make your code easier to read by using CommonJS exports module notation to declare tasks.
Makes life a little easier if you are consistent when with quotes, rather than mixing singles and doubles. Both allow globbing
Following Gulp’s own documentation is perhaps the place to start, their sample code on github has some great examples of setting up a basic gulpfile.
If you wrap all that up you get this:
/*
* Example of requires with gulp methods also requiring gulp.
*/
var {
gulp,
dest,
series,
parallel,
src,
task,
watch
} = require('gulp'),
vinylPaths = require('vinyl-paths'), // may not be required, see note in clean func.
del = require('del'),
ts = require('gulp-typescript');
/*
* Added a basic TypeScript Project so the example is complete and could run.
*/
var typeScriptProject = ts.createProject({
declaration: true
});
/*
* Your tasks converted to plain/standard js functions.
*/
function clean () {
return src('dbSchema/*')
.pipe(vinylPaths(del));
// Looking at your example code the vinylPaths is redundant,
// as long as you’re using del ^2.0 it will return its promise,
// so you could replace the above with:
return del([ 'dbSchema' ]);
}
function copyDb () {
return src('db/*')
.pipe(dest('dbSchema'));
}
function scripts () {
// example src path
return src('lib/*.ts')
.pipe(typeScriptProject())
.pipe(dest('dist'));
}
/*
* By defining all the tasks separately it makes it really clear how the tasks will run.
*/
var build = gulp.series (
clean,
gulp.parallel (
copyDb,
scripts
)
);
/*
* Example of using `exports` module notation to declare tasks.
*/
exports.clean = clean;
exports.copyDb = copyDb;
exports.scripts = scripts;
exports.build = build;
/*
* Good practise to define the default task as a reference to another task.
*/
exports.default = build;

Why subTasks not created in my task runner explorer?

I am working on my Gulp tutorial(using this site: http://www.davepaquette.com/archive/2014/10/08/how-to-use-gulp-in-visual-studio.aspx).
Here is gulpFile.js:
// include plug-ins
var gulp = require('gulp');
var concat = require('gulp-concat');
var uglify = require('gulp-uglify');
var del = require('del');
var config = {
//Include all js files but exclude any min.js files
src: ['app/**/*.js', '!app/**/*.min.js']
}
//delete the output file(s)
gulp.task('clean', function () {
//del is an async function and not a gulp plugin (just standard nodejs)
//It returns a promise, so make sure you return that from this task function
// so gulp knows when the delete is complete
return del(['app/all.min.js']);
});
// Combine and minify all files from the app folder
// This tasks depends on the clean task which means gulp will ensure that the
// Clean task is completed before running the scripts task.
gulp.task('scripts', ['clean'], function () {
return gulp.src(config.src)
.pipe(uglify())
.pipe(concat('all.min.js'))
.pipe(gulp.dest('app/'));
});
gulp.task('watch', function () {
return gulp.watch(config.src, ['scripts']);
});
//Set a default tasks
gulp.task('default', ['scripts'], function () { });
Here is task runner explorer:
And here how task runner explorer looks in tutorial site above:
Any idea why I dont see subTasks in my task runner explorer?
This is the only way so far that I've been able to fix this.
After adding a task, rename your gulpfile to something else and then close Task Runner Explorer.
Change the renamed file back to gulpfile.js, then reopen Task Runner Explorer.
You should see your gulpfile tasks updated.

Gulp task executed by watch using cached config stream

I'm trying use gulp to bundle and minify my files using gulp-bundle-assets. Running the tasks on their own is fine. My problem is using gulp.watch to watch for any changes in my config file and re-bundle my scripts.
The first time the watch executes everything works correctly. On successive occasions everything runs, but the exact same files are bundled - any changes in the config are ignored.
If I run my "bundle" task while the watch is running, "bundle" will use the current configuration. While successive watches will continue to use the configuration on the first execution.
My guess would be the data for the stream retrieved by gulp.src is cached. So how do I tell it to always get the latest version?
var gulp = require('gulp');
var bundle = require('gulp-bundle-assets');
var del = require('del');
var index = 0;
gulp.task('bundle', function () {
console.log('Bundling files ' + (index++));
return gulp.src('./bundle.config.js')
.pipe(bundle())
.pipe(gulp.dest('./bundles'));
});
gulp.task('watch', function () {
gulp.watch(['./scripts/**/*.{js,css}', './bundle.config.js'], ['clean', 'bundle']);
});
gulp.task('clean', function (cb) {
console.log('Cleaning files');
del(['./bundles/**/*'], cb);
});
An alternative I tried was to use watch(...).on, and calling gulp.run, but that didn't fix the problem, either. I also tried pasting the code from the bundle task in to the on callback, but still got the same result.
The culprit isn't gulp.src(), but bundle(). The gulp-bundle-assets plugin uses require() to load your bundle.config.js. Since Node.js caches return values from require() you always get the same config object after the file is loaded for the first time.
The solution is to invalidate the require cache in your bundle task:
var gulp = require('gulp');
var bundle = require('gulp-bundle-assets');
var del = require('del');
var index = 0;
gulp.task('bundle', ['clean'], function () { // run clean task before bundle task
// invalidate require cache for ./bundle.config.js
delete require.cache[require.resolve('./bundle.config.js')];
console.log('Bundling files ' + (index++));
return gulp.src('./bundle.config.js')
.pipe(bundle())
.pipe(gulp.dest('./bundles'));
});
gulp.task('watch', function () {
gulp.watch(['./scripts/**/*.{js,css}',
'./bundle.config.js'], ['bundle']); // only run bundle task
});
gulp.task('clean', function () {
console.log('Cleaning files');
return del(['./bundles/**/*']); // return promise object
});
Unrelated to your problem, but I also fixed your clean task. The way you had it set up didn't work.

Gulp tasks not running synchronously

I am trying to install packages through bower, and once the installation is finished, I want the files to be moved from dist folder to its parent, and then delete the dist folder. But somehow, its not working properly.
var gulp = require('gulp'),
bower = require('gulp-bower'),
del = require('del'),
fs = require('fs'),
path = require('path'),
merge = require('merge-stream');
vinylPaths = require('vinyl-paths');
runSequence = require('run-sequence');
var appPath="./www";
var folders = getFolders(appPath);
/* Function to get folders present in www */
function getFolders(dir) {
return fs.readdirSync(dir)
.filter(function(file) {
return fs.statSync(path.join(dir, file)).isDirectory();
});
}
gulp.task('clean', function (){
var tasks = folders.map(function(folder) {
return gulp.src(path.join(appPath, folder))
.pipe(vinylPaths(del))
});
});
/* Gulp task to run bower install */
gulp.task('bower', ['clean'], function() {
return bower({cmd: "install"});
});
/* Gulp task to copy files from dist folder to their parent folders */
gulp.task('moveFiles', ['bower'], function (){
var tasks = folders.map(function(folder) {
console.log("FOLDER", folder);
return gulp.src(path.join(appPath, folder, '/dist/**/*'))
.pipe(gulp.dest(path.join(appPath, folder )));
});
return tasks;
});
/* Gulp task to clean the dist folder after files have been copied */
gulp.task('delete-dist-folder', ['moveFiles'], function () {
var tasks = folders.map(function(folder) {
return gulp.src(path.join(appPath, folder, '/dist'))
.pipe(vinylPaths(del))
});
return tasks;
});
gulp.task('default', ['delete-dist-folder']);
This is what I wrote till now.
After bower, the rest two tasks don't run. But if I run them individually, they work perfectly fine.
I am unable to figure out what is going wrong here. Any help would be greatly appreciated.
The problem is that you return arrays of event streams. Look at your delete-dist-folder task. You return tasks and tasks is created from calling .map on an array. So tasks is an array (of event streams).
Gulp does not know what to do with your arrays and assumes that your tasks are synchronous. There are only 3 ways to mark a task as asynchronous: 1) return an even stream; Gulp will wait for the stream to end, 2) return a promise; Gulp will wait for the promise to be resolved or rejected, or 3) declare your task callback to take a single parameter which you'll call when your task is done; Gulp will wait for the callback to be called. An array of event streams does not correspond to any of these options.
The Gulp wiki suggest using merge-stream to return more than one stream from a task. Judging by the code of merge-stream, and supposing you imported merge-stream as merge, you could do return merge.apply(undefined, tasks).
Side node: in your clean task you forgot to return a value.
I had a similar issue a while back when nesting task(requiring one task in another). So to solve this issue and run task in sequence I used run-sequence.
You seem to have installed run-sequence. Use it this way:
runSequence = require('run-sequence');
gulp.task('default', function(callback) {
runSequence('clean', 'bower', 'moveFiles', 'delete-dist-folder',
callback);
});
Hope this might help you. You can refer this for any help.
This is a temporary solution untill gulp 4.0, which will include option to configure your task run in parallel or sequentially.

Gulp, make a task use another tasks output

I'm building a workflow with Gulp for handling e-mails and I'm having some trouble.
My gulp file compiles a jade file into html, and I then want to run another task on the html file that this task outputs. I have set it up like shown in the code below.
The problem is that, even though the console says that the 'emailBuilder' task is run, it's not doing anything. But if I run 'emailBuilder' separately after 'gulp build' it does do what it should.
Image shows that emailBuilder is run last, still doesn't do what it should.
How can I make this work smoothly?
//-----------------------------------------------------
// ### REQUIREMENTS
//-------------------
var gulp = require('gulp'),
jade = require('gulp-jade'),
sass = require('gulp-sass'),
del = require('del'),
emailBuilder = require('gulp-email-builder'),
runSequence = require('gulp-run-sequence');
//-----------------------------------------------------
// ### Clean
// `gulp clean`
//-------------------
// Clean our compiled folder before we generate new content into it
gulp.task('clean', function (cb) {
del([
// here we use a globbing pattern to match everything inside the `compiled` folder, except our gitkeep file
'compiled/**/*',
], { dot: true },
cb);
});
//-----------------------------------------------------
// ### Compile SCSS
// `gulp compile-css`
//-------------------
gulp.task('compile-scss', function () {
gulp.src('./src/scss/*.scss')
.pipe(sass().on('error', sass.logError))
.pipe(gulp.dest('./compiled/css'));
});
//-----------------------------------------------------
// ### Build Jade templates
// `gulp templates`
//-------------------
gulp.task('templates', function() {
var YOUR_LOCALS = {};
gulp.src('./src/templates/*.jade')
.pipe(jade({
pretty: true,
locals: YOUR_LOCALS
}))
.pipe(gulp.dest('./compiled/templates/'));
});
//-----------------------------------------------------
// ### Inline CSS, send tests
// `gulp compile-css`
//-------------------
gulp.task('emailBuilder', function() {
return gulp.src(['./compiled/templates/*.html'])
.pipe(emailBuilder())
.pipe(gulp.dest('./compiled/templates/'));
});
//-----------------------------------------------------
// ### Build
// `gulp build` - Clean up the builds directory and do a complete build.
//-------------------
gulp.task('build', function(callback) {
runSequence(
'clean',
'compile-scss',
'templates',
'emailBuilder',
callback);
});
You need to add a return statement to your tasks. According to the gulp API docs on tasks:
Make sure your dependency tasks are correctly using the async run hints: take in a callback or return a promise or event stream.
If you don't return a promise or the event stream (or use a callback) the following tasks won't know when the previous one is done.
I suspect that in your case the emailBuilder task is run too soon.