gulp - how to pipe tasks - javascript

I have this task:
var path = require('path');
var gulp = require('gulp');
var conf = require('./conf');
var svgSprite = require("gulp-svg-sprites");
var clean = require('gulp-clean');
gulp.task('sprite-make', function () {
//first task
gulp.src([path.join(conf.paths.src, '/assets/svg/*.svg'), '!' + path.join(conf.paths.src, '/assets/svg/sprite.svg')])
.pipe(svgSprite({
preview: false,
svgPath: path.join(conf.paths.src, '/assets/svg/sprite.svg'),
cssFile: ('_sprite.scss')
}))
.pipe(gulp.dest(path.join(conf.paths.src, '/app/styles')));
//second task
gulp.src(path.join(conf.paths.src, '/app/styles/svg/**/*'))
.pipe(gulp.dest(path.join(conf.paths.src, '/assets/svg')));
//third task
gulp.src(path.join(conf.paths.src, '/app/styles/svg'), {read: false})
.pipe(clean());
});
What I want is to execute this tasks one after another (create the sprite -> copy it to new destination -> delete the src).
Currently the tasks running async, and if I try to do pipe(gulp.src(...) I am getting the following error: Unhandled stream error in pipe

Pretty well defined in the doc : https://github.com/gulpjs/gulp/blob/master/docs/API.md
Note: By default, tasks run with maximum concurrency -- e.g. it
launches all the tasks at once and waits for nothing. If you want to
create a series where tasks run in a particular order, you need to do
two things:
give it a hint to tell it when the task is done, and give it a hint
that a task depends on completion of another. For these examples,
let's presume you have two tasks, "one" and "two" that you
specifically want to run in this order:
In task "one" you add a hint to tell it when the task is done. Either
take in a callback and call it when you're done or return a promise or
stream that the engine should wait to resolve or end respectively.
In task "two" you add a hint telling the engine that it depends on
completion of the first task.
So this example would look like this:
var gulp = require('gulp');
// takes in a callback so the engine knows when it'll be done
gulp.task('one', function(cb) {
// do stuff -- async or otherwise
cb(err); // if err is not null and not undefined, the run will stop, and note that it failed
});
// identifies a dependent task must be complete before this one begins
gulp.task('two', ['one'], function() {
// task 'one' is done now
});
gulp.task('default', ['one', 'two']);

Related

Can I gulp-notify when a watched task completes?

We have a gulpfile with ~12 tasks, 4 of which are activated by a gulp.watch. I would like to use gulp-notify when a task started by gulp.watch completes. I don't want gulp-notify to do anything if a task is run directly. Sample code below:
const
debug = require("gulp-debug"),
gulp = require("gulp"),
notify = require("gulp-notify");
gulp.task("scripts:app", function () {
return gulp.src(...)
.pipe(debug({ title: "tsc" }))
.pipe(...); // <--- if i add notify here,
// I will always get a notification
});
gulp.task("watch", function () {
gulp.watch("ts/**/*.ts", ["scripts:app"]);
});
If I pipe to notify inside the 'scripts:app' task, it will make a notification every time that task runs, regardless of how that task was started. Again, I want to notify when the watched task completes.
I considered adding a task 'scripts:app:notify' that depends on 'scripts:app', but if possible I'd like to avoid creating "unnecessary" tasks.
I also tried the following:
gulp.watch("ts/**/*.ts", ["scripts:app"])
.on("change", function (x) { notify('changed!').write(''); });
But that results in a notification for every file changed. I want a notification when the task completes.
In other words, if I run gulp scripts:app, I should not get a notification. When I run gulp watch and change a watched file, I should get a notification.
How can I do this?
Try adding params to your build script:
function buildApp(notify){
return gulp.src(...)
.pipe(...)
.pipe(function(){
if (notify) {
//drop notification
}
});
});
}
//Register watcher
gulp.watch("ts/**/*.ts", function(){
var notify = true;
buildApp(notify);
});
//Register task so we can still call it manually
gulp.task("scripts:app", buildApp.bind(null, false));
As you can see, buildApp is a simple function. It's callable through a watcher or a "normal" task registration.

Gulp tasks not working in sync

I'm trying to use browserify with babelify in my project. Everything works great except the problem of sync.
// Browserify
//---------------------------------------------------
gulp.task('browserify', function() {
var bundler = browserify('_babel/script.js').transform(babelify);
bundler.bundle()
.pipe(source('_babel/script.js'))
.pipe(gulp.dest('_dev'));
});
// JavaScript moving and merging
//---------------------------------------------------
gulp.task('js-min', ['browserify'], function() {
return gulp.src('_dev/_babel/script.js')
.pipe(concatjs('scripts.js'))
.pipe(gulp.dest('_js'))
.pipe(browserSync.stream());
});
gulp.watch('_babel/**', ['js-min']);
From what I can tell, browserify notifies gulp that it's done (it's done very quic, 10 ms or so) when it's not. And then js-min moves old file. Such observation seems valid because I am always one change behind.
What can I do?
There are three ways to tell Gulp that a task has finished.
You have all sync stuff to execute in the task:
gulp.task('task-a', function(){
// do sync stuff
// you may return here
// but because everything is sync Gulp assumes that everything has ended
});
You get the callback as input
// the passed cb is the next task to execute
gulp.task('task-b', function(cb){
// do async stuff
cb( result );
});
Return a promise/stream (which fits your case):
gulp.task('task-c', function(){
// return either a promise or a stream
return gulp.src( ... );
});
In both cases 2 and 3 Gulp will wait the end of the execution before calling the next function.
You are basically writing a case 3 but Gulp believes it's 1.
To fix this just return the bundler and you should be fine:
// Browserify
//---------------------------------------------------
gulp.task('browserify', function() {
var bundler = browserify('_babel/script.js').transform(babelify);
return bundler.bundle()
.pipe(source('_babel/script.js'))
.pipe(gulp.dest('_dev'));
});
// JavaScript moving and merging
//---------------------------------------------------
gulp.task('js-min', ['browserify'], function() {
return gulp.src('_dev/_babel/script.js')
.pipe(concatjs('scripts.js'))
.pipe(gulp.dest('_js'))
.pipe(browserSync.stream());
});
gulp.watch('_babel/**', ['js-min']);

Making gulp write files synchronously before moving on to the next task

gulpfile.js
gulp.task('browser-bundle', ['react'], function() {
...
});
gulp.task('react', function(){
gulp.src(options.JSX_SOURCE)
.pipe(react())
.pipe(gulp.dest(options.JSX_DEST))
});
As you can see I have the browser-bundle task depending on the react task. I believe this works as expected because in the output I see this:
[gulp] Running 'react'...
[gulp] Finished 'react' in 3.43 ms
[gulp] Running 'browser-bundle'...
However, although the react task is finished, the files its supposed to write to the operating system are not quite there yet. I've notice that if I put a sleep statement in the browser bundle command then it works as expected, however this seems a little hacky to me.
If I want the react task to not be considered finished until the files (from gulp.dest) have been synchronously written to disk how would I do that?
You need a return statement:
gulp.task('react', function(){
return gulp.src(options.JSX_SOURCE)
.pipe(react())
.pipe(gulp.dest(options.JSX_DEST))
});
With this all my write operations are done before the next task processed.
back to 2019: if some one come here with similar problem
In gulp 4.*, at least, gulp wait for promise to resolve but ignore the result.
so... if you use async await pattern and return the result of gulp.src('...') you got a surprise. the task not wait for stream finish before it continue! somthing that can result to serious bug and waist of time. the solution is "promisify" gulp.src
example:
gulp.task( async function notWaitingTask(){
// the return stream are ignored because function return promise not stream
return gulp.src('file.js')
.pipe(gulp.dest('new-location'))
})
gulp.task( async function waitingTask(){
// the return stream are respect
await promisifyStream(
gulp.src('file.js')
.pipe(gulp.dest('new-location'))
)
})
function promisifyStream(stream) {
return new Promise( res => stream.on('end',res));
}
The accepted answer is spot on, but as per https://github.com/gulpjs/gulp/issues/899, in the 3.x branch of gulp, you cannot do this with dependencies without a bit of extra special sauce:
var run = require('run-sequence');
var nodeunit = require('gulp-nodeunit');
var babel = require('gulp-babel');
var gulp = require('gulp');
/// Explicitly run items in order
gulp.task('default', function(callback) {
run('scripts', 'tests', callback);
});
/// Run tests
gulp.task('tests', function() {
return gulp.src('./build/**/*.tests.js').pipe(nodeunit());
});
// Compile ES6 scripts using bable
gulp.task('scripts', function() {
return gulp.src('./src/**/*.js')
.pipe(babel())
.pipe(gulp.dest('./build'));
});
Notice specifically the use of the 'run-sequence' module to force the tasks to run one after another, as well.
(Without run, rm -rf build && gulp will result in OK: 0 assertions (0ms) because the tests task will not find the files created by the scripts task because it starts before the scripts task is completely resolved)
Met same issue here. Let's say there are 2 tasks, First and Second. Second runs after First.
The First task generates some files, which are to be read by the Second task. Using dependency doesn't make sure the Second task can find the files generated.
I have to explicitly using the done callback on the pipeline to let Second only starts after First truly done.
//This approach works!
gulp.task('First', function(done)) {
var subFolders = fs.readdirSync(somefolder)...
var tasksForFolders = subFolders.map(function(folder) {
return gulp.src('folder/**/*').sthtogeneratefiles();
});
tasksForFolders[tasksForFolders.length-1].on('end',done);
return tasksForFolders;
}
gulp.task('Second', ['First'],function() {
return gulp.src('generatedfolders/**/*').doth();
}
Without the done trick, the Second never finds the files generated by First. Below shows what I tried, the Second task can find the files generated by calling gulp First by hand, and then calling gulp Second subsequently.
//This is the WRONG approach, just for demonstration!!
gulp.task('First', function()) {
var subFolders = fs.readdirSync(somefolder)...
var tasksForFolders = subFolders.map(function(folder) {
return gulp.src('folder/**/*').sthtogeneratefiles();
});
return tasksForFolders;
}
gulp.task('Second', function() {
return gulp.src('generatedfolders/**/*').doth();
}

How to print out a text once grunt task completes?

Once a Grunt task completes, I want to print out some information. See the Grunt snippet below.
Is there a way to achieve this? I noticed that grunt.task.run() does not support callbacks. This causes my message to be printed out prior to coverage report output.
grunt.registerTask('coverage', 'Runs all unit tests available via Mocha and generates code coverage report', function() {
grunt.task.run('env:unitTest', 'mochaTest');
grunt.log.writeln('Code coverage report was generated into "build/coverage.html"');
});
I also want to avoid "hacks" such as creating a grunt task only for printing the information out and adding it to the grunt.task.run() chain of tasks.
Create a task that will run when everything is all done and then add it to your task chain:
grunt.registerTask('alldone', function() {
grunt.log.writeln('Code coverage report was generated into "build/coverage.html"');
});
grunt.registerTask('default', ['env:unitTest', 'mochaTest', 'alldone']);
There is a much better way to do it, without creating an extra task, and modifying anything else.
Grunt is a node process, so you can:
use the process stdout to write what you need
subscribe to the process exit event to do it when a task is finishing its execution
This is a simple example which prints out the time when the tasks has finished their execution:
module.exports = function (grunt) {
// Creates a write function bound to process.stdout:
var write = process.stdout.write.bind(process.stdout);
// Subscribes to the process exit event...
process.on("exit", function () {
// ... to write the information in the process stdout
write('\nFinished at ' + new Date().toLocaleTimeString()+ '\n');
});
// From here, your usual gruntfile configuration, without changes
grunt.initConfig({
When you run any task, you'll see a message at the bottom like:
Finished at 18:26:45

Node.js and Jake - How to call system commands synchronously within a task?

A Jake task executes a long-running system command. Another task depends on the first task being completely finished before starting. The 'exec' function of 'child_process' executes system commands asynchronously, making it possible to for the second task to begin before the first task is complete.
What's the cleanest way to write the Jakefile to ensure that the long-running system command in the first task finishes before the second task starts?
I've thought about using polling in a dummy loop at the end of the first task, but this just smells bad. It seems like there must be a better way. I've seen this SO question, but it doesn't quite address my question.
var exec = require('child_process').exec;
desc('first task');
task('first', [], function(params) {
exec('long running system command');
});
desc('second task');
task('second', ['first'], function(params) {
// do something dependent on the completion of 'first' task
});
I found the answer to my own question by re-rereading Matthew Eernisse's post. For those wondering how to do it:
var exec = require('child_process').exec;
desc('first task');
task('first', [], function(params) {
exec('long running system command', function() {
complete();
});
}, true); // this prevents task from exiting until complete() is called
desc('second task');
task('second', ['first'], function(params) {
// do something dependent on the completion of 'first' task
});
Just for future reference, I have a synchronous exec module with no other dependencies.
https://npmjs.org/package/allsync
Example:
var allsync = require("allsync");
allsync.exec( "find /", function(data){
process.stdout.write(data);
});
console.log("Done!");
In the above exampale, Done is only printed after the find process exists. The exec function essentially blocks until complete.

Categories