Trouble getting Grunt to run node.js script - node.js

I am a grunt and node noob but I managed to write a node script that does what I want it to and works from the command line. I don't want to publish the script as a node module but I would like to run it from my grunt file.
What changes (if any) do I need to make to the script for this to work?
The more I read about configuring grunt files and custom tasks the more confused I get. I currently have something that looks like this:
module.exports = function(grunt) {
grunt.initConfig({
'mytaskname': 'what goes here?'
});
grunt.loadNpmTasks('./node_modules/script_name');
grunt.registerTask('run-from-command-line', 'description', function() {
grunt.log.writeln('Not running...');
});
}
Any help would be greatly appreciated.

You could use the grunt-execute plugin for doing this which executes files in a node.js child process.
Example:
If your node script is in "node-scripts/script.js", Gruntfile.js would look something like this:
module.exports = function(grunt) {
grunt.initConfig({
execute: {
target: {
src: ["node-scripts/script.js"]
}
}
});
// Load the plugins
grunt.loadNpmTasks("grunt-execute");
grunt.registerTask("default", ["execute"]);
};

Related

SailsJs add custom task in default.js

I'm trying to add a custom task in a salsjs application.
This is what I've done so far:
Added a new file in the task/config directory named cssminTemplates.js
Modify the default.js file in the task/registerd directory.
My cssminTemplates.js is basically a copy of the cssmin.js standard file:
module.exports = function(grunt) {
grunt.config.set('cssminTemplates', {
dist: {
src: ['asset/templates/above_the_fold.css'],
dest: 'asset/templates/above_the_fold.min.css'
}
});
grunt.loadNpmTasks('grunt-contrib-cssmin');
};
default.js file as been modified as follow:
module.exports = function (grunt) {
grunt.registerTask('default', [
'compileAssets',
'linkAssets',
'cssminTemplates',
'watch']);
};
But when I start the app with sails lift command I got this error:
Warning: Task "cssminTemplates" not found.
I try to change the 'cssminTemplates' with 'cssmin' and I've got no errors.
In Grunt.js (ref), cssminTemplates function is invoked instead of cssmin which is loaded via grunt.loadNpmTasks('grunt-contrib-cssmin');. This is where the function is invoked:
function invokeConfigFn(tasks) {
for (var taskName in tasks) {
if (tasks.hasOwnProperty(taskName)) {
// Invoking the function....
tasks[taskName](grunt);
}
}
}
In other words, you are setting the function (cssminTemplates) and invoking it from Grunt.js but Grunt loaded cssmin instead via loadNpmTasks(). I think that's why setting cssminTemplates does not work.

How can I pass arguments to a Gulp task?

Say I have a task that looks something like this:
settings.localLESS = ["../css/*.less"];
gulp.task('compile-less-files', function(){
gulp.src(settings.localLESS)
.pipe(less())
.pipe(minifyCSS())
.pipe(gulp.dest(someDest));
})
gulp.watch(settings.localLESS, ['compile-less-files']).on('change', function(event) {
...
});
But I don't want to compile them all. I only want to compile the file that I pass as an argument to the task. Perhaps something like this?
gulp.task('compile-less-file', function(fileName){
gulp.src(fileName)
.pipe(less())
.pipe(minifyCSS())
.pipe(gulp.dest(someDest));
})
gulp.watch(settings.localLESS, ['compile-less-file']).on('change', function(event) {
...
});
Update: I want to set up watchers for all source project files and to run specific tasks once any of file will be changed.
Try to break down your project into small partial files, then create a new file which will act as a "master" file where you can import other files. This way you can be able to choose which file to compile when you are importing.
You can use yargs - https://www.npmjs.com/package/yargs
npm install --save-dev yargs
OR
You can use node's process.argv
gulp.task('taskname', function() {
console.log(process.argv);
});
Then you can pass arguments to your task like below
gulp taskname --option 123

Include Gruntfile and run a task in an another file

I have an app using Grunt, that I launch in my terminal, and I want to run a task through an another app.
So I'd like to know how can I include my Gruntfile.js to this other app, and run the task.
For now this new app is really basic, juste a simple local web page using NodeJS, with a button that launch the task.
Gruntfile (I want to run the "archive" task)
module.exports = function (grunt) {
require('time-grunt')(grunt);
require('jit-grunt')(grunt, {
ngtemplates: "grunt-angular-templates"
});
var Generator = require("./generator.js")(grunt);
var generator = new Generator();
generator.printLogo();
// Build
grunt.registerTask("build", function (fileType) {
//definition of build task
grunt.task.run(tasks);
});
// Archive Task.
grunt.registerTask("archive", ["build", "compress", "clean:post-rsync"]);
};
Other file : (I tried a require, It seems to work, but I can't run the "archive" task of the Gruntfile.)
var grunt = require('grunt');
var gruntfile = require('./Gruntfile.js')(grunt);
var app = express();
app.get('/', function(req, res){
res.render('test.ejs');
});
app.post('/create', function(req, res){
//run grunt task "archive" here
//gruntfile.grunt.registerTask("archive", ["build"]);
res.redirect('/');
});
app.listen(8080);
Do you have any idea how could I run the task in my gruntfile in this other file ?
(The function printLogo() is working so i'm sure the Gruntfile is include)
Thank you very much (I'm a beginner with Grunt so sorry if I miss something trivial)
You can just run a command from node. This way you don’t have to worry about dependencies and what not. You just spawn grunt, like you normally would, except programatically.
var spawn = require('child_process').spawn;
// This will run the 'archive' task of grunt
spawn('grunt', ['archive'], {
cwd: 'path/to/grunt/project'
});
Grunt is a command line tool, the cleanest approach here would be to refactor your Gruntfile and extract your task's logics into a library.
Then from your Gruntfile's task you can call that library, and from your /create route you can also call your library.
You can use grunt-hub plugin:
grunt.initConfig({
hub: {
all: {
src: ['../*/Gruntfile.js'],
tasks: ['jshint', 'nodeunit'],
},
},
});

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

Nodemon-like task in Grunt : execute node process and watch

I feel like I'm missing something.
Here is what I want to achieve :
Having a grunt task that executes my server.js and runs watch task in parallel. It feels to me that this is precisely one of the tasks grunt was designed for but I can't achieve this configuration.
Among others, I have read this :
Running Node app through Grunt
but I still can't make it.
Here is my Gruntfile.js :
module.exports = function(grunt) {
// Project configuration.
grunt.initConfig({
watch: {
scripts: {
files: ['*.js'],
tasks: ['start'],
options: {
nospawn: true
}
}
}
});
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.registerTask('start', function() {
grunt.util.spawn({
cmd: 'node',
args: ['server.js']
});
grunt.task.run('watch');
});
grunt.registerTask('default', 'start');
};
I have "grunt-contrib-watch": "~0.3.1" which should be higher version than grunt-contrib-watch#0.3.0 as in the previously mentioned post.
If you could help me achieve the proper configuration, I would be extremely grateful. But more in general, I don't understand why there is no official grunt-contrib-nodemon-like package and task since I have the feeling it would be another great reason to use grunt (which I really like as a tool !)
Thanks
Edit: grunt-nodemon
since writing this, a nice person developed that.
I was having a lot of trouble using grunt.util.spawn to fire off new processes. They would run, but they wouldn't give me any output back. Perhaps you can figure out what I could not in these docs. http://gruntjs.com/api/grunt.util#grunt.util.spawn
Two problems I see with what you have:
I think grunt.registerTask() has to take three arguments when you use a callback function to run your task.
I don't think you can just call node server.js over and over again everytime a file changes. It will work on the first time, for it to really work you'd have to manage the server as a child process, killing and restarting it on subsequent file changes.
For the registerTask arguments try this, just to see if you can get something to work in your current implementation.
http://gruntjs.com/api/grunt.task#grunt.task.registertask
It takes (taskName, description, taskFunction) like so:
grunt.registerTask('start', 'My start task description', function() {
grunt.util.spawn({
cmd: 'node',
args: ['server.js']
});
grunt.task.run('watch');
});
That might at least get your watch to run node server.js the first time a file changes.
Here's what I would do instead.
Either just use nodemon $ nodemon server.js as is
or...
Read the source and use grunt-develop
He is managing the server as a child process, might be what you're looking for.
or...
Get grunt-shell
npm install grunt-shell --save-dev
And use it to run nodemon for you:
module.exports = function(grunt) {
// Project configuration.
grunt.initConfig({
serverFile: 'server.js',
shell: {
nodemon: {
command: 'nodemon <%= serverFile %>',
options: {
stdout: true,
stderr: true
}
}
},
watch: { /* nothing to do in watch anymore */ }
});
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-shell');
grunt.registerTask('default', 'shell:nodemon');
};
$ grunt shell:nodemon
I sincerely hope that helps. Good luck!
Hi I also came across this problem and here is my solution (based on nackjicholson's answer). This uses grunt-nodemon in a spawned process. so I can:
Reload nodejs
Watch for changes to e.g. .less files
Get output of both tasks
grunt.loadNpmTasks('grunt-nodemon');
grunt.initConfig({
nodemon: {
dev: {
options: {
file: 'server.js',
nodeArgs: ['--debug'],
env: {
PORT: '8282'
}
}
}
},
});
grunt.registerTask('server', function (target) {
// Running nodejs in a different process and displaying output on the main console
var nodemon = grunt.util.spawn({
cmd: 'grunt',
grunt: true,
args: 'nodemon'
});
nodemon.stdout.pipe(process.stdout);
nodemon.stderr.pipe(process.stderr);
// here you can run other tasks e.g.
// grunt.task.run([ 'watch' ]);
});
Use grunt-concurrent
The issue is that tasks like watch and nodemon will never terminate, so grunt will never reach them. You need to spawn a new process.
You can do this easily using grunt-concurrent:
https://github.com/sindresorhus/grunt-concurrent
For example:
module.exports = function(grunt) {
grunt.initConfig({
...
concurrent: {
dev: {
tasks: ['nodemon', 'watch'],
options: {
logConcurrentOutput: true
}
}
}
});
};
The two will now run happily side by side.

Resources