My Gulp build script does various things including linting code and packaging releases.
I'd like to extend this script, so that it can be reused by all of my different repos. This necessitates adding unit tests, so that I can be sure that the expected environment and config result in the right files being generated into the correct locations.
This testing is proving very difficult, as, when running shell commands from Node using execa
, both Gulp and Mocha are adding layers of abstraction. These make it hard to see when tests are failing and why.
The solution seems to be to remove the abstraction by using raw shell commands in my npm scripts. So now I'm migrating my build script from Gulp to NPM.
This simple example prints the contents of a directory.
- When a first npm
list
script is run fromwpdtrt-dbth/package.json
- It calls a second npm
list
script inwpdtrt-dbth/node_modules/wpdtrt-npm-scripts/package.json
- This runs the shell
ls
command, printing out the contents of thewpdtrt-dbth
directory.
The prefix
flag allows scripts in dependency B to be called by dependency A, by replacing the implicit script path (CWD) with another path.
This is the location where global items are installed, which by default is the install location of npm itself. If
prefix
is set on the command line, then non-global commands are forced to run in the given folder. The Ultimate Guide to Configuring NPM
It's a similar idea to running a binary at ./node_modules/.bin/name
, where ./node_modules/.bin/
is the prefix.
// ./test/fixtures/dotherightthing/wpdtrt-dbth/package.json
{
"name" : "wpdtrt-dbth",
"config": {
"wpdtrt_npm_scripts": "./node_modules/wpdtrt-npm-scripts"
},
"scripts" {
"list": "npm run list --prefix $npm_package_config_wpdtrt_npm_scripts"
}
}
The second script traverses back to the wpdtrt-dbth
directory, and runs the ls
command, printing the contents of the wpdtrt-dbth
directory to the screen.
Here the config
is redundant, as $INIT_CWD
stores the path to the directory where the script was originally run.
// ./test/fixtures/dotherightthing/wpdtrt-dbth/node_modules/wpdtrt-npm-scripts/package.json
{
"name": "wpdtrt-npm-scripts",
"scripts": {
"list": "cd $INIT_CWD && ls"
}
}
This approach allows the mechanics of the various build tasks to be updated in wpdtrt-npm-scripts
, independently of wpdtrt-dbth
, wpdtrt
, wpdtrt-gallery
and so on.
During the development of wpdtrt-npm-scripts
, it might not be loaded as an NPM dependency yet.
If this is the case, running npm run ls
in the wpdtrt-dbth
directory will generate an error:
npm ERR! enoent ENOENT: no such file or directory, open '/Website/test/fixtures/dotherightthing/wpdtrt-dbth/node_modules/wpdtrt-npm-scripts/package.json'
To correct this, we need to change the path to wpdtrt-npm-scripts
, but only for the test.
Luckily the path is controlled by the config
object in wpdtrt-dbth/package.json
, so we can override it on the command line:
// old relative path points to ./test/fixtures/dotherightthing/wpdtrt-dbth/node_modules/wpdtrt-npm-scripts/package.json
// new relative path points to ./package.json
npm config set wpdtrt-dbth:wpdtrt_npm_scripts ../../../../
That's it.
npm run list
now runs the ls
command in the wpdtrt-dbth
directory.
- Run npm install in a different directory
- npm script command to run a script command from another package.json
- npm scripting: configs and arguments... and some more tricks
If the $CI
variable exists (CI=true
), CI
is output, otherwise WP
is used instead.
The output is then piped (|
) to another function which converts it to lowercase.
Finally, the output is used to populate a new file.
{
"scripts": {
"compile:scss_import": "cd $INIT_CWD && echo '@import \"wpdtrt/dependencies-'${CI:-WP}'\";' | tr -s '[:upper:]' '[:lower:]' > scss/_wpdtrt-import.scss"
}
}
// scss/_wpdtrt-import.scss
@import "wpdtrt/dependencies-WP";
Note: It's possibly to permanently bork Node by setting a bad variable name. In this case you need to edit the .npmrc
file to remove the bad entry:
nano ~/.npmrc
See: Where is NPM config file?
Or, delete an environmental variable like so (note: no leading $
):
unset varname
- How to check if an environment variable exists and get its value?
- how to convert value in a variable from upper case to lower case