前端开发者丨JavaScript
npm scripts 使用指南node 开发离不开 npm, 而脚本功能是 npm 最强大、 最常用的功能之一。
本文介绍如何使用 npm 脚本( npm scripts)。
一、 什么是 npm 脚本? npm 允许在 package.json 文件里面, 使用 scripts 字段定义脚本命令。 { // … “scripts”: { “build”: “node build.js” } } 1 2 3 4 5 6 { // … “scripts” : { “build” : “node build.js” } }上面代码是 package.json 文件的一个片段,里面的 scripts 字段是一个对象。
它的每一个属性, 对应一段脚本。
比如, build命令对应的脚本是nodebuild.js。
命令行下使用npmrun命令, 就可以执行这段脚本。
$npmrunbuild# 等同于执行$nodebuild.js123$npmrunbuild# 等同于执行$nodebuild.js这些定义在package.json里面的脚本, 就称为npm脚本。
它的优点很多。
项目的相关脚本, 可以集中在一个地方。
不同项目的脚本命令, 只要功能相同, 就可以有同样的对外接口。
用户不需要知道怎么测试你的项目, 只要运行npmruntest即可。
即可。
可以利用npm提供的很多辅助功能。
查看当前项目的所有npm脚本命令, 可以使用不带任何参数的npmrun命令。
$npmrun1$npmrun二、 原理npm脚本的原理非常简单。
每当执行npmrun, 就会自动新建一个Shell, 在这个Shell里面执行指定的脚本命令。
因此, 只要是Shell( 一般是Bash) 可以运行的命令, 就可以写在npm脚本里面。
比较特别的是, npmrun新建的这个Shell, 会将当前目录的node_modules/.bin子目录加入PATH变量, 执行结束后, 再将PATH变量恢复原样。
这意味着, 当前目录的node_modules/.bin子目录里面的所有脚本, 都可以直接用脚本名调用, 而不必加上路径。
比如, 当前项目的依赖里面有Mocha, 只要直接写mochatest就可以了。
“test”: “mocha test”
1″test”: “mocha test”
而不用写成下面这样。
“test”: “./node_modules/.bin/mocha test”
1″test”: “./node_modules/.bin/mocha test”
由于npm脚本的唯一要求就是可以在Shell执行, 因此它不一定是node脚本, 任何可执行文件都可以写在里面。
npm脚本的退出码, 也遵守Shell脚本规则。
如果退出码不是0, npm就认为这个脚本执行失败。
三、 通配符由于npm脚本就是Shell脚本, 因为可以使用Shell通配符。
“lint”: “jshint *.js”
“lint”: “jshint **/*.js”
12″lint”: “jshint *.js”
“lint”: “jshint **/*.js”
上面代码中, *表示任意文件名, **表示任意一层子目录。
如果要将通配符传入原始命令, 防止被Shell转义, 要将星号转义。
“test”: “tap test/*.js”
1″test”: “tap test/*.js”
四、 传参向npm脚本传入参数, 要使用–标明。
“lint”: “jshint **.js”
1″lint”: “jshint **.js”
向上面的npmrunlint命令传入参数, 必须写成下面这样。
$npmrunlint—-reportercheckstyle>checkstyle.xml1$npmrunlint—-reportercheckstyle>checkstyle.xml也可以在package.json里面再封装一个命令。 “lint”: “jshint **.js”,”lint:checkstyle”: “npm run lint — –reporter checkstyle > checkstyle.xml”
12″lint”: “jshint **.js”,”lint:checkstyle”: “npm run lint — –reporter checkstyle > checkstyle.xml”
五、 执行顺序如果npm脚本里面需要执行多个任务, 那么需要明确它们的执行顺序。
如果是并行执行( 即同时的平行执行), 可以使用&符号。
$npmrunscript1.js&npmrunscript2.js1$npmrunscript1.js&npmrunscript2.js如果是继发执行( 即只有前一个任务成功, 才执行下一个任务), 可以使用&&符号。
$npmrunscript1.js&&npmrunscript2.js1$npmrunscript1.js&&npmrunscript2.js这两个符号是Bash的功能。
此外, 还可以使用node的任务管理模块: script-runner、 npm-run-all、 redrun。
六、 默认值一般来说, npm脚本由用户提供。
但是, npm对两个脚本提供了默认值。
也就是说, 这两个脚本不用定义, 就可以直接使用。
“start”: “node server.js”,
“install”: “node-gyp rebuild”
12″start”: “node server.js”,
“install”: “node-gyp rebuild”
上面代码中, npmrunstart的默认值是nodeserver.js, 前提是项目根目录下有server.js这个脚本; npmruninstall的默认值是node-gyprebuild, 前提是项目根目录下有binding.gyp文件。
七、 钩子npm脚本有pre和post两个钩子。
举例来说, build脚本命令的钩子就是prebuild和postbuild。
“prebuild”: “echo I run before the build script”,”build”: “cross-env NODE_ENV=production webpack”,”postbuild”: “echo I run after the build script”
123″prebuild”: “echo I run before the build script”,”build”: “cross-env NODE_ENV=production webpack”,”postbuild”: “echo I run after the build script”
用户执行npmrunbuild的时候, 会自动按照下面的顺序执行。
npmrunprebuild&&npmrunbuild&&npmrunpostbuild1npmrunprebuild&&npmrunbuild&&npmrunpostbuild因此, 可以在这两个钩子里面, 完成一些准备工作和清理工作。
下面是一个例子。
“clean”: “rimraf ./dist && mkdir dist”,”prebuild”: “npm run clean”,”build”: “cross-env NODE_ENV=production webpack”
123″clean”: “rimraf ./dist && mkdir dist”,”prebuild”: “npm run clean”,”build”: “cross-env NODE_ENV=production webpack”
npm默认提供下面这些钩子。
prepublish, postpublishpreinstall, postinstallpreuninstall, postuninstallpreversion, postversionpretest, posttestprestop, poststopprestart, poststartprerestart, postrestart自定义的脚本命令也可以加上pre和post钩子。
比如, myscript这个脚本命令, 也有premyscript和postmyscript钩子。
不过, 双重的pre和post无效, 比如prepretest和postposttest是无效的。
npm提供一个npm_lifecycle_event变量, 返回当前正在运行的脚本名称, 比如pretest、 test、 posttest等等。
所以, 可以利用这个变量, 在同一个脚本文件里面, 为不同的npmscripts命令编写代码。
请看下面的例子。
constTARGET= 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!`);
}
12345678910111213
constTARGET= 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 ! `);
}
八、 简写形式四个常用的npm脚本有简写形式。
npmstart是npmrunstart是npmstop是npmrunstop的简写是的简写npmtest是npmruntest的简写是的简写npmrestart是npmrunstop&&npmrunrestart&&npmrunstart的简写npmstart、 npmstop和npmrestart都比较好理解, 而npmrestart是一个复合命令, 实际上会执行三个脚本命令: stop、 restart、 start。
具体的执行顺序如下。
prerestartprestopstoppoststoprestartprestartstartpoststartpostrestart九、 变量npm脚本有一个非常强大的功能, 就是可以使用npm的内部变量。
首先, 通过npm_package_前缀, npm脚本可以拿到package.json里面的字段。
比如, 下面是一个package.json。 {
“name”: “foo”,
“version”: “1.2.5”,
“scripts”: {
“view”: “node view.js”
}
}
1234567{
“name”: “foo”,
“version”: “1.2.5”,
“scripts”: {
“view”: “node view.js”
}
}
那么, 变量npm_package_name返回foo, 变量npm_package_version返回1.2.5。
// view.js console.log(process.env.npm_package_name); // foo console.log(process.env.npm_package_version); // 1.2.5 1 2 3 // view.js console . log ( process . env . npm_package_name ) ; // foo console . log ( process . env . npm_package_version ) ; // 1.2.5上面代码中,我们通过环境变量 process.env 对象,拿到 package.json 的字段值。
如果是Bash脚本, 可以用$npm_package_name和$npm_package_version取到这两个值。
npm_package_前缀也支持嵌套的package.json字段。 “repository”: {
“type”: “git”,
“url”: “xxx”
},scripts: {
“view”: “echo $npm_package_repository_type”
}
1234567″repository”: {
“type”: “git”,
“url”: “xxx”
},scripts: {
“view”: “echo $npm_package_repository_type”
}
上面代码中, repository字段的type属性, 可以通过npm_package_repository_type取到。
下面是另外一个例子。
“scripts”:{
“install”:”foo.js”
}
123″scripts”:{
“install”:”foo.js”
}
上面代码中, npm_package_scripts_install变量的值等于foo.js。
然后, npm脚本还可以通过npm_config_前缀, 拿到npm的配置变量, 即npmconfiggetxxx命令返回的值。
比如, 当前模块的发行标签, 可以通过npm_config_tag取到。
“view”:”echo $npm_config_tag”, 1″view”:”echo $npm_config_tag”, 注意, package.json里面的config对象, 可以被环境变量覆盖。 {
“name”:”foo”,
“config”:{
“port”:”8080″
},
“scripts”:{
“start”:”node server.js”
}
}
12345{
“name”:”foo”,
“config”:{
“port”:”8080″
},
“scripts”:{
“start”:”node server.js”
}
}
上面代码中, npm_package_config_port变量返回的是8080。
这个值可以用下面的方法覆盖。
$npmconfigsetfoo:port801$npmconfigsetfoo:port80最后, env命令可以列出所有环境变量。 “env”:”env”
1″env”:”env”
十、 常用脚本示例// 删除目录 “clean”: “rimraf dist/*”, // 本地搭建一个 HTTP 服务 “serve”: “http-server -p 9090 dist/”, // 打开浏览器 “open:dev”: “opener https://www.rokub.com:9090”, // 实时刷新 “livereload”: “live-reload –port 9091 dist/”, // 构建 html 文件 “build:html”: “jade index.jade > dist/index.html”, // 只要 css 文件有变动,就重新执行构建 “watch:css”: “watch ‘npm run build:css’ assets/styles/”, // 只要 HTML 文件有变动,就重新执行构建 “watch:html”: “watch ‘npm run build:html’ assets/html”, // 部署到 Amazon S3 “deploy:prod”: “s3-cli sync ./dist/ s3://example-com/prod-site/”, // 构建 favicon “build:favicon”: “node scripts/favicon.js”, 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 // 删除目录 “clean” : “rimraf dist/*” , // 本地搭建一个 HTTP 服务 “serve” : “http-server -p 9090 dist/” , // 打开浏览器 “open:dev” : “opener https://www.rokub.com:9090” , // 实时刷新 “livereload” : “live-reload –port 9091 dist/” , // 构建 HTML 文件 “build:html” : “jade index.jade > dist/index.html” , // 只要 CSS 文件有变动,就重新执行构建 “watch:css” : “watch ‘npm run build:css’ assets/styles/” , // 只要 HTML 文件有变动,就重新执行构建 “watch:html” : “watch ‘npm run build:html’ assets/html” , // 部署到 Amazon S3 “deploy:prod” : “s3-cli sync ./dist/ s3://example-com/prod-site/” , // 构建 favicon “build:favicon” : “node scripts/favicon.js” 。
前端开发者丨JavaScript
评论前必须登录!
注册