Gulp tasks not running synchronously - gulp

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.

Related

execute tasks synchronously in 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();
};
});

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 and glob-stream task finishing too soon

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.

How to make gulp remove deleted files while watching on a particular glob pattern?

I have a gulp watch task over a glob, looking for changes and updating an output folder. It is successfully able to updated changed files, add new files but it fails to remove deleted files.
The callback looks like this:
var cb = function (event) {
console.log('Moving assets...');
return gulp.src('app/assets/**/*', {base: 'app'})
.pipe(changed('build/assets'))
.pipe(gulp.dest('build'));
};
The gulp watch task is this:
gulp.watch('app/assets/**/*', cb);
I know that the gulp watch is running fine because the callback receives all the deleted events. But the callback itself is unable to remove the deleted file from the build/assets/ folder.
Do I have to explicitly handle the deleted event or am I missing something out?
The question is old, but I think it's still relevant.
Here is the solution I came up with, based on ondaplana answer in this github issue and the documentation of the gulp modules that are used:
Basically, it uses gulp-watch instead of gulp native watch function, to pipe gulp-filter and del modules.
var filter = require('gulp-filter');
var vinylPaths = require('vinyl-paths');
var del = require('del');
var watch = require('gulp-watch');
var notDeletedFilter = filter(
function(file) {
return file.event !== 'unlink' && file.event !== 'unlinkDir';
},
{restore: true}
);
notDeletedFilter.restore
.pipe(gulp.dest('dist'))
.pipe(vinylPaths(del));
//use gulp-watch instead of gulp native watch function
watch(['app/assets/**/*'], {events: ['add', 'change', 'unlink', 'unlinkDir']})
.pipe(notDeletedFilter)
.pipe(anyModule())
.pipe(gulp.dest('build'));
Documentation :
Gulp recipes