Is it possible to run the grunt command after a yeoman generator install? - node.js

Basically I'd like to run grunt after my generator finishes installing dependencies, I found that you can add a callback function to the installDependencies method to run after everything has been installed like this:
this.on('end', function () {
this.installDependencies({
skipInstall: options['skip-install'],
callback: function () {
console.log('All done!');
}
});
});
However I'm not sure how to run the grunt task (as in going to the terminal and running "grunt")

After this.on('end') add this lines
// Now you can bind to the dependencies installed event
this.on('dependenciesInstalled', function() {
this.spawnCommand('grunt', ['build']);
});
check this topic for more details.
But if you're using the latest update of yeomen, you'll need to make it like this
this.on('end', function () {
if (!this.options['skip-install']) {
this.npmInstall();
this.spawnCommand('grunt', ['prepare']); // change 'prepare' with your task.
}
});

Related

Running gulp tasks in sequence throws `Unhandled stream error in pipe`

I have a gulp task as following :
gulp.task('build-files, function(cb) {
runSequence('run-build-cmd',
'delete-dest', 'copy-files',
cb);
});
This task is running whenever something changed in a source folder as following :
gulp.watch(pathToSrcFolder, ['build-files']);
So this task runs 3 other gulp tasks in the specified order, the first one it runs a build command, the second one will delete a folder as following :
gulp.task('delete-dest', (cb) => {
del([pathToDestFolder], {force: true});
cb();
});
and the third one will copy files from a source into two destinations :
gulp.task('copy-files', () => {
return gulp.src(pathToSrcFolder)
.pipe(gulp.dest(pathToDestFolder))
.pipe(gulp.dest(anotherPath));
});
Please notice that the pathToDestFolder is the same folder in both delete-source and copy-files commands.
The problem I had running this sequence, is this error:
internal/streams/legacy.js:59
throw er; // Unhandled stream error in pipe.
^
Error: ENOENT: no such file or directory, chmod 'pathToDestFolder\path\to\some\file\file.ext'
I don't know why I'm getting this error.
And when I run the gulp delete-dest in cmd prompt (which will clear the pathToDestFolder) and then gulp copy-files (which will copy the source folder into two folders pathToDestFolder and anotherPath) it works as expected .
So I guess runSequence didn't work as expected ? if so, how can I solve this ?
Edit:
I tried to use rimraf instead of del, and all seems to work just fine, I know that rimraf is depricated, and it's better to use del instead, but why del in this case results in an exception ?
Edit 2:
Instead of using rimraf as a solution, I tried this solution:
gulp.task('delete-dest', (cb) => {
del([pathToDestFolder], {force: true})
.then(paths => {cb();});
});
And it worked like magic.
Why this worked instead ? I don't know !
If someone can clarify things I would be greatful.
If you look here, you'll find that del returns a promise. It's an async method.
In your code, you call the cb() right after calling del(...), but before del actually finishes deleting the directory.
That's why you have to execute the callback after chaining with then:
gulp.task('delete-dest', (cb) => {
del([pathToDestFolder], {force: true})
.then(paths => {cb();});
});
And then your operations will run in the correct order.
The error you were getting before is the result of things being run in a weird order, leading to weird behavior. Gulp is trying to copy to a directory while the file system is deleting it, and that conflict leads to a file system error.
As an experiment, you can try running the synchronous version of del like so:
gulp.task('delete-dest', (cb) => {
del.sync([pathToDestFolder], {force: true});
cb();
});
See if that works (though you should prefer the async version).
As a side note, unless this is a feature of Gulp 4 though probably not, rather than calling a callback in your task, you can just return a promise like so:
gulp.task('delete-dest', () => {
return del([pathToDestFolder], {force: true});
});
That will tell Gulp that your task is finished, and it can move on to the next.

Restarting gulp after changes to gulpfile.js

I am attempting to re-run my gulp build when gulpfile.js changes, but I am having issues with the method all of my research has lead me to.
I have one watcher for all my less and javascript files and a configuration object that has the list of files to watch, how they are output, etc. This is a stripped-down example of what it looks like:
var $ = require('gulp-load-plugins')();
var config = {
root: rootPath,
output: {
app: 'app',
vendor: 'vendor'
}, // ...
};
gulp.task('default', ['build', 'watch']);
gulp.task('build', ['clean', 'less:app', 'less:theme', 'css:vendor', 'js:app', 'js:vendor', 'rev', 'css:copyfonts']);
gulp.task('watch', function () {
var allFiles = config.styles.appSrc
.concat(config.styles.vendorSrc)
.concat(config.scripts.appSrc)
.concat(config.scripts.vendorSrc);
$.watch(allFiles, function () {
gulp.start('default');
});
});
gulp.task('watch:gulp', function () {
var p;
gulp.watch('gulpfile.js', spawnUpdatedGulp);
spawnUpdatedGulp();
function spawnUpdatedGulp() {
if (p) {
p.kill();
}
p = spawn('gulp', ['default', '--color'], { stdio: 'inherit' });
}
});
// .. other build tasks ..
The above code shows how I tried the accepted answer to this:
How can Gulp be restarted upon each Gulpfile change?
However, it has a major issue. When I run watch:gulp, it runs the build just fine, and everything is great. The config.output.app variable is how the app specific css and js files are named, so my test case has been:
run gulp:watch, check that the css output is named according to config.output.app
change config.output.app, and perform step #1 again
save any random javascript file that it is watching, and see if it builds correctly
Step 3 is riddled with permission errors because of multiple watchers on the files, and this only gets worse the more I repeat steps 1 and 2. Visual Studio will even freeze.
I have not found a way to clean up the old watchers. I tried to manually kill them like this:
var appFileWatcher;
gulp.task('watch', function () {
var allFiles = config.styles.appSrc
.concat(config.styles.vendorSrc)
.concat(config.scripts.appSrc)
.concat(config.scripts.vendorSrc);
appFileWatcher = $.watch(allFiles, function () {
gulp.start('default');
});
});
gulp.task('watch:gulp', function () {
var p;
var gulpWatcher = $.watch('gulpfile.js', spawnUpdatedGulp);
spawnUpdatedGulp();
function spawnUpdatedGulp() {
if (p) {
p.kill();
}
if (appFileWatcher) {
appFileWatcher.unwatch();
}
gulpWatcher.unwatch();
p = spawn('gulp', ['default', '--color'], { stdio: 'inherit' });
}
});
This also does not work. I still get multiple watchers trying to perform the build when I perform my same test case.
How do I kill those watchers that stay around after the new gulp process is spawned?

How can I make gulp-watch generate CSS file when SASS changes?

Here is my code:
gulp.task('sass', function () {
gulp.src('./public/stylesheets/*.scss')
.pipe(sass())
.pipe(gulp.dest('./public/stylesheets/'));
});
gulp.task('watch-saas', function () {
watch('./public/stylesheets/*.scss', function () {
gulp.start('sass');
});
});
Output:
[19:15:46] Using gulpfile ~/WebstormProjects/mySite/gulpFile.js
[19:15:46] Starting 'watch-saas'...
[19:15:46] Finished 'watch-saas' after 38 ms
Im afraid no CSS. Any ideas how to make this work?
I think my code looks very much like the example code here. And the 'sass' task runs fine on its own.
I'm not that experienced in Gulp, but I usually use:
gulp.task('watch-saas', function () {
return gulp.watch(['./public/stylesheets/*.scss'], ['sass']);
});
I assume that you have to return the result in your task, because it's an asynchronous task.
We should first pipe it and ask gulp to watch it in changes in our scss or file we alerted
var gulp = require('gulp')
var watch = require('gulp-watch');
gulp.task('styles', function(){
return gulp.src(''./public/stylesheets/.scss'').pipe(gulp.dest('./sass'));
});
watch('./public/stylesheets/.scss', function(){
gulp.start('styles');
});
styles is the task name which I assigned here

Is there a way to know that nodeunit has finished all tests?

I need to run some code after nodeunit successfully passed all tests.
I'm testing some Firebase wrappers and Firebase reference blocks exiting nodeunit after all test are run.
I am looking for some hook or callback to run after all unit tests are passed. So I can terminate Firebase process in order nodeunit to be able to exit.
Didn't found a right way to do it.
There is my temporary solution:
//Put a *LAST* test to clear all if needed:
exports.last_test = function(test){
//do_clear_all_things_if_needed();
setTimeout(process.exit, 500); // exit in 500 milli-seconds
test.done();
}
In my case, this is used to make sure DB connection or some network connect get killed any way. The reason it works is because nodeunit run tests in series.
It's not the best, even not the good way, just to let the test exit.
For nodeunit 0.9.0
For a recent project, we counted the tests by iterating exports, then called tearDown to count the completions. After the last test exits, we called process.exit().
See the spec for full details. Note that this went at the end of the file (after all the tests were added onto exports)
(function(exports) {
// firebase is holding open a socket connection
// this just ends the process to terminate it
var total = 0, expectCount = countTests(exports);
exports.tearDown = function(done) {
if( ++total === expectCount ) {
setTimeout(function() {
process.exit();
}, 500);
}
done();
};
function countTests(exports) {
var count = 0;
for(var key in exports) {
if( key.match(/^test/) ) {
count++;
}
}
return count;
}
})(exports);
As per nodeunit docs I can't seem to find a way to provide a callback after all tests have ran.
I suggest that you use Grunt so you can create a test workflow with tasks, for example:
Install the command line tool: npm install -g grunt-cli
Install grunt to your project npm install grunt --save-dev
Install the nodeunit grunt plugin: npm install grunt-contrib-nodeunit --save-dev
Create a Gruntfile.js like the following:
module.exports = function(grunt) {
grunt.initConfig({
nodeunit : {
all : ['tests/*.js'] //point to where your tests are
}
});
grunt.loadNpmTasks('grunt-contrib-nodeunit');
grunt.registerTask('test', [
'nodeunit'
]);
};
Create your custom task that will be run after the tests by changing your grunt file to the following:
module.exports = function(grunt) {
grunt.initConfig({
nodeunit : {
all : ['tests/*.js'] //point to where your tests are
}
});
grunt.loadNpmTasks('grunt-contrib-nodeunit');
//this is just an example you can do whatever you want
grunt.registerTask('generate-build-json', 'Generates a build.json file containing date and time info of the build', function() {
fs.writeFileSync('build.json', JSON.stringify({
platform: os.platform(),
arch: os.arch(),
timestamp: new Date().toISOString()
}, null, 4));
grunt.log.writeln('File build.json created.');
});
grunt.registerTask('test', [
'nodeunit',
'generate-build-json'
]);
};
Run your test tasks with grunt test
I came across another solution how to deal with this solution. I have to say the all answers here are correct. However when inspecting grunt I found out that Grunt is running nodeunit tests via reporter and the reporter offers a callback option when all tests are finished. It could be done something like this:
in folder
test_scripts/
some_test.js
test.js can contain something like this:
//loads default reporter, but any other can be used
var reporter = require('nodeunit').reporters.default;
// safer exit, but process.exit(0) will do the same in most cases
var exit = require('exit');
reporter.run(['test/basic.js'], null, function(){
console.log(' now the tests are finished');
exit(0);
});
the script can be added to let's say package.json in script object
"scripts": {
"nodeunit": "node scripts/some_test.js",
},
now it can be done as
npm run nodeunit
the tests in some_tests.js can be chained or it can be run one by one using npm

Using grunt to run a node server and do cleanup after

So basically this is what I want to do. Have a grunt script that compiles my coffee files to JS. Then run the node server and then, either after the server closes or while it's still running, delete the JS files that were the result of the compilation and only keep the .coffee ones.
I'm having a couple of issues getting it to work. Most importantly, the way I'm currently doing it is this:
grunt.loadNpmTasks("grunt-contrib-coffee");
grunt.registerTask("node", "Starting node server", function () {
var done = this.async();
console.log("test");
var sp = grunt.util.spawn({
cmd: "node",
args: ["index"]
}, function (err, res, code) {
console.log(err, res, code);
done();
});
});
grunt.registerTask("default", ["coffee", "node"]);
The problem here is that the node serer isn't run in the same process as grunt. This matters because I can't just CTRL-C once to terminate JUST the node server.
Ideally, I'd like to have it run in the same process and have the grunt script pause while it's waiting for me to CTRL-C the server. Then, after it's finished, I want grunt to remove the said files.
How can I achieve this?
Edit: Note that the snippet doesn't have the actual removal implemented since I can't get this to work.
If you keep the variable sp in a more global scope, you can define a task node:kill that simply checks whether sp === null (or similar), and if not, does sp.kill(). Then you can simply run the node:kill task after your testing task. You could additionally invoke a separate task that just deletes the generated JS files.
For something similar I used grunt-shell-spawn in conjunction with a shutdown listener.
In your grunt initConfig:
shell: {
runSuperCoolJavaServer:{
command:'java -jar mysupercoolserver.jar',
options: {
async:true //spawn it instead!
}
}
},
Then outside of initConfig, you can set up a listener for when the user ctrl+c's out of your grunt task:
grunt.registerTask("superCoolServerShutdownListener",function(step){
var name = this.name;
if (step === 'exit') process.exit();
else {
process.on("SIGINT",function(){
grunt.log.writeln("").writeln("Shutting down super cool server...");
grunt.task.run(["shell:runSuperCoolJavaServer:kill"]); //the key!
grunt.task.current.async()();
});
}
});
Finally, register the tasks
grunt.registerTask('serverWithKill', [
'runSuperCoolJavaServer',
'superCoolServerShutdownListener']
);

Resources