I'm trying to run a set of tasks in series, that is one after the other in Gulp 4.0 however when I add my 3rd task my gulp code breaks.
gulp.task('concat-js', (done) => {
gulp.src([
'app1.js',
'app2.js',
])
.pipe(concat("app.js"))
.pipe(gulp.dest('build'))
done();
});
gulp.task('concat-css', (done) => {
gulp.src([
'.styles1.css',
'.style2.css'
])
.pipe(concat("app.css"))
.pipe(gulp.dest('build'))
done();
});
gulp.task('minify-js', (done) => {
gulp.src('./build/app.js')
.pipe(uglify())
.pipe(gulp.dest('./build/'))
done();
})
//this works & creates /build with the app.js & app.css files
gulp.task('build-production-static-resource', gulp.series('concat-js', 'concat-css',, (done) => {
done();
}));
If I delete the build folder to start all over & try adding another task (minfy-js), my third task fails & the build folder also doesn't get created.
//File not found with singular glob: /Users/user/myapp/build/app.js
gulp.task('build-production-static-resource', gulp.series('concat-js', 'concat-css', 'minify-js', (done) => {
done();
}));
The way you're signalling async completion of your tasks is wrong. Read this answer for an overview of the different ways in which you can signal async completion in gulp.
Basically all the streams that you create via gulp.src() are asynchronous. That means you create the stream and your code immediately returns. However the actual processing of the stream starts only after you exit the task function. In order for gulp to know that you're using a stream and that it has to wait for the stream to finish processing, you need to return the stream from your task.
You're doing something else entirely. You're invoking a callback function done which is another way to signal asynchronous task completion to gulp. However that's the completely wrong way in this case, because when you invoke the callback function done the stream you created hasn't even started to process.
That means gulp thinks your concat-js task has finished, although the code inside your task hasn't even really started running. So when the minify-js task runs your ./build/app.js file hasn't been created yet. Boom. Error.
To fix this always return the streams from your tasks:
gulp.task('concat-js', () => {
return gulp.src([
'app1.js',
'app2.js',
])
.pipe(concat("app.js"))
.pipe(gulp.dest('build'))
});
gulp.task('concat-css', () => {
return gulp.src([
'.styles1.css',
'.style2.css'
])
.pipe(concat("app.css"))
.pipe(gulp.dest('build'))
});
gulp.task('minify-js', () => {
return gulp.src('./build/app.js')
.pipe(uglify())
.pipe(gulp.dest('./build/'))
})
gulp.task('build-production-static-resource', gulp.series(
'concat-js', 'concat-css', 'minify-js'
));
Related
I have such a gulp task
gulp.task("js-min", function () {
browserify(config.paths.mainJs)
.transform(reactify)
.bundle()
.pipe(source('tec.min.js'))
.pipe(buffer())
.pipe(sourcemaps.init({loadMaps: true}))
.pipe(uglify())
.pipe(sourcemaps.write(config.paths.dist))
.pipe(gulp.dest(config.paths.dist));
});
that create the minified version of the application. It runs periodically by the gulp-watch task. The problem I see, is that gulp tells me this task finishes in 30ms, but if I check the file being generated, it takes another 30s to see the actual new file being updated.
How shall I change the gulp task js-min so I know exactly when the file was finished updating in file system.
There are two solutions, and without knowing what browserify package you are using.
If it is promise based, then simply edit your code to return that promise:
gulp.task("js-min", function () {
return browserify(config.paths.mainJs)
If it is not promise-based, then it will have some kind of an onend or done method that takes a callback. In that case, it would be like this:
gulp.task("js-min", function (done) {
browserify(config.paths.mainJs)
.transform(reactify)
.bundle()
.pipe(source('tec.min.js'))
.pipe(buffer())
.pipe(sourcemaps.init({loadMaps: true}))
.pipe(uglify())
.pipe(sourcemaps.write(config.paths.dist))
.pipe(gulp.dest(config.paths.dist))
// THIS IS THE LINE TO CHANGE
.onfinish(done);
});
I have a global task that must run in sequence (synchronous) some sub-tasks. I used the task's dependencies mechanism to handle that "synchronous" logic :
// main task
gulp.task('deploy', ['build', 'upload', 'extract', 'migrate'], function() {
// task returns a stream
});
// sub tasks
gulp.task('migrate', ['extract'], function() {
// task returns a stream
});
gulp.task('extract', ['upload'], function() {
// task returns a stream
});
gulp.task('upload', ['build'], function() {
// task returns a stream
});
gulp.task('build', [], function() {
// task returns a stream
});
Dependencies works well and run all in sequence.
But now, how can I call migrate without executing extract>upload>build.
Because, sometimes I'll want to call manually :
gulp build
gulp upload
gulp extract
And I don't want each tasks to re-run all dependencies ...
Thanks
What I've done is define (2) versions of each task I want to isolate, but have them call the same logic so I'm not repeating myself.
For example, in my current project, I have an e2e-tests-development task that depends on build-development, which builds both the server and the client before running e2e tests. Sometimes I just want to re-run the tests and not re-build the entire application.
My e2e-tests-development.js file looks roughly like this:
var gulp = require('gulp');
// Omitted...
gulp.task('e2e-tests-development',
['build-development'],
_task);
gulp.task('e2e-tests-development-isolated',
[], // no dependencies for the isolated version of the task.
_task);
function _task() {
// Omitted...
}
And obviously you'd invoke gulp with e2e-tests-development-isolated instead of e2e-tests-development if you want to just run that task.
(Of course what gulp really needs is a --no-depedencies flag from the command-line...)
In the end, the run-sequence plugin does really well the job :
var runner = require('run-sequence');
// main task
gulp.task('deploy', [], function() {
runner(
'build',
'upload',
'extract',
'migrate'
);
});
// sub tasks
gulp.task('migrate', ['extract'], function() {
// task returns a stream
});
gulp.task('extract', ['upload'], function() {
// task returns a stream
});
gulp.task('upload', ['build'], function() {
// task returns a stream
});
gulp.task('build', ['clean:build'], function() {
// task returns a stream
});
gulp.task('clean:build', [], function() {
// task returns a stream
});
This way I can independently call any sub-task without re-executing previous subtaks...
if you need the 2 version approach like I do, the following solution will do:
gulp.task('deploy:build', ['build'], function () {
gulp.start('deploy');
}
Now I can call deploy without having a dependency on build.
I have two sets of files, let's call them base and mods. The mods files override the base files, so when I run the gulp task related to base, I need to run the mods task directly after. My setup is something like this:
gulp.task('base',function(){
return gulp.src('base-glob')
.pipe(...)
.pipe(gulp.dest('out-glob'))
});
gulp.task('mods',function(){
return gulp.src('mods-glob')
.pipe(...)
.pipe(gulp.dest('out-glob'))
});
So I want to run the mods task at the completion of the base task. Note that this is not the same as defining base as a dependency of mods, because if I'm only changing mods files, I only need to run the mods task. I'd prefer not to use a plugin.
I've been reading the docs about callback functions and other suggestions of synchronous tasks, but can't seem to get my head around it.
I know you don't want to use a plugin, but gulp doesn't have a way to run a sequence of tasks in order without a plugin. Gulp 4 will, but in the meantime the stopgap solution is the run-sequence plugin.
gulp.task('all', function() {
runSequence('base', 'mods');
});
This ensures that the tasks run in order as opposed to unordered dependencies.
Now setup a watch:
gulp.task('watch', function() {
gulp.watch('base-glob', ['all']);
gulp.watch('mods-glob', ['mods']);
});
Whenever base-glob changes, gulp will run all task, which will run the sequence base then mods.
Whenever mods-glob changes, gulp will run only mods task.
That sound about right?
runSequence has some weird bugs, it kept complaining that my tasks are not defined.
If you look into the Orchestrator source, particularly the .start() implementation you will see that if the last parameter is a function it will treat it as a callback.
I wrote this snippet for my own tasks:
gulp.task( 'task1', () => console.log(a) )
gulp.task( 'task2', () => console.log(a) )
gulp.task( 'task3', () => console.log(a) )
gulp.task( 'task4', () => console.log(a) )
gulp.task( 'task5', () => console.log(a) )
function runSequential( tasks ) {
if( !tasks || tasks.length <= 0 ) return;
const task = tasks[0];
gulp.start( task, () => {
console.log( `${task} finished` );
runSequential( tasks.slice(1) );
} );
}
gulp.task( "run-all", () => runSequential([ "task1", "task2", "task3", "task4", "task5" ));
Please find the content of the gulpfile.js as below.
The task uglify depends on the task jshint. Currently when I run gulp, both the tasks get executed, irrespective of the outcome of the jshint task. I don't want the uglify task to get executed when there are 'jshint' error(s).
In other words, when ever there are dependent tasks, I don't want the subsequent tasks to get executed, if there are error detected by the preceding task.
Is it possible in gulp?
var gulp = require('gulp');
var jshint = require('gulp-jshint');
var uglify = require('gulp-uglify');
gulp.task('jshint', function () {
return gulp.src(['assets/js/**/*.js'])
.pipe(jshint('.jshintrc'))
.pipe(jshint.reporter('jshint-stylish'));
});
gulp.task('uglify', ['jshint'], function() {
return gulp.src('assets/js/**/*.js')
.pipe(uglify())
.pipe(gulp.dest('assets-min/js/'));
});
gulp.task('default', ['jshint', 'uglify']);
Please refer the below console output - not desired. Though there had been jshint error, the uglify task ran successfully.
I have also created a GitHub repository with the boilerplate code for the above mentioned.
Please find the same at #sarbbottam/gulp-workflow.
Console out of the undesired workflow
Console out of the expected workflow
For JSHint, there is a built-in reporter for this purpose, fail. If an error occurs, it will stop your gulp process.
You just have to redefine your task like :
gulp.task('jshint', function () {
return gulp.src(['assets/js/**/*.js'])
.pipe(jshint('.jshintrc'))
.pipe(jshint.reporter('jshint-stylish'))
.pipe(jshint.reporter('fail'))
})
With other tasks, you can add an error callback on it and exit the process to prevent subsequent tasks to run.
Here is an example with ngmin (cause uglify is hard to break, but it will be the same) :
function handleError (err) {
console.log(err.toString())
process.exit(-1)
}
gulp.task('min', function () {
return gulp.src(['assets/js/**/*.js'])
.pipe(ngmin())
.on('error', handleError)
})
To complement Aperçu's answer, if you don't want gulp to just exit (because you have watcher running) then you can do the following:
gulp.task('min', function(done) {
return gulp.src(['assets/js/**/*.js'])
.pipe(ngmin())
.on('error', done);
});
This will prevent the next task that depends on this one to run but your watchers will still be running.
I have a simple build script that supposedly should pack all my js modules into a single file using browserify. I have the following code ( inspired from http://www.forbeslindesay.co.uk/post/46324645400/standalone-browserify-builds)
function _browserify(srcPath, distPath) {
var browserify = require('browserify');
var b = new browserify();
b.add(srcPath);
b.bundle().pipe(_fs.createWriteStream(distPath));
console.log(' '+ distPath +' built.');
}
But when I run it, I get a completely empty file. Any idea why?
okay, definitely spent waaaay too much of my evening on this, but this turns out to be an async issue. you're most likely getting an error in there somewhere, but grunt is killing off the process before the error callback has a chance to be called. grunt provides a nifty async method on each task's context that you have to use to let grunt know that this is an async task (and therefore needs to wait for everything to be finito). something like...
grunt.registerTask('build', function () {
var done = this.async();
browserify({ debug: true })
.add('./src/main.js')
.bundle()
.on('error', function (err) {
console.log(err);
})
.pipe(fs.createWriteStream('./target/bundle.js')
.on('end', done);
});