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
listscript is run fromwpdtrt-dbth/package.json - It calls a second npm
listscript inwpdtrt-dbth/node_modules/wpdtrt-npm-scripts/package.json - This runs the shell
lscommand, printing out the contents of thewpdtrt-dbthdirectory.
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
prefixis 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