How to make gulp not finish task before it's done? - node.js

I have this gulp task, and it works fine, but when looking at the log, it always says Starting Task, then immediately Finished Task, then it starts logging everything. How do I make it wait until everything is complete until it says it's finished? I think it's due to the function being async so done() gets called right away, but I'm not sure what to do.
gulp function
gulp.task("img-projects", function(done) {
gulp.src('projects/*/images/**/*.*')
.pipe(imagemin())
.pipe(rename(function (path) {
path.dirname = path.dirname.replace('/images','');
console.log('path');
return path;
}))
.pipe(gulp.dest('public'));
done();
});
output:
[19:11:55] Starting 'js-projects'...
[19:11:55] Finished 'js-projects' after 34 ms
[19:11:55] path
[19:11:55] path
[19:11:55] path

All you need to add is an on('end', ...) listener to wait until the gulp stream is complete before calling done():
gulp.task("img-projects", function(done) {
gulp.src('projects/*/images/**/*.*')
.pipe(imagemin())
.pipe(rename(function (path) {
path.dirname = path.dirname.replace('/images','');
console.log('path');
return path;
}))
.pipe(gulp.dest('public'))
.on('end', done);
});
Sources:
How do you run a gulp "on end" task but only at the end of the current task?
gulp API (docs for src()/dest()/etc): https://github.com/gulpjs/gulp/tree/master/docs/api
node.js streams API which provides on(...): https://nodejs.org/api/stream.html
similar issue: https://github.com/gulpjs/gulp/issues/1181#issuecomment-126694791

Try,
The gulp functions are async
gulp.task("img-projects", function() {
return gulp.src('projects/*/images/**/*.*')
.pipe(imagemin())
.pipe(rename(function (path) {
path.dirname = path.dirname.replace('/images','');
console.log('path');
return path;
}))
.pipe(gulp.dest('public'));
});

Related

node mocha async hooks not working?

Ok so I'm obviously new to mocha. From my understanding after reading the docs and googling this should work but it isn't:
describe("Check before", function(){
var beforeCalled = false;
before(function(){
setTimeout(function() {
beforeCalled = true;
done();
}, 150);
});
it("should run after before called", function(){
expect(beforeCalled).to.equal(true);
})
})
the it part doesn't wait for 'before' to finish and is called. Maybe I read the docs wrong or I'm missing something, not sure.
Any insight would be helpful.
The done callback must be in the function signature for mocha to wait.
before(function(done){
setTimeout(function() {
beforeCalled = true;
done();
}, 150);
});
I've got into the habit of always using done when there are mixed synchronous and async tests. Mocha can finish as if no tests have failed if you forget one async done on an it.

Node.js streams => Delete contents of folder before transpiling to it

I am using Gulp and I would like to delete/"clean" all contents of a directory before writing transpiled source to it.
Is there a way to connect the stream that runs the delete operation to the stream that does the read/transform/write operation?
Right now I have this:
function transpileJSX() {
var d = domain.create();
d.run(function () {
gulp.src('./public/static/app/js/views/**/*.js').pipe(react({harmony: true}))
.pipe(gulp.dest('./public/static/app/js/jsx')).on('end', function () {
d.emit('end');
d.exit();
});
});
return d;
}
function deleteJSX() {
return gulp.src('./public/static/app/js/jsx/**/*.js')
.pipe(clean({force: true}));
}
gulp.task('transpile-jsx', function () {
return transpileJSX().on('error', function (err) {
console.error(err);
});
});
gulp.task('delete-jsx', function (cb) {
return deleteJSX();
});
the problem is that this doesn't seem to work:
deleteJSX().pipe(transpileJSX());
the transpileJSX operation seems to start before the deleteJSX operation begins. And that might be expected when it comes to streams. But I think I want to make sure the whole thing works properly by ensuring the entire delete operation completes first?
For example, if I do this:
gulp.task('some-task', ['delete-jsx','transpile-jsx'], function (done) {
someTask(done);
});
the gulp logs show that the transpile-jsx task starts before the delete-jsx task ends.
If someone has a pattern to use when it comes to cleaning out a folder before transpiling to it, I'd like to copy it thanks!
You're almost there already. You just have to rearrange task dependencies, since gulp runs tasks for maximum concurrency:
gulp.task('transpile-jsx', ['delete-jsx'], function () {
//...
});
gulp.task('some-task', ['transpile-jsx'], function () {
//...
});
This will be easier once Gulp 4 hits. There you will be able to write stuff like:
gulp.task('some-task', gulp.series('delete-jsx', 'transpile-jsx', function () {
//...
}));

How can I kill nodemon process after running mocha tests?

I need to have a gulp task that starts the server, runs mocha tests against it and finally closes it. I have the following code:
var mocha = require('gulp-mocha');
var nodemon = require('nodemon');
gulp.task('my-integration-tests', function () {
return nodemon({ script: './server.js' })
.on('start', function () {
gulp.src(['./mySpecs.spec.js'])
.pipe(mocha());
});
});
The server is successfully started and the tests are run. However after this the process created by nodemon is still alive. Is there a way to instruct nodemon to close upon completion? Also having the application opening and closing in the same process as the mocha tests is not an option with the current configuration.
UPDATE:
Apart from ThomasBromans answer, I came up with this solution which seems to work in my case. Whenever gulp-mocha finishes the tests it will kind of emit an 'end' event. When this happens we only need to emit 'quit' on the child process then kill the main process, like so:
gulp.task('my-integration-tests', function () {
var childProc = nodemon({ script: './server.js' });
childProc.on('quit', function () {
console.log('event emitted, child process is being killed');
})
childProc.on('start', function () {
gulp.src(['./mySpecs.spec.js'])
.pipe(mocha())
.once('end', function () {
console.log('mocha stuff ended. time to kill processes');
childProc.emit('quit');
setTimeout(function () {
console.log('kill main process');
process.exit();
}, 1500);
});
});
});
Unfortunately I still need the timeout between the child process being killed and the killing of the main process, if I remove the timeout it happens that the child process remains hanging. This solution is of course open to improvements.
You can exit the process with process.exit(). Just add another .pipe. Your task will look like this:
gulp.task('my-integration-tests', function () {
return nodemon({ script: './server.js' })
.on('start', function () {
gulp.src(['./mySpecs.spec.js'])
.pipe(mocha())
.pipe(process.exit());
});
});
EDIT running tasks in a sequence (I am not sure this works without any changes):
var gulp = require('gulp'),
mocha = require('gulp-mocha'),
nodemon = require('nodemon'),
runSequence = require('run-sequence');
gulp.task('nodemon', function() {
return nodemon({script: './server.js'});
});
gulp.task('mocha', function() {
return mocha();
});
gulp.task('stop', function() {
process.exit();
});
gulp.task('my-integration-tests', function () {
runSequence('nodemon',
'mocha',
'stop');
});

Yeoman generator: how to run async command after all files copied

I'm writing a yeoman generator.
I need to run some shell script after all files copied.
The generator is being called as a child generator so it should wait till script finished.
The script is some command file being run via spawn:
that.spawnCommand('createdb.cmd');
As the script depends on files created by the generator it cannot run right inside generator's methods as all copy/template action are async and have not executed yet:
MyGenerator.prototype.serverApp = function serverApp() {
if (this.useLocalDb) {
this.copy('App_Data/createdb.cmd', 'App_Data/createdb.cmd');
// here I cannot run spawn with createdb.cmd as it doesn't exist
}
}
So the only place I found where I can run spawn is the 'end' event handler:
var MyGenerator = module.exports = function MyGenerator (args, options, config) {
this.on('end', function () {
if (that.useLocalDb) {
that.spawnCommand('createdb.cmd')
}
}
}
The script runs successfully but the generator finishes earlier than the child process. I need to tell Yeoman to wait for my child process.
Something like this:
this.on('end', function (done) {
this.spawnCommand('createdb.cmd')
.on('close', function () {
done();
});
}.bind(this));
But 'end' handler doesn't have the argument with 'dine' callback.
How to do this?
UPDATE:
thanks to #SimonBoudrias I got it working.
The full working code is below.
BTW: end method is described in the docs
var MyGenerator = module.exports = yeoman.generators.Base.extend({
constructor: function (args, options, config) {
yeoman.generators.Base.apply(this, arguments);
this.appName = this.options.appName;
},
prompting : function () {
// asking user
},
writing : function () {
// copying files
},
end: function () {
var that = this;
if (this.useLocalDb) {
var done = this.async();
process.chdir('App_Data');
this.spawnCommand('createdb.cmd').on('close', function () {
that._sayGoodbay();
done();
});
process.chdir('..');
} else {
this._sayGoodbay();
}
},
_sayGoodbay: funciton () {
// final words to user
}
});
Never trigger any action in the end event. This event is to be used by implementors, not generator themselves.
In your case:
module.exports = generators.Base({
end: function () {
var done = this.async();
this.spawnCommand('createdb.cmd').on('close', done);
}
});

Using a node module within a Grunt Task fails

I'm trying to extract meta data from files read within a Grunt task.
executing: node test.js on this file:
var exif = require('exif2');
exif('fixtures/forest.png', function (err, o) {
console.log(arguments);
});
Produces the expected output
However, executing the grunt process: grunt projectJSON
module.exports = function (grunt) {
var exif = require('exif2');
return grunt.registerMultiTask("projectJSON", "Creates project JSON file.", function () {
exif('fixtures/forest.png', function (err, o) {
console.log(arguments);
});
});
}
** note that I am just testing with the fixtures/forest.png file
Produces no output whatsoever. The callback isn't even fired.
When I console.log exif, I get: [Function]
What am I missing? I think that the doesn't work is because of the grunt task, but I have no idea how to fix it. Wrapping it in a try-catch block produces nothing.
You need to make your projectJSON task asynchronous - Grunt is exiting before your exif callback is being invoked.
Have a look at the Grunt documentation on asynchronous tasks.
This is how you can make your task asynchronous:
module.exports = function (grunt) {
var exif = require('exif2');
grunt.registerMultiTask("projectJSON", "Creates project JSON file.", function () {
// Make task asynchronous.
var done = this.async();
exif('fixtures/forest.png', function (err, o) {
console.log(arguments);
// Invoke the task callback to continue with
// other Grunt tasks.
done();
});
});
}

Resources