Correct way to kill npm watching processes (Browserify + Vue.js)

2,214 views
Skip to first unread message

Patrick Davey

unread,
Nov 10, 2016, 11:32:36 AM11/10/16
to phoenix-talk
I'm really enjoying playing with Phoenix, and I'm porting a little personal rails app to phoenix to see how it all fits together. The rails app in question uses vue-js, and I'm using the "singe page component" files (.vue) files. As far as I could tell, that precludes using brunch as there was no preprocessor to turn the .vue files into .js ones.

Anyway, I switched out brunch for browserify partly using this quite good article here: http://martinholman.co.nz/blog/2015/09/27/elixir-phoenix-browserify/

The issue I was having was that when I killed the `mix phoenix.server` task, the node processes were not being killed in turn. I went onto the slack channel and was given a helpful pointer from @micmus that "elixir expects processes like that to close themselves when the stdin of the process is closed. If the process does not respect this it will misbehave and may live past the erlang system. One way to solve it is to wrap it in a well behaved script or something."

My original command to spin up the wachers was this line in /config/dev.exs:

  watchers: [npm: ["run", "watch"]]

(note, it's different from the standard one which uses node)

Then in my package.json I have the scripts which look like this:

 
"scripts": {
   
"build-assets": "cp -r web/static/assets/* priv/static",
   
"watch-assets": "watch-run -p 'web/static/assets/*' npm run build-assets",
   
"watch-js": "watchify -vd -p browserify-hmr -e web/static/js/app.js -o priv/static/js/app.js",
   
"watch-css": "catw web/static/css/*.css -o priv/static/css/app.css -v",
   
"watch": "npm run watch-assets & npm run watch-js & npm run watch-css"
 
},


The scripts themselves run fine, it's just that the processes weren't getting killed.

My current solution


Now, I have solved this in what is probably a horrible way, I have no idea, but it works (which is nice). I created a script which is called by node. It looks like this:

var exec = require('child_process').exec;
var child1 = exec('npm run watch-assets');
var child2 = exec('npm run watch-js');
var child3 = exec('npm run watch-css');

process
.stdin.on('end', function() {
  process
.kill(child1.pid);
  process
.kill(child2.pid);
  process
.kill(child3.pid);
  process
.exit(0);
});
process
.stdin.resume();

and I call this script from my config/dev.exs . It works fine, builds the assets, watches, and kills the processes on complete.

The actual question ;) :
Is there a better or more blessed way to do this? I'm not that up to speed on the node ecosystem, processes, phoenix, programmi ... ;) I jest, however, I'd love to know what the "right" way to do it is.

Chris McCord

unread,
Nov 10, 2016, 11:52:21 AM11/10/16
to phoeni...@googlegroups.com
Your workaround is the way to go. The node tools should be good cli citizens and watch for `process.stdin.on('end',` themselves, but failing that, your workaround is fine. We sent a PR to brunch to support this, so you could try contributing to those projects to add support.


--
You received this message because you are subscribed to the Google Groups "phoenix-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to phoenix-talk...@googlegroups.com.
To post to this group, send email to phoeni...@googlegroups.com.
Visit this group at https://groups.google.com/group/phoenix-talk.
To view this discussion on the web visit https://groups.google.com/d/msgid/phoenix-talk/21d9f329-1145-4925-9c6c-d4d3503150af%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Patrick Davey

unread,
Nov 10, 2016, 12:40:05 PM11/10/16
to phoenix-talk
Thanks Chris (and thanks for the great work with Phoenix! loving it)

It's quite possible that the existing tools _do_ listen for `process.stdin.on('end',` themselves and I simply wasn't passing stdin to them correctly. I haven't played with pipes and processes much at all, so this is all quite new. Is there an easy way in my `package.json` script handler below to pass around the stdin ? Maybe it all would have worked anyway and I was simply approaching it incorrectly.


"watch": "npm run watch-assets & npm run watch-js & npm run watch-css"


Sorry if I'm not super clear, I really haven't played around with this stuff much, though I'm psyched that I got it mostly correct.

Either way when I'm finished this little project I'm planning on writing it up and enumerating my gotchas, so hopefully that'll help some people too.

Michał Muskała

unread,
Nov 15, 2016, 1:48:46 PM11/15/16
to phoeni...@googlegroups.com
I believe the issue is the use of & operator. In shell it means - move the process to background. So your script:

npm run watch-assets & npm run watch-js & npm run watch-css

Starts 3 processes, where the first two are put in the background. I believe this looses the first two processes. And even if they listen on stdin, because they are detached, they don't read from the pipe that Elixir is connecting with them.

Michał.
> To view this discussion on the web visit https://groups.google.com/d/msgid/phoenix-talk/8a7397d2-19ac-4803-bf47-1e80ed9b6f39%40googlegroups.com.

OvermindDL1

unread,
Nov 18, 2016, 4:13:32 PM11/18/16
to phoenix-talk
Michał is right, if you want to spin-up concurrent processes that get ended properly instead of just detaching them via `&` you should use  https://www.npmjs.com/package/npm-run-all or something else of that form.
Reply all
Reply to author
Forward
0 new messages