Npm Scripts Tutorial In 10 Minutes
- ·
- 01 Feb 2019
- ·
- ·
- 10497 Views
You'll have to work with npm when developing using Node, and scripting is one of the most powerful and common features of npm.
I'll introduce how to use npm scripts in this article.
1. What's npm Scripts?
Npm allows you to define script commands using the scripts
field in the package.json
file.
{
// ...
"scripts": {
"build": "node build.js"
}
}
The above code is a fragment of the package.json
file, and the scripts
field here is an object. Each of its properties corresponds to a script. For example, the script corresponding to the build
command is node build.js
.
The script will be executed if you use the npm run
command under the command line.
$ npm run build
# equivalent to execution
$ node build.js
These scripts that are defined in the package.json
are called npm scripts. There are many advantages:
- Project-related scripts can be put together in one place.
- Script commands for different projects can use the same external interface as long as they have the same function. Users don't need to know how to test your project, just run npm run test.
- You can take advantage of many of the accessibility features provided by npm.
You can use the npm run
command without any parameters to view all npm script commands for the current project.
$ npm run
2. The Principle
The principle of npm scripts is very simple. Whenever npm run
is executed, a new shell will be created automatically and the specified script command will be executed in the shell. Therefore, as long as the command can be run by shell (usually Bash), it can be written in the npm scripts.
What's special is that the shell created by npm run
will add the node_modules/.bin
subdirectory of the current directory to the PATH
variable, and the PATH
variable will be restored after the execution.
It means that all scripts in the node_modules/.bin subdirectory of the current directory can be called through the scripts' names directly without having to add the path. For example, if there is a Mocha in the dependencies of the current project, you just need to write mocha test
directly:
"test": "mocha test"
instead of writing it like this:
"test": "./node_modules/.bin/mocha test"
Since the only requirement for the npm scripts is that the scripts can be executed in the shell, they are not necessarily Node scripts and any executable file can be written inside.
The exit code for npm scripts also follows the rules of shell scripts. If the exit code is not 0
, npm will assume that the script fails to execute.
3. Wildcards
Since the npm scripts are shell scripts, you can use Shell wildcards.
"lint": "jshint *.js"
"lint": "jshint **/*.js"
In the above code, *
means any file name, **
means any subdirectory.
If you want to pass a wildcard to the original command to prevent being escaped by the shell, you must escape the asterisk.
"test": "tap test/\*.js"
4. Pass The Parameters
Use --
to indicate the parameters passed to the npm scripts.
"lint": "jshint **.js"
It must be written as follows if you pass parameters to the above npm run lint
command.
$ npm run lint -- --reporter checkstyle > checkstyle.xml
You can also encapsulate a command again in package.json
.
"lint": "jshint **.js",
"lint:checkstyle": "npm run lint -- --reporter checkstyle > checkstyle.xml"
5. The Order Of Execution
The order of execution needs to be clarified if you want to perform multiple tasks in the npm scripts.
If it is the parallel execution (simultaneous parallel execution), you can use the & symbol.
$ npm run script1.js & npm run script2.js
If it is the sequential execution (the next task is executed only if the previous task is successfully executed), you can use the &&
symbol.
$ npm run script1.js && npm run script2.js
These two symbols are the functions of Bash. In addition, you can use node's task management module: script-runner, npm-run-all, redrun.
6. The Default Values
In general, npm scripts are provided by users. However, npm provides default values for two scripts. In other words, these two scripts can be used directly without definition.
"start": "node server.js",
"install": "node-gyp rebuild"
In the above code, the default value of npm run start
is node server.js
, provided that there is a server.js
script in the root directory of the project; the default value of npm run install
is node-gyp rebuild
, provided that there is a binding.gyp
file in the root directory of the project.
7. The Hooks
The npm scripts have two hooks: pre
and post
. For example, the hooks for the commands of the build
script are prebuild
and postbuild
.
"prebuild": "echo I run before the build script",
"build": "cross-env NODE_ENV=production webpack",
"postbuild": "echo I run after the build script"
It will execute in the following order automatically when the user executes npm run build
.
npm run prebuild && npm run build && npm run postbuild
Therefore, some preparation and cleanup can be done in these two hooks. Here is an example below.
"clean": "rimraf ./dist && mkdir dist",
"prebuild": "npm run clean",
"build": "cross-env NODE_ENV=production webpack"
Npm provides the following hooks by default.
- prepublish,postpublish
- preinstall,postinstall
- preuninstall,postuninstall
- preversion,postversion
- pretest,posttest
- prestop,poststop
- prestart,poststart
- prerestart,postrestart
Custom script commands can also be added with the pre
and post
hooks. For example, the script command myscript
has the premyscript
and postmyscript
hooks. However, double pre
s and post
s are invalid. For example, prepretest
and postposttest
are invalid.
The npm_lifecycle_event
variable provided by npm returns the name of the currently running script, such as pretest
, test
, posttest
, and so on. So, you can use the variable to write code for different commands of npm scripts
in the same script file. Let's take a look at the example below.
const TARGET = process.env.npm_lifecycle_event;
if (TARGET === 'test') {
console.log(`Running the test task!`);
}
if (TARGET === 'pretest') {
console.log(`Running the pretest task!`);
}
if (TARGET === 'posttest') {
console.log(`Running the posttest task!`);
}
Note that the
prepublish
hook will not only run before thenpm publish
command, but will also run before thenpm install
(without any arguments) command. However, such behavior is very easy to make users confused, so npm 4 introduces a new hookprepare
which behaves likeprepublish
. And starting with npm 5, theprepublish
hook will only run before thenpm publish
command.
8. The Abbreviated Forms
Here are the shorter versions for the four commonly used npm scripts.
npm start
is short fornpm run start
npm stop
is short fornpm run stop
npm test
is short fornpm run test
npm restart
is short fornpm run stop && npm run restart && npm run start
npm start
, npm stop
, and npm restart
are all well understood, while the npm restart
is a compound command that actually executes three script commands: stop
, restart
, start
. And the execution sequence is as follows.
- prerestart
- prestop
- stop
- poststop
- restart
- prestart
- start
- poststart
- postrestart
9. Variables
The npm scripts have a very powerful feature which is allowing you to use the internal variables of npm.
First, npm scripts can get the fields in the package.json
with the npm_package_
prefix. For example, here is a package.json
below.
{
"name": "foo",
"version": "1.2.5",
"scripts": {
"view": "node view.js"
}
}
Then, the variable npm_package_name
returns foo
, and the variable npm_package_version
returns 1.2.5
.
// view.js
console.log(process.env.npm_package_name); // foo
console.log(process.env.npm_package_version); // 1.2.5
In the above code, we get the field values of the package.json
through the environment variable process.env
object. If it's a Bash script, you can get the two values with $npm_package_name
and $npm_package_version
.
The npm_package_
prefix also supports nested package.json
fields.
"repository": {
"type": "git",
"url": "xxx"
},
scripts: {
"view": "echo $npm_package_repository_type"
}
In the above code, you can get the type
attribute of the repository
field with npm_package_repository_type
.
Here is another example.
"scripts": {
"install": "foo.js"
}
In the above code, the value of the npm_package_scripts_install
variable is equal to foo.js
.
The configuration variable of npm (the value returned by the npm config get xxx
command), can be also gotten via the npm_config_
prefix. For example, you can get the the release tag of the current module with npm_config_tag
.
"view": "echo $npm_config_tag",
Note that the config
object in the package.json
can be overridden by the environment variable.
{
"name" : "foo",
"config" : { "port" : "8080" },
"scripts" : { "start" : "node server.js" }
}
In the above code, the npm_package_config_port
variable returns 8080
. And this value can be overridden by the following method.
$ npm config set foo:port 80
The env command can list all environment variables.
"env": "env"
10. Examples For Common Scripts
// delete the directory
"clean": "rimraf dist/*",
// build an HTTP service locally
"serve": "http-server -p 9090 dist/",
// open the browser
"open:dev": "opener http://localhost:9090",
// real-time refresh
"livereload": "live-reload --port 9091 dist/",
// build an HTML file
"build:html": "jade index.jade > dist/index.html",
// Re-execute the build as long as the CSS file has changed.
"watch:css": "watch 'npm run build:css' assets/styles/",
// Re-execute the build as long as the HTML file has changed
"watch:html": "watch 'npm run build:html' assets/html",
// Deploy to Amazon S3.
"deploy:prod": "s3-cli sync ./dist/ s3://example-com/prod-site/",
// build favicon
"build:favicon": "node scripts/favicon.js",
11. Reference
- How to Use npm as a Build Tool, by Keith Cirkel
- Awesome npm scripts, by Ryan Zimmerman
0 Comment
Login to post a comment
Login With Github