你真的瞭解npm-scripts嗎?

滴滴WebApp架構組發表於2019-04-15

作者:馮偉堯

GitHub:tank0317

我們都很熟悉的,通過 npm run script-name 可以執行 package.json 中 scripts 物件配置的指令碼。但是,你或許不知道下面這些知識。

下文中 npm-scirpt 指 package.json scripts 中配置的指令碼命令。name-scirpt 指代某一個名字為 name 的指令碼命令。

生命週期指令碼/自定義指令碼

當我們使用命令 npm start 時,npm 會嘗試執行 package.json scripts 中配置的 start 指令碼命令。start-script 的預設配置為 "start": "node server.js"。所以如果專案根目錄下有 server.js 檔案,那麼通過 npm start 會直接執行 server.js 中的程式碼。

除了 start-script ,當使用 npm start 命令時,npm 同樣會嘗試在 package.json scripts 中查詢是否配置了 prestart,poststart 指令碼命令。如果都配置了,npm 會按照以下順序執行指令碼。

  • npm run prestart
  • npm run start
  • npm run poststart

類似的,npm test, npm restart, npm stop 都會按照以上的方式執行 scripts 中配置的對應指令碼。同時 npm 會通過 npm_lifecycle_event 環境變數標識當前處於哪一階段(所謂的生命週期)。比如,在 prestart-script 指令碼執行階段 npm_lifecycle_event 的值為 "prestart",start-script 階段,值為 "start",即 package.json scripts 物件配置的指令碼名字。

以上是 npm 內建命令對應的指令碼執行邏輯,對於我們平時最熟悉的自定義指令碼,以上邏輯同樣適用。比如我們配置了 "build": "webpack --mode=production",同時配置了 prebuild 以及 postbuild 指令碼,當使用 npm run build 時,同樣會依次執行 prebuild-script、build-script、postbuild-script。

任意指令碼

我們配置的指令碼命令,如 "start": "node server.js"node server.js 會當做一行程式碼傳遞給系統的 SHELL 去解釋執行。實際使用的 SHELL 可能會根據系統平臺而不同,類 UNIX 系統裡,如 macOS 或 linux 中指代的是 /bin/sh, 在 windows 中使用的是 cmd.exe。

既然是交給 SHELL 去解釋執行的,說明配置的指令碼可以是任意能夠在 SHELL 中執行的命令,而不僅僅是 node 指令碼或者 js 程式。即如果你的系統裡安裝了 python(或者說系統變數 PATH 裡能找到 python 命令),你也可以將 scripts 配置為 "myscript": "python xxx.py"

環境變數

上面提到了在使用 npm run script-name 命令時,npm 會設定一個環境變數 npm_lifecycle_event。實際上 npm 還會設定很多環境變數,通過內建命令 npm run env 可以檢視 npm 為指令碼執行時設定的所有環境變數。 其中 package.json 中設定的所有欄位,都會被設定為 npm_package_ 開頭的環境變數。如果你的 packge.json 設定如下

{
  "name": "npm-demo",
  "version": "1.0.0",
  "script": {
    "build": "webpack --mode=production"
  },
  "files": ["src"]
}
複製程式碼

則可以得到 npm_package_name、npm_package_version、npm_package_script_build、npm_package_files_0 等變數。注意上面 package.json 中物件和陣列中每個欄位都會有對應的環境變數。

不止 package.json,npm 相關的所有配置也會有 npm_config_ 開頭的環境變數。

另外,需要注意的是,即使在子目錄下使用 npm run 命令,指令碼也會在專案的根目錄下執行。如果你想要區分在哪裡使用的 npm run 命令,可以使用 INIT_CWD 環境變數,該變數儲存了 npm run 命令執行時目錄的絕對路徑。

如何使用這些環境變數?如果你的指令碼是 shell 指令碼,可以直接通過對應的環境變數名獲取變數值,如果是 node 指令碼,可以通過 nodejs 中的全域性變數 process.env 獲取,比如獲取專案版本號可以使用 process.env.npm_package_version

PATH

上面提到了 npm-script 執行前會設定一些環境變數,其中很重要的一個環境變數是 PATH。npm 會將專案 node_modules/.bin 的絕對路徑新增到環境變數 PATH 中。因此我們可以在 npm-script 中使用專案本地安裝的一些命令列工具。如上面設定的 build 指令碼: "build": "webpack --mode=production"

只要我們本地安裝了 webpack,就可以在專案的 node_modules/.bin 路徑下看到 webpack 可執行檔案。又因為 node_modules/.bin 路徑已經新增到 PATH 中,所以指令碼執行時能夠在 PATH 中找到 webpack 命令,從而順利執行。

最後,為什麼 webpack 安裝後,能夠在 node_modules/.bin 路徑下找到對應的可執行檔案?可以檢視 docs.npmjs.com/files/packa…

Reference

docs.npmjs.com/cli/run-scr…

docs.npmjs.com/misc/script…

docs.npmjs.com/files/packa…

相關文章