p-s
aka npm-package-scripts or nps
for short
All the benefits of npm scripts without the cost of a bloated package.json and limits of json
Quick Video Intro :tv:
Pull out npm scripts into another file with p-s by Elijah Manor (5:53)
The problem
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).
This solution
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: {
default: 'jest',
watch: {
script: 'jest --watch',
description: 'run in the amazingly intelligent Jest watch mode'
}
},
build: {
default: 'webpack',
prod: 'webpack -p',
},
validate: 'concurrently "nps lint" "nps test" "nps 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:
default: jest
watch:
script: jest --watch
description: run in the amazingly intelligent Jest watch mode
build:
default: webpack
prod: webpack -p
validate: concurrently "nps lint" "nps test" "nps build"
To 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, find out how here).
Then you can run:
nps help
Which will output:
Usage: nps [options] <script>...
Commands:
init automatically migrate from npm scripts to p-s
completion generate bash completion script
Options:
--config, -c Config file to use (defaults to nearest package-scripts.yml
or package-scripts.js)
[default: "<path-to-your-project>/package-scripts.js"]
--silent, -s Silent nps output [boolean] [default: false]
--log-level, -l The log level to use
[choices: "error", "warn", "info", "debug"] [default: "info"]
--require, -r Module to preload
-h, --help Show help [boolean]
-v, --version Show version number [boolean]
Examples:
nps.js test build Runs the `test` script then the
`build` script
nps.js "test --cover" "build --prod" Runs the `test` script and forwards
the "--cover" flag then the `build`
script and forwards the "--prod"
flag
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 - concurrently "nps lint" "nps test" "nps build"
Because 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 script
And these prefixes can go as deep as you like!
nps b.p # will run the production build script
Cool 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
.
Installation
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
global installation
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. See more about this below.
Getting started
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.
API
CLI
Commands
help
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 the start
script in your package.json
this allows you
to run npm start help
rather than npm start -- --help
init
As indicated above, this will migrate your npm scripts to package-scripts.
completion
nps completion >> <your-bash-profile-file>
Normally <your-bash-profile-file>
will be ~/.bash_profile
, ~/.bashrc
, or ~/.zshrc
.
Note: 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.
CLI options
-h, --help
Will print out the help you see above (the available scripts are colored 🌈 and come from the config specified/default
config).
-s, --silent
By default, nps
will log out to the console before running the command. You can add -s
to your command to silence
this.
-c, --config
Use a different config
nps -c ./other/package-scripts.js lint
Normally, nps
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.
-l, --log-level
Specify the log level to use
-r, --require
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.
scripts
To run a script, you simply provide the name of the script like so:
nps cover
And you can run multiple scripts in series by simply adding more space-separated arguments.
nps cover check-coverage
And you can pass arguments to scripts by putting the scripts in quotes:
nps "test --cover" check-coverage
That's all for the CLI.
package-scripts.js
Remember, this file is JavaScript, so you can write functions to make things more simple!
See other/EXAMPLES.md for examples of cool things you can do with this.
nps
expects to your package-scripts.js
file to module.exports
an object with the following properties:
scripts
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`"',
simple: 'echo "this is easy"',
hidden: {
script: 'debugging script',
hiddenFromHelp: true,
},
test: {
default: {
script: 'jest',
description: 'Run tests with jest',
},
otherStuff: {
script: 'echo "testing other things"',
description: 'this is a handy description',
},
},
'kebab-case': 'echo "kebab-case"',
series: 'nps simple,test,kebabCase',
},
}
nps k # runs nps kebab-case
options
This object is used to configure nps
with the following options:
silent
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
.
logLevel
This sets the logLevel of nps
.
ENV variables
LOG_LEVEL
By setting LOG_LEVEL
environment variable you can control the log level for nps
Log level
Log levels available:
error
- errors onlywarn
- errors and warnings onlyinfo
- info, errors, and warnings (default)
FAQ
How do I do ___ ?
Have you looked at the examples in other/EXAMPLES.md?
Why npm start
?
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 t
npm 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.
Inspiration
This was inspired by a tweet by @sindresorhus.
Other Solutions
- 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).
Contributors
Thanks goes to these people (emoji key):
This project follows the all-contributors specification.
Contributions of any kind welcome!
LICENSE
MIT