Run package.json scripts upon any file changes in a folder
By Flavio Copes
Learn how to re-run a package.json script automatically whenever a file in a folder changes, using the watch npm package to rebuild on every save.
To run a package.json script whenever a file changes in a folder, we can use the watch npm package. It watches a folder tree and runs a command of our choice on every change.
My practical problem: I want to automatically regenerate the CSS, going through a PostCSS pipeline, upon file changes.
The approach I describe will work for any kind of automatic file and folder watching, not just for this specific case.
I have this script in action, which I run using yarn build:css:
"scripts": {
"build:css": "postcss src/tailwind.css -o static/dist/tailwind.css"
}
and I want to re-run it whenever something changes in the layouts folder, which contains all the HTML files that build up my site.
If you’re familiar with Tailwind, it creates a slightly big CSS file with all the things you might need, and you can optimize it by removing any class you don’t use.
Every time I change something in there, I want to regenerate the CSS, and trigger the purge and minification I set up in the PostCSS setup.
How to do this?
Install the watch package:
npm install watch
and add the watch script to your package.json file. You already had build:css from before, we just add a script that watches the layouts folder and runs build:css upon every change:
"scripts": {
"build:css": "postcss src/tailwind.css -o static/dist/tailwind.css",
"watch": "watch 'npm run build:css' ./layouts"
}
Now run npm run watch or yarn watch. Save any file inside layouts, and the CSS is rebuilt.
How the command works
The syntax is watch '<command>' <folder>. The folder is watched recursively, so files in subfolders trigger the command too.
You can also watch more than one folder, by listing them all:
"watch": "watch 'npm run build:css' ./layouts ./content"
Watch out for the quotes
The command must be wrapped in quotes. Since the script already lives inside a JSON string delimited by double quotes, use single quotes around the command.
Without them, the shell splits npm run build:css into separate arguments, and watch treats run and build:css as folders to watch. You get errors about folders that don’t exist, or a watcher that does nothing useful.
Too many rebuilds?
Some editors save a file multiple times in a row, and each save triggers the command. If your build is slow, that piles up.
The --wait flag helps. It disables watching for a number of seconds after each run:
"watch": "watch 'npm run build:css' ./layouts --wait=3"
With this, after a rebuild the watcher waits 3 seconds before it can fire again, so a burst of saves results in one rebuild instead of five.
Related posts about node: