aka npm-package-scripts or
npsfor short
All the benefits of npm scripts without the cost of a bloated package.json and limits of json
Simplify and empower npm scripts with p-s 11:19
Even though npm scripts have a ton of advantages (learn more), it can grow into an
unmaintainable mess in your package.json file. Part of the problem is we're configuring scripts in json
which has fundamental issues (like no comments).
p-s is a package that solves this problem by allowing you to move your scripts to a package-scripts.js file. Because
this file is a JavaScript file, you can do a lot more with your project scripts. Here's an example of a
package-scripts.js file:
module.exports = {
scripts: {
default: 'node index.js',
lint: 'eslint .',
test: {
// learn more about Jest here: https://kcd.im/egghead-jest
default: 'jest',
watch: {
script: 'jest --watch',
description: 'run in the amazingly intelligent Jest watch mode'
}
},
build: {
default: 'webpack',
prod: 'webpack -p',
},
validate: 'nps --parallel lint,test,build',
},
}Or in case you prefer YAML, here's an example of how that would look in a package-scripts.yml file:
scripts:
default: node index.js
lint: eslint .
test:
# learn more about Jest here: https://kcd.im/egghead-jest
default: jest
watch:
script: jest --watch
description: run in the amazingly intelligent Jest watch mode
build:
default: webpack
prod: webpack -p
validate: nps --parallel lint,test,buildTo use p-s, it's recommended that you either install it globally (npm i -g p-s) or add ./node_modules/bin to your
$PATH (be careful that you know what you're doing when doing this).
Then you can run:
p-s --helpWhich will output:
Usage: nps [options]
Options:
-h, --help output usage information
-V, --version output the version number
-s, --silent Silent nps output
-p, --parallel <script-name1,script-name2> Scripts to run in parallel (comma seprated)
-c, --config <filepath> Config file to use (defaults to nearest package-scripts.yml or package-scripts.js)
-l, --log-level <level> The log level to use (error, warn, info [default])
-r, --require <module> Module to preload
Available scripts (camel or kebab case accepted)
lint - eslint .
test - jest
test.watch - run in the amazingly intelligent Jest watch mode - jest --watch
build - webpack
build.prod - webpack -p
validate - nps --parallel lint,test,buildBecause p-s is harder to type, it is recommended that you use the alias nps to interact with p-s, which is much
easier to type and the rest of the documentation will use nps
Now, to run a script, you can run:
nps lint
nps test.watch
# etc.But the fun doesn't end there! You can use a prefix:
nps b # will run the build scriptAnd these prefixes can go as deep as you like!
nps b.p # will run the production build scriptCool stuff right? And there's more on the roadmap.
Also check out the examples. You'll find some good stuff in there (including how to deal with windows and other cross-platform issues).
Note: If you don't like installing things globally and don't want to muck with your $PATH (or don't want to
require that your co-workers or project contributors to do so), then you can add a single script to your package.json.
We recommend that you use the start script because it requires less typing:
package.json
{
"scripts": {
"start": "nps"
}
}You don't have to use the start script if you don't want. Note that if you're writing a node application, you're
likely using start for starting your server. In that case, you can create a default script which will be run
when nps is run without arguments (so effectively it'll work just the same). But if you'd prefer, you can use whatever
you wish. For example you could easily create a nps script and do: npm run nps b.
This module is distributed via npm which is bundled with node and should
be installed as one of your project's devDependencies:
npm install --save-dev p-s
You can install this module globally also (this is recommended):
npm install --global p-s
From here you can use p-s on the command line via one of the installed aliases: nps or p-s.
If you do this, you may also be interested in installing the shell autocompletion script. Do so by running:
nps completion <optionally-your-bash-profile-file>
The bash profile file defaults to ~/.bash_profile for bash and ~/.zshrc for zsh. Special thanks to the
omelette package for making this so easy.
If you're already using npm scripts, you can get up and going really quickly with the init command:
./node_modules/.bin/nps init
or
./node_modules/.bin/nps init --type yaml
This will use your package.json scripts to generate a package-scripts.js (respectively a package-scripts.yml)
file and update your scripts to utilize the nps binary.
If you have a help script, then your help script will be run. Otherwise, this will output the help.
Note: you can do this with
nps --help, but if you're using thestartscript in yourpackage.jsonthis allows you to runnpm start helprather thannpm start -- --help
As indicated above, this will migrate your npm scripts to package-scripts.
Installs autocompletion functionality into your default bash or zsh configuration. You can override the default by providing a specific file:
nps completion ~/.bashrcNote: you should probably only do this if you have the package installed globally. In that case you should probably also
normally use the nps alias rather than p-s because it's easier to type.
Will print out the help you see above (the available scripts are colored π and come from the config specified/default config).
By default, nps will log out to the console before running the command. You can add -s to your command to silence
this.
Run the given scripts in parallel. This enables handy workflows like this:
nps -p lint,build,cover && nps check-coverage && nps report-coverageUse a different config
nps -c ./other/package-scripts.js lint
Normally, npss will look for a package-scripts.js file and load that to get the scripts. Generally you'll want to
have this at the root of your project (next to the package.json). But by specifying -c or --config, nps will
use that file instead.
Specify the log level to use
You can specify a module which will be loaded before the config file is loaded. This allows you to preload for example babel-register so you can use all babel presets you like.
You can pass additional arguments to the script(s) that are being spawned:
nps lint --fix # --fix will be passed on to the lint scriptIf you don't use -p (because you don't need parallelism) then you can simply provide the name of the script like so:
nps coverAnd you can run multiple scripts in series by providing a comma-separated list:
nps cover,check-coverageThat's all for the CLI.
nps expects to your package-scripts.js file to module.exports an object with the following properties:
This can be an object or a function that returns an object. See the annotated example below for what this object can look like (and different ways to run them):
module.exports = {
scripts: {
default: 'echo "This runs on `nps`"', // nps
// you can assign a script property to a string
simple: 'echo "this is easy"', // nps simple
// you can specify whether some scripts should be excluded from the help list
hidden: {
script: 'debugging script',
hiddenFromHelp: true,
},
test: {
default: {
script: 'jest', // nps test
description: 'Run tests with jest',
// your scripts will be run with node_modules/.bin in the PATH, so you can use locally installed packages.
// this is done in a cross-platform way, so your scripts will work on Mac and Windows :)
// NOTE: if you need to set environment variables, I recommend you check out the cross-env package, which works
// great with p-s
},
otherStuff: {
// this one can be executed two different ways:
// 1. nps test.otherStuff
// 2. nps test.other-stuff
script: 'echo "testing other things"',
description: 'this is a handy description',
},
},
// this one can be executed a few different ways:
// 1. nps k
// 2. nps kebab-case
// 3. nps kebabCase
'kebab-case': 'echo "kebab-case"',
series: 'nps simple,test,kebabCase', // runs these other scripts in series
},
}nps k # runs nps kebab-caseThis object is used to configure nps with the following options:
Setting this to true will prevent nps from outputting anything for your script (normally you'll get simple output
indicating the command that's being executed). This effectively sets the logLevel to disable.
This sets the logLevel of nps.
By setting LOG_LEVEL environment variable you can control the log level for nps
Log levels available:
error- errors onlywarn- errors and warnings onlyinfo- info, errors, and warnings (default)
Just to be clear: You do not have to use the start script. You can use whatever you like. But I recommend using
the start. npm scripts are generally run with npm run <script-name>. There are some exceptions to
this. For example:
npm run test===npm test===npm tnpm run start===npm start
So, while you could use a script called script and run npm run script build, I just think it reads more clearly to
just use the start script and run npm start build. It's also nice that it's fewer things to type. You could also use
the test script and then type even less: npm t build, but thats just... odd.
Note, often servers are configured to run npm start by default to start the server. To allow for this case, you can
provide a default script at the root of your scripts which will be run when npm start is run without any arguments.
Effectively this will allow you to have a script run when npm start is executed.
This was inspired by a tweet by @sindresorhus.
- scripty has a solution for this problem as well. The reason I didn't go with that though is you still need a line for every script (one of the pains I'm trying to solve) and a each script requires its own file (one of the benefits of npm scripts I wanted to keep).
- react-component-template uses
p-sto implement shareable npm scripts. See then how dependent react-swap can reuse them.
GOTCHAS:
-
use
process.cwd()as the base for all paths -
Hypercubed/EventsSpeedTests uses
p-sto automate benchmark running and reporting in node and the browser.package-scripts.jsenables us to keep our scripts DRY. Combined with grunion allows benchmarks to be run, serially or concurrently, on glob patterns. -
SmithersAssistant/Smithers is an electron based personal assistant. Smithers works on multiple platforms. Smithers uses
p-sto dynamically find the current platform and execute the dev environment. Now we don't have to manually update thepackage.jsonscripts when you are on a different platform!
Thanks goes to these people (emoji key):
This project follows the all-contributors specification. Contributions of any kind welcome!
MIT