Build Tools Notes

I’ve been working on our build tools at work. Our tools were somewhat outdated, and we were wanting to move away from Grunt. I ultimately decided to go with npm scripts (although the speed of Gulp was tempting). Now that I’m wrapping up, I wanted to write down some notes for things that took a bit of research to figure out.

If you are looking for a complete walkthrough on setting up npm scripts as build tools, here are some articles that helped me:

Reusing an npm script with additional options

You can reduce duplication by reusing scripts and adding -- and then additional options (e.g -- --flag). In the example below, I have a script to build my CSS files with Sass. Then I have a script that watches my Sass files for changes by running the same build script with the --watch option.

"build:css": "node-sass --output-style expanded --precision 6 src/css -o build/css"
"watch:css": "npm run build:css -- --watch"

Using config variables in package.json

If you are building scrips for use on a single platform, then using configuration variables in the package.json file is easy. It gets a bit more complicated when trying to make scripts that work for both Mac/Unix and Windows, because Windows needs a different format for the variables ($npm_package_name for Mac/Unix and %npm_package_name% for Windows).

The best way I found to get around this obstacle is to use the cross-env package. I use the cross-env-shell feature to run the scripts using config variables. You can access any values in the package.json file by adding $npm_package_ to the name (e.g. $npm_package_name).

    "name": "my-package",
    "config": {
        "src": {
            "path": "src",
            "cssPath": "src/css"
        "build": {
            "path": "build",
      "cssPath": "build/css"
        "scripts": {
            "build": ""cross-env-shell 'sass -s expanded --no-source-map $npm_package_config_src_cssPath:$npm_package_config_build_cssPath'""

Using cross-env-shell with copyfiles

I used the copyfiles package to copy static assets from the source directory to the build directory. I had trouble getting this to work with cross-env-shell at first when using something like this:

"copy": "cross-env-shell \"copyfiles -u 1 -e \"$npm_package_config_src_path/**/*.{scss,js}\" \"$npm_package_config_src_path/**/*\" $npm_package_config_build_path\""

At some point, I realized that I could use cross-env-shell with single quotes instead of using escaped double quotes (\") as they show in the cross-env documentation. Switching to single quotes made everything work again:

"copy": "cross-env-shell 'copyfiles -u 1 -e \"$npm_package_config_src_path/**/*.{scss,js}\" \"$npm_package_config_src_path/**/*\" $npm_package_config_build_path'"

Using package.json variables in a webpack config

The package.json values and variables can be accessed inside a webpack config. Just import the file at the top of the config.

const PACKAGE = require('./package.json')

module.exports = {
    entry: `./${PACKAGE.config.src.jsPath}/${}/${}.js`

npm rum

I made one happy little discovery from a typo: npm rum works just the same as npm run. 🍹