npm中script腳本的使用

一、什么是 npm 腳本?

npm 允許在package.json文件里面贞瞒,使用scripts字段定義腳本命令。


{
  // ...
  "scripts": {
    "build": "node build.js"
  }
}

上面代碼是package.json文件的一個(gè)片段趁曼,里面的scripts字段是一個(gè)對(duì)象军浆。它的每一個(gè)屬性,對(duì)應(yīng)一段腳本挡闰。比如乒融,build命令對(duì)應(yīng)的腳本是node build.js

命令行下使用npm run命令摄悯,就可以執(zhí)行這段腳本赞季。


$ npm run build
# 等同于執(zhí)行
$ node build.js

這些定義在package.json里面的腳本,就稱為 npm 腳本射众。它的優(yōu)點(diǎn)很多碟摆。

  • 項(xiàng)目的相關(guān)腳本,可以集中在一個(gè)地方叨橱。
  • 不同項(xiàng)目的腳本命令典蜕,只要功能相同舀奶,就可以有同樣的對(duì)外接口。用戶不需要知道怎么測(cè)試你的項(xiàng)目刊棕,只要運(yùn)行npm run test即可察郁。
  • 可以利用 npm 提供的很多輔助功能。

查看當(dāng)前項(xiàng)目的所有 npm 腳本命令轩缤,可以使用不帶任何參數(shù)的npm run命令命迈。


$ npm run

二、原理

npm 腳本的原理非常簡(jiǎn)單火的。每當(dāng)執(zhí)行npm run壶愤,就會(huì)自動(dòng)新建一個(gè) Shell,在這個(gè) Shell 里面執(zhí)行指定的腳本命令馏鹤。因此征椒,只要是 Shell(一般是 Bash)可以運(yùn)行的命令,就可以寫在 npm 腳本里面湃累。

比較特別的是勃救,npm run新建的這個(gè) Shell,會(huì)將當(dāng)前目錄的node_modules/.bin子目錄加入PATH變量治力,執(zhí)行結(jié)束后蒙秒,再將PATH變量恢復(fù)原樣。

這意味著宵统,當(dāng)前目錄的node_modules/.bin子目錄里面的所有腳本晕讲,都可以直接用腳本名調(diào)用,而不必加上路徑马澈。比如益兄,當(dāng)前項(xiàng)目的依賴?yán)锩嬗?Mocha,只要直接寫mocha test就可以了箭券。


"test": "mocha test"

而不用寫成下面這樣净捅。


"test": "./node_modules/.bin/mocha test"

由于 npm 腳本的唯一要求就是可以在 Shell 執(zhí)行,因此它不一定是 Node 腳本辩块,任何可執(zhí)行文件都可以寫在里面蛔六。

npm 腳本的退出碼,也遵守 Shell 腳本規(guī)則废亭。如果退出碼不是0国章,npm 就認(rèn)為這個(gè)腳本執(zhí)行失敗。

三豆村、通配符

由于 npm 腳本就是 Shell 腳本液兽,因?yàn)榭梢允褂?Shell 通配符。


"lint": "jshint *.js"
"lint": "jshint **/*.js"

上面代碼中,*表示任意文件名四啰,**表示任意一層子目錄宁玫。

如果要將通配符傳入原始命令,防止被 Shell 轉(zhuǎn)義柑晒,要將星號(hào)轉(zhuǎn)義欧瘪。


"test": "tap test/\*.js"

四、傳參

向 npm 腳本傳入?yún)?shù)匙赞,要使用--標(biāo)明佛掖。


"lint": "jshint **.js"

向上面的npm run lint命令傳入?yún)?shù),必須寫成下面這樣涌庭。


$ npm run lint --  --reporter checkstyle > checkstyle.xml

也可以在package.json里面再封裝一個(gè)命令芥被。


"lint": "jshint **.js",
"lint:checkstyle": "npm run lint -- --reporter checkstyle > checkstyle.xml"

五、執(zhí)行順序

如果 npm 腳本里面需要執(zhí)行多個(gè)任務(wù)坐榆,那么需要明確它們的執(zhí)行順序撕彤。

如果是并行執(zhí)行(即同時(shí)的平行執(zhí)行),可以使用&符號(hào)猛拴。


$ npm run script1.js & npm run script2.js

如果是繼發(fā)執(zhí)行(即只有前一個(gè)任務(wù)成功,才執(zhí)行下一個(gè)任務(wù))蚀狰,可以使用&&符號(hào)愉昆。


$ npm run script1.js && npm run script2.js

這兩個(gè)符號(hào)是 Bash 的功能。此外麻蹋,還可以使用 node 的任務(wù)管理模塊:script-runner跛溉、npm-run-allredrun扮授。

六芳室、默認(rèn)值

一般來說,npm 腳本由用戶提供刹勃。但是堪侯,npm 對(duì)兩個(gè)腳本提供了默認(rèn)值。也就是說荔仁,這兩個(gè)腳本不用定義伍宦,就可以直接使用。


"start": "node server.js"乏梁,
"install": "node-gyp rebuild"

上面代碼中次洼,npm run start的默認(rèn)值是node server.js,前提是項(xiàng)目根目錄下有server.js這個(gè)腳本遇骑;npm run install的默認(rèn)值是node-gyp rebuild卖毁,前提是項(xiàng)目根目錄下有binding.gyp文件。

七落萎、鉤子

npm 腳本有prepost兩個(gè)鉤子亥啦。舉例來說炭剪,build腳本命令的鉤子就是prebuildpostbuild


"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的時(shí)候禁悠,會(huì)自動(dòng)按照下面的順序執(zhí)行念祭。


npm run prebuild && npm run build && npm run postbuild

因此,可以在這兩個(gè)鉤子里面碍侦,完成一些準(zhǔn)備工作和清理工作粱坤。下面是一個(gè)例子。


"clean": "rimraf ./dist && mkdir dist",
"prebuild": "npm run clean",
"build": "cross-env NODE_ENV=production webpack"

npm 默認(rèn)提供下面這些鉤子瓷产。

  • prepublish站玄,postpublish
  • preinstall,postinstall
  • preuninstall濒旦,postuninstall
  • preversion株旷,postversion
  • pretest,posttest
  • prestop尔邓,poststop
  • prestart晾剖,poststart
  • prerestart,postrestart

自定義的腳本命令也可以加上prepost鉤子梯嗽。比如齿尽,myscript這個(gè)腳本命令,也有premyscriptpostmyscript鉤子灯节。不過循头,雙重的prepost無效,比如prepretestpostposttest是無效的炎疆。

npm 提供一個(gè)npm_lifecycle_event變量卡骂,返回當(dāng)前正在運(yùn)行的腳本名稱,比如pretest形入、test全跨、posttest等等。所以亿遂,可以利用這個(gè)變量螟蒸,在同一個(gè)腳本文件里面,為不同的npm scripts命令編寫代碼崩掘。請(qǐng)看下面的例子七嫌。


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這個(gè)鉤子不僅會(huì)在npm publish命令之前運(yùn)行苞慢,還會(huì)在npm install(不帶任何參數(shù))命令之前運(yùn)行诵原。這種行為很容易讓用戶感到困惑,所以 npm 4 引入了一個(gè)新的鉤子prepare,行為等同于prepublish绍赛,而從 npm 5 開始蔓纠,prepublish將只在npm publish命令之前運(yùn)行。

八吗蚌、簡(jiǎn)寫形式

四個(gè)常用的 npm 腳本有簡(jiǎn)寫形式腿倚。

  • npm startnpm run start
  • npm stopnpm run stop的簡(jiǎn)寫
  • npm testnpm run test的簡(jiǎn)寫
  • npm restartnpm run stop && npm run restart && npm run start的簡(jiǎn)寫

npm startnpm stopnpm restart都比較好理解蚯妇,而npm restart是一個(gè)復(fù)合命令敷燎,實(shí)際上會(huì)執(zhí)行三個(gè)腳本命令:stoprestart箩言、start硬贯。具體的執(zhí)行順序如下。

  1. prerestart
  2. prestop
  3. stop
  4. poststop
  5. restart
  6. prestart
  7. start
  8. poststart
  9. postrestart

九陨收、變量

npm 腳本有一個(gè)非常強(qiáng)大的功能饭豹,就是可以使用 npm 的內(nèi)部變量。

首先务漩,通過npm_package_前綴拄衰,npm 腳本可以拿到package.json里面的字段。比如饵骨,下面是一個(gè)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對(duì)象饼煞,拿到package.json的字段值。如果是 Bash 腳本诗越,可以用$npm_package_name$npm_package_version取到這兩個(gè)值砖瞧。

npm_package_前綴也支持嵌套的package.json字段。


  "repository": {
    "type": "git",
    "url": "xxx"
  },
  scripts: {
    "view": "echo $npm_package_repository_type"
  }

上面代碼中嚷狞,repository字段的type屬性块促,可以通過npm_package_repository_type取到。

下面是另外一個(gè)例子床未。


"scripts": {
  "install": "foo.js"
}

上面代碼中竭翠,npm_package_scripts_install變量的值等于foo.js

然后薇搁,npm 腳本還可以通過npm_config_前綴斋扰,拿到 npm 的配置變量,即npm config get xxx命令返回的值。比如传货,當(dāng)前模塊的發(fā)行標(biāo)簽屎鳍,可以通過npm_config_tag取到。


"view": "echo $npm_config_tag",

注意问裕,package.json里面的config對(duì)象逮壁,可以被環(huán)境變量覆蓋。


{ 
  "name" : "foo",
  "config" : { "port" : "8080" },
  "scripts" : { "start" : "node server.js" }
}

上面代碼中粮宛,npm_package_config_port變量返回的是8080窥淆。這個(gè)值可以用下面的方法覆蓋。


$ npm config set foo:port 80

最后窟勃,env命令可以列出所有環(huán)境變量祖乳。


"env": "env"

十、常用腳本示例


// 刪除目錄
"clean": "rimraf dist/*",

// 本地搭建一個(gè) HTTP 服務(wù)
"serve": "http-server -p 9090 dist/",

// 打開瀏覽器
"open:dev": "opener http://localhost:9090",

// 實(shí)時(shí)刷新
 "livereload": "live-reload --port 9091 dist/",

// 構(gòu)建 HTML 文件
"build:html": "jade index.jade > dist/index.html",

// 只要 CSS 文件有變動(dòng)秉氧,就重新執(zhí)行構(gòu)建
"watch:css": "watch 'npm run build:css' assets/styles/",

// 只要 HTML 文件有變動(dòng)眷昆,就重新執(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",

十一、參考鏈接

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末汁咏,一起剝皮案震驚了整個(gè)濱河市亚斋,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌攘滩,老刑警劉巖帅刊,帶你破解...
    沈念sama閱讀 207,248評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異漂问,居然都是意外死亡赖瞒,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門蚤假,熙熙樓的掌柜王于貴愁眉苦臉地迎上來栏饮,“玉大人,你說我怎么就攤上這事磷仰∨坻遥” “怎么了?”我有些...
    開封第一講書人閱讀 153,443評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵灶平,是天一觀的道長(zhǎng)伺通。 經(jīng)常有香客問我,道長(zhǎng)逢享,這世上最難降的妖魔是什么罐监? 我笑而不...
    開封第一講書人閱讀 55,475評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮瞒爬,結(jié)果婚禮上笑诅,老公的妹妹穿的比我還像新娘调缨。我一直安慰自己,他們只是感情好吆你,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評(píng)論 5 374
  • 文/花漫 我一把揭開白布弦叶。 她就那樣靜靜地躺著,像睡著了一般妇多。 火紅的嫁衣襯著肌膚如雪伤哺。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,185評(píng)論 1 284
  • 那天者祖,我揣著相機(jī)與錄音立莉,去河邊找鬼。 笑死七问,一個(gè)胖子當(dāng)著我的面吹牛蜓耻,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播械巡,決...
    沈念sama閱讀 38,451評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼刹淌,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了讥耗?” 一聲冷哼從身側(cè)響起有勾,我...
    開封第一講書人閱讀 37,112評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎古程,沒想到半個(gè)月后蔼卡,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,609評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡挣磨,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評(píng)論 2 325
  • 正文 我和宋清朗相戀三年雇逞,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片茁裙。...
    茶點(diǎn)故事閱讀 38,163評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡塘砸,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出呜达,到底是詐尸還是另有隱情谣蠢,我是刑警寧澤粟耻,帶...
    沈念sama閱讀 33,803評(píng)論 4 323
  • 正文 年R本政府宣布查近,位于F島的核電站,受9級(jí)特大地震影響挤忙,放射性物質(zhì)發(fā)生泄漏霜威。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評(píng)論 3 307
  • 文/蒙蒙 一册烈、第九天 我趴在偏房一處隱蔽的房頂上張望戈泼。 院中可真熱鬧婿禽,春花似錦、人聲如沸大猛。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽挽绩。三九已至膛壹,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間唉堪,已是汗流浹背模聋。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評(píng)論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留唠亚,地道東北人链方。 一個(gè)月前我還...
    沈念sama閱讀 45,636評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像灶搜,于是被迫代替她去往敵國和親祟蚀。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評(píng)論 2 344

推薦閱讀更多精彩內(nèi)容

  • Node 開發(fā)離不開 npm占调,而腳本功能是 npm 最強(qiáng)大暂题、最常用的功能之一。 本文介紹如何使用 npm 腳本(n...
    鄧海琪閱讀 5,624評(píng)論 0 0
  • 關(guān)鍵詞:npm 定義:npm 允許在package.json文件里面究珊,使用scripts字段定義腳本命令薪者。 上面代...
    ferrint閱讀 13,598評(píng)論 2 6
  • 一、什么是 npm 腳本剿涮? npm 允許在package.json文件里面言津,使用scripts字段定義腳本命令。 ...
    豬豬9527閱讀 388評(píng)論 0 0
  • 什么是 NPM npm之于Node取试,就像pip之于Python,gem之于Ruby,composer之于PHP悬槽。 ...
    ihoey閱讀 6,248評(píng)論 2 36
  • 剛結(jié)束了產(chǎn)品經(jīng)理實(shí)戰(zhàn)訓(xùn)練營的課程,現(xiàn)在留點(diǎn)時(shí)間給自己思考總結(jié)一下瞬浓。 開課第一次聽導(dǎo)師講的初婆,就是產(chǎn)品經(jīng)理要一日三省猿棉!...
    產(chǎn)品汪的故事書閱讀 637評(píng)論 0 0