13

I am trying to run my Node application as a Grunt task. I need to spawn this as a child process, however, to allow me to run the watch task in parallel.

This works:

grunt.registerTask('start', function () {
  grunt.util.spawn(
    { cmd: 'node'
    , args: ['app.js']
    })

  grunt.task.run('watch:app')
})

However, when changes are detected by the watch task, this will trigger the start task again. Before I spawn another child process of my Node app, I need to kill the previous one.

I can't figure out how to kill the process, however. Something like this does not work:

var child

grunt.registerTask('start', function () {
  if (child) child.kill()
  child = grunt.util.spawn(
    { cmd: 'node'
    , args: ['app.js']
    })

  grunt.task.run('watch:app')
})

It appears that:

  1. Even though I store the spawned process in a variable outside of the function context, it does not persist, so the next time the start task is run, child is undefined.
  2. child has no kill function…

2 Answers2

5

Take a look at grunt-nodemon which handles a lot of the headaches related to spawning a child process.

gleitz
  • 595
  • 4
  • 12
4

This is because grunt-contrib-watch currently spawns all task runs as child processes. So the variable child is not within the same process context. Fairly soon, grunt-contrib-watch@0.3.0 will be released with a nospawn option. This will let you configure the watch to spawn task runs within the same context and would make your above example work.

Take a look at this issue for a little more information:

https://github.com/gruntjs/grunt-contrib-watch/issues/45

Kyle Robinson Young
  • 13,732
  • 1
  • 47
  • 38
  • I've just replaced my `grunt-contrib-watch` module with the [nospawn](https://github.com/gruntjs/grunt-contrib-watch/tree/nospawn) branch and set the `nospawn` option to true: https://gist.github.com/OliverJAsh/5021187. `child` is still not defined on the second function call. Also, do you know how I can kill the child process? –  Feb 23 '13 at 20:22
  • The Gruntfile isnt a json file, only a js file. You also dont need to call the watch task with grunt.task.run(). Here is an example using the watch to share context: https://github.com/gruntjs/grunt-contrib-watch/blob/nospawn/test/fixtures/nospawn/Gruntfile.js#L35 – Kyle Robinson Young Feb 23 '13 at 23:14
  • 1
    To kill a child process do: `child.kill('SIGINT');` – Kyle Robinson Young Feb 23 '13 at 23:15
  • It is JS, I just extracted the bit that was relevant, sorry for the confusion. I can't work out why `child` is undefined still, even though I'm sure `nospawn` is set to true and I have the right module installed. –  Feb 23 '13 at 23:19
  • Got it to work! The code demonstrated was correct, I just had something going on in my `package.json`. Thank you. –  Feb 23 '13 at 23:23
  • Although it works, I am getting this error: https://gist.github.com/OliverJAsh/5021819 (running Grunt with the `--stack` flag). –  Feb 23 '13 at 23:24
  • I'm sorry, it doesn't work. That error causes Grunt to fail. It occurs when `watch` triggers the `start` task (second time). –  Feb 23 '13 at 23:27
  • Oh ha I was confused by your config. It appears that `grunt.util.spawn` requires the 2nd arg. So do `grunt.util.spawn({}, function() {});` The function is a callback called when the child process has finished. – Kyle Robinson Young Feb 23 '13 at 23:31
  • Thanks a lot for your help Kyle. That fixed it! :) I can't believe my chances that the `nospawn` pull request happened just in time for this. –  Feb 23 '13 at 23:32
  • Cool. If you run into any issues feel free to open an issue on github. I'll publish the version with nospawn soon as v0.3.0. Thanks! – Kyle Robinson Young Feb 23 '13 at 23:34
  • Hey I'm looking for a similar solution, would you mind posting your Gruntfile in a gist? Thanks. – Leonidas Mar 06 '13 at 03:23
  • Here is an example Gruntfile using nospawn: https://github.com/gruntjs/grunt-contrib-watch/blob/master/test/fixtures/nospawn/Gruntfile.js – Kyle Robinson Young Mar 06 '13 at 18:58