Run package.json scripts upon any file changes in a folder

By

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.

Tagged: Node.js · All topics
~~~

Related posts about node: