轉(zhuǎn)載自 npm scripts 使用指南
Node 開發(fā)離不開 npm腺晾,而腳本功能是 npm 最強大翎卓、最常用的功能之一。
本文介紹如何使用 npm 腳本(npm scripts)鹤竭。
一忙上、什么是 npm 腳本?
npm 允許在package.json
文件里面锅劝,使用scripts
字段定義腳本命令攒驰。
{
// ...
"scripts": {
"build": "node build.js"
}
}
上面代碼是package.json
文件的一個片段,里面的scripts
字段是一個對象故爵。它的每一個屬性玻粪,對應(yīng)一段腳本。比如稠集,build
命令對應(yīng)的腳本是node build.js
奶段。
命令行下使用npm run
命令饥瓷,就可以執(zhí)行這段腳本剥纷。
$ npm run build
# 等同于執(zhí)行
$ node build.js
這些定義在package.json
里面的腳本,就稱為 npm 腳本呢铆。它的優(yōu)點很多晦鞋。
- 項目的相關(guān)腳本,可以集中在一個地方棺克。
- 不同項目的腳本命令悠垛,只要功能相同,就可以有同樣的對外接口娜谊。用戶不需要知道怎么測試你的項目确买,只要運行
npm run test
即可。 - 可以利用 npm 提供的很多輔助功能纱皆。
查看當(dāng)前項目的所有 npm 腳本命令湾趾,可以使用不帶任何參數(shù)的npm run
命令。
$ npm run
二派草、原理
npm 腳本的原理非常簡單搀缠。每當(dāng)執(zhí)行npm run
,就會自動新建一個 Shell近迁,在這個 Shell 里面執(zhí)行指定的腳本命令艺普。因此,只要是 Shell(一般是 Bash)可以運行的命令鉴竭,就可以寫在 npm 腳本里面歧譬。
比較特別的是,npm run
新建的這個 Shell搏存,會將當(dāng)前目錄的node_modules/.bin
子目錄加入PATH
變量缴罗,執(zhí)行結(jié)束后,再將PATH
變量恢復(fù)原樣祭埂。
這意味著面氓,當(dāng)前目錄的node_modules/.bin
子目錄里面的所有腳本兵钮,都可以直接用腳本名調(diào)用,而不必加上路徑舌界。比如掘譬,當(dāng)前項目的依賴里面有 Mocha,只要直接寫mocha test
就可以了呻拌。
"test": "mocha test"
而不用寫成下面這樣葱轩。
"test": "./node_modules/.bin/mocha test"
由于 npm 腳本的唯一要求就是可以在 Shell 執(zhí)行,因此它不一定是 Node 腳本藐握,任何可執(zhí)行文件都可以寫在里面靴拱。
npm 腳本的退出碼,也遵守 Shell 腳本規(guī)則猾普。如果退出碼不是0
袜炕,npm 就認為這個腳本執(zhí)行失敗。
三初家、通配符
由于 npm 腳本就是 Shell 腳本偎窘,因為可以使用 Shell 通配符。
"lint": "jshint *.js"
"lint": "jshint **/*.js"
上面代碼中溜在,*
表示任意文件名陌知,**
表示任意一層子目錄。
如果要將通配符傳入原始命令掖肋,防止被 Shell 轉(zhuǎn)義仆葡,要將星號轉(zhuǎn)義。
"test": "tap test/\*.js"
四志笼、傳參
向 npm 腳本傳入?yún)?shù)沿盅,要使用--
標明。
"lint": "jshint **.js"
向上面的npm run lint
命令傳入?yún)?shù)籽腕,必須寫成下面這樣嗡呼。
$ npm run lint -- --reporter checkstyle checkstyle.xml
也可以在package.json
里面再封裝一個命令。
"lint": "jshint **.js",
"lint:checkstyle": "npm run lint -- --reporter checkstyle checkstyle.xml"
五皇耗、執(zhí)行順序
如果 npm 腳本里面需要執(zhí)行多個任務(wù)南窗,那么需要明確它們的執(zhí)行順序。
如果是并行執(zhí)行(即同時的平行執(zhí)行)郎楼,可以使用&
符號万伤。
$ npm run script1.js & npm run script2.js
如果是繼發(fā)執(zhí)行(即只有前一個任務(wù)成功,才執(zhí)行下一個任務(wù))呜袁,可以使用&&
符號敌买。
$ npm run script1.js && npm run script2.js
這兩個符號是 Bash 的功能。此外阶界,還可以使用 node 的任務(wù)管理模塊:script-runner虹钮、npm-run-all聋庵、redrun。
六芙粱、默認值
一般來說祭玉,npm 腳本由用戶提供。但是春畔,npm 對兩個腳本提供了默認值脱货。也就是說,這兩個腳本不用定義律姨,就可以直接使用振峻。
"start": "node server.js",
"install": "node-gyp rebuild"
上面代碼中择份,npm run start
的默認值是node server.js
扣孟,前提是項目根目錄下有server.js
這個腳本;npm run install
的默認值是node-gyp rebuild
缓淹,前提是項目根目錄下有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"
用戶執(zhí)行npm run build
的時候伏蚊,會自動按照下面的順序執(zhí)行。
npm run prebuild && npm run build && npm run postbuild
因此格粪,可以在這兩個鉤子里面躏吊,完成一些準備工作和清理工作。下面是一個例子帐萎。
"clean": "rimraf ./dist && mkdir dist",
"prebuild": "npm run clean",
"build": "cross-env NODE_ENV=production webpack"
npm 默認提供下面這些鉤子比伏。
- prepublish,postpublish
- preinstall疆导,postinstall
- preuninstall赁项,postuninstall
- preversion,postversion
- pretest澈段,posttest
- prestop悠菜,poststop
- prestart,poststart
- prerestart败富,postrestart
自定義的腳本命令也可以加上pre
和post
鉤子悔醋。比如,myscript
這個腳本命令兽叮,也有premyscript
和postmyscript
鉤子芬骄。不過猾愿,雙重的pre
和post
無效,比如prepretest
和postposttest
是無效的账阻。
npm 提供一個npm_lifecycle_event
變量匪蟀,返回當(dāng)前正在運行的腳本名稱,比如pretest
宰僧、test
材彪、posttest
等等。所以琴儿,可以利用這個變量段化,在同一個腳本文件里面,為不同的npm scripts
命令編寫代碼造成。請看下面的例子显熏。
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!`);
}
注意,prepublish
這個鉤子不僅會在npm publish
命令之前運行晒屎,還會在npm install
(不帶任何參數(shù))命令之前運行喘蟆。這種行為很容易讓用戶感到困惑,所以 npm 4 引入了一個新的鉤子prepare
鼓鲁,行為等同于prepublish
蕴轨,而從 npm 5 開始,prepublish
將只在npm publish
命令之前運行骇吭。
八橙弱、簡寫形式
四個常用的 npm 腳本有簡寫形式。
-
npm start
是npm run start
-
npm stop
是npm run stop
的簡寫 -
npm test
是npm run test
的簡寫 -
npm restart
是npm run stop && npm run restart && npm run start
的簡寫
npm start
燥狰、npm stop
和npm restart
都比較好理解棘脐,而npm restart
是一個復(fù)合命令,實際上會執(zhí)行三個腳本命令:stop
龙致、restart
蛀缝、start
。具體的執(zhí)行順序如下目代。
- prerestart
- prestop
- stop
- poststop
- restart
- prestart
- start
- poststart
- postrestart
九屈梁、變量
npm 腳本有一個非常強大的功能,就是可以使用 npm 的內(nèi)部變量像啼。
首先俘闯,通過npm_package_
前綴,npm 腳本可以拿到package.json
里面的字段忽冻。比如真朗,下面是一個package.json
。
{
"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
上面代碼中,我們通過環(huán)境變量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"
}
上面代碼中,repository
字段的type
屬性袱衷,可以通過npm_package_repository_type
取到捎废。
下面是另外一個例子。
"scripts": {
"install": "foo.js"
}
上面代碼中致燥,npm_package_scripts_install
變量的值等于foo.js
登疗。
然后,npm 腳本還可以通過npm_config_
前綴嫌蚤,拿到 npm 的配置變量辐益,即npm config get xxx
命令返回的值。比如脱吱,當(dāng)前模塊的發(fā)行標簽智政,可以通過npm_config_tag
取到。
"view": "echo $npm_config_tag",
注意急凰,package.json
里面的config
對象女仰,可以被環(huán)境變量覆蓋猜年。
{
"name" : "foo",
"config" : { "port" : "8080" },
"scripts" : { "start" : "node server.js" }
}
上面代碼中抡锈,npm_package_config_port
變量返回的是8080
。這個值可以用下面的方法覆蓋乔外。
$ npm config set foo:port 80
最后床三,env
命令可以列出所有環(huán)境變量。
"env": "env"
十杨幼、常用腳本示例
// 刪除目錄
"clean": "rimraf dist/*",
// 本地搭建一個 HTTP 服務(wù)
"serve": "http-server -p 9090 dist/",
// 打開瀏覽器
"open:dev": "opener http://localhost:9090",
// 實時刷新
"livereload": "live-reload --port 9091 dist/",
// 構(gòu)建 HTML 文件
"build:html": "jade index.jade dist/index.html",
// 只要 CSS 文件有變動撇簿,就重新執(zhí)行構(gòu)建
"watch:css": "watch 'npm run build:css' assets/styles/",
// 只要 HTML 文件有變動,就重新執(zhí)行構(gòu)建
"watch:html": "watch 'npm run build:html' assets/html",
// 部署到 Amazon S3
"deploy:prod": "s3-cli sync ./dist/ s3://example-com/prod-site/",
// 構(gòu)建 favicon
"build:favicon": "node scripts/favicon.js",
十一差购、參考鏈接
- How to Use npm as a Build Tool, by Keith Cirkel
- Awesome npm scripts, by Ryan Zimmerman
(完)