A short story on npm scripts & killing processes (how to make your tools work for you!)
spongechameleon
Posted on August 23, 2020
The background
I have a project. It has static files. They are:
A HTML file
A Sass file (.scss)
A Typescript file (.ts)
To get my sass to compile into regular .css, I use the node-sass
npm package.
To get my typescript to compile into regular .js, I use the tsc
compiler.
To get my browser to automatically update whenever one of these files is changed, I use the browser-sync
npm package.
How I start up:
Open a terminal. Go to project directory. Start
vim
.-
Open another terminal. Go to project directory. Run
tsc & node-sass & browser-sync &
- (Full disclosure:
node-sass
andbrowser-sync
are run with options, but that's not important)
- (Full disclosure:
Go back to vim and edit.
How I close down:
Close vim (but how?!). Close terminal.
-
Go to the other terminal. Find and kill my processes, one-by-one:
ps aux | grep node-sass
- Mentally take note of the displayed PID (process ID) from the second column
kill <PID I definitely always remember perfectly>
- Repeat for
tsc
andbrowser-sync
This is clearly a lot of typing and PID-remembering. Nobody likes that. We can do better.
The npm script
My start up command is too much typing. So we’re going to have package.json
do the heavy lifting.
“scripts”: {
“ts”: “tsc”,
“sass”: “node-sass”,
“browser”: “browser-sync”,
“serve”: “npm run ts & npm run sass & npm run browser &”
}
Now, all we have to run is npm run serve
and everything is taken care of for us.
OK, but why go through all the trouble of making scripts for each single command? Why not just do:
“scripts”: {
“serve”: “tsc & node-sass & browser-sync &”
}
The answer to that is all about our friend, &
, the ampersand. Anything with an &
will run continuously and show up in the output of ps aux
. And we intentionally want all of our processes- whatever they really are- to show up as npm
processes!
Hence:
The
“serve”
script that only runsnpm
commandsThe absence of an
&
in the“ts/sass/browser”
scripts
The kill
So here’s why we want all of those tools to show up as npm
commands:
ps aux | grep [n]pm | awk ‘{ print $2 }’
This command:
Outputs all processes
Filters by
[n]pm
(only considers processes with the first letter of “n”)Grabs the second column/word of output, which in this case is the PID
Now all that’s left is to kill all of those PIDs we collected:
kill $(ps aux | grep [n]pm | awk ‘{ print $2 }’)
Booyah. But… hate typing that? Me too. So, we can either just alias this in our .bashrc as ‘npmkill’ or something…
The generalized, easy to type kill
…or take an extra minute to whip together a quick bash script that:
Accepts a grep search term
Lets us see our processes before we kill them
#!/usr/bin/bash
ps aux | grep $1
read -p ‘kill processes? (y/n): ‘ confirm
if [ $confirm == ‘y’ ]
then
kill $(ps aux | grep $1 | awk ‘{ print $2 }’)
fi
The $1
refers to the first argument passed to the script, so if we call our script pidkill.sh
then running pidkill [n]pm
would mean $1
== [n]pm
.
The read -p ‘<prompt>: ‘ confirm
allows us to (a) enter our response on the same line and (b) saves our response to the $confirm
variable.
Then it’s a simple if statement and our shell expansion!
Don’t forget to alias your script in .bashrc if you want to be able to use it anywhere, otherwise you’ll have to be in the directory of the script or type out its path every time.
alias pidkill=’~/pidkill.sh’
does the trick for me.
Thanks for reading and happy coding!
sponge
Posted on August 23, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.