Login With Github

Npm Scripts Tutorial In 10 Minutes

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 pres and posts 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 the npm publish command, but will also run before the npm install (without any arguments) command. However, such behavior is very easy to make users confused, so npm 4 introduces a new hook prepare which behaves like prepublish. And starting with npm 5, the prepublish hook will only run before the npm publish command.

8. The Abbreviated Forms

Here are the shorter versions for the four commonly used npm scripts.

  • npm start is short for npm run start
  • npm stop is short for npm run stop
  • npm test is short for npm run test
  • npm restart is short for npm 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

0 Comment