我們都很熟悉的,通過 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…