指令碼

npm 處理「指令碼」欄位的說明

選擇 CLI 版本

說明

package.json 檔案的 "scripts" 屬性支援多個內建指令碼和其預設的生命週期事件,以及任意指令碼。這些都可以透過執行 npm run-script <stage> 或簡寫的 npm run <stage> 來執行。對於這些指令碼,也會執行具有相符名稱的 前置後置 指令碼 (例如 premyscriptmyscriptpostmyscript)。相依性的指令碼可以使用 npm explore <pkg> -- npm run <stage> 來執行。

前置和後置指令碼

若要為在 package.json"scripts" 區段中定義的任何腳本建立「pre」或「post」腳本,只要建立另一個 名稱相符 的腳本,並在開頭加上「pre」或「post」即可。

{
"scripts": {
"precompress": "{{ executes BEFORE the `compress` script }}",
"compress": "{{ run command to compress files }}",
"postcompress": "{{ executes AFTER `compress` script }}"
}
}

在此範例中,npm run compress 會如說明所述執行這些腳本。

生命週期指令碼

有些特殊生命週期腳本只會在特定情況下發生。這些腳本會在 pre<event>post<event><event> 腳本之外發生。

  • prepareprepublishprepublishOnlyprepackpostpackdependencies

prepare (自 npm@4.0.0 起)

  • 在封裝套件之前執行,例如在 npm publishnpm pack 期間執行

  • 在沒有任何引數的情況下執行本機 npm install

  • prepublish 之後,但在 prepublishOnly 之前執行

  • 注意:如果透過 git 安裝的套件包含 prepare 腳本,則會在封裝並安裝套件之前,安裝其 dependenciesdevDependencies,並執行 prepare 腳本。

  • npm@7 起,這些腳本會在背景執行。若要查看輸出,請使用 --foreground-scripts 執行。

prepublish (已棄用)

  • npm publish 期間不會執行,但在 npm cinpm install 期間會執行。請參閱下方以取得更多資訊。

prepublishOnly

  • 在準備並封裝套件之前執行,僅在 npm publish 中執行。

prepack

  • 在封裝 tarball 之前執行(在「npm pack」、「npm publish」以及安裝 git 相依項時執行)。
  • 注意:「npm run pack」與「npm pack」不同。「npm run pack」是使用者定義的任意腳本名稱,而「npm pack」是 CLI 定義的指令。

postpack

  • 在產生 tarball 之後,但在將其移至最終目的地之前執行(如果有的話,發布不會在本地儲存 tarball)

dependencies

  • 在對 node_modules 目錄進行任何修改操作之後執行,如果發生變更。
  • 不會在全域模式中執行

準備和預發佈

棄用注意事項:prepublish

npm@1.1.71 起,npm CLI 已同時為 npm publishnpm install 執行 prepublish 腳本,因為這是一種為套件做好使用準備的便利方式(以下部分說明一些常見的使用案例)。實際上,這也證明 非常令人困惑。自 npm@4.0.0 起,已推出一個新事件 prepare,用於保留這項既有行為。已新增一個事件 prepublishOnly,作為過渡策略,讓使用者避免現有 npm 版本令人困惑的行為,而且僅在 npm publish 上執行(例如,最後一次執行測試,以確保它們處於良好狀態)。

請參閱 https://github.com/npm/npm/issues/10074,深入了解這項變更的理由,並進一步閱讀。

使用案例

如果您需要在套件使用前執行作業,而且作業不依賴目標系統的操作系統或架構,請使用 prepublish 腳本。這包括以下任務

  • 將 CoffeeScript 原始碼編譯成 JavaScript。
  • 建立 JavaScript 原始碼的縮小版本。
  • 擷取套件將使用的遠端資源。

prepublish 時間執行這些作業的優點是,它們可以在單一位置執行一次,從而降低複雜性和變異性。此外,這表示

  • 您可以依賴 coffee-script 作為 devDependency,因此您的使用者不需要安裝它。
  • 您不需要在套件中包含縮小程式,以減少使用者的檔案大小。
  • 您不需要依賴使用者在目標機器上擁有 curlwget 或其他系統工具。

相依性

只要 npm 指令造成 node_modules 目錄變更,就會執行 dependencies 指令碼。在變更套用後,且 package.jsonpackage-lock.json 檔案更新後,才會執行此指令碼。

生命週期操作順序

npm cache add

  • prepare

npm ci

  • preinstall
  • install
  • postinstall
  • prepublish
  • preprepare
  • prepare
  • postprepare

這些指令碼會在模組實際安裝到 node_modules 之後,依序執行,其間不會執行任何內部動作

npm diff

  • prepare

npm install

執行 npm install -g <pkg-name> 時,也會執行這些指令碼

  • preinstall
  • install
  • postinstall
  • prepublish
  • preprepare
  • prepare
  • postprepare

如果您的套件根目錄中有一個 binding.gyp 檔案,而且您尚未定義自己的 installpreinstall 指令碼,npm 會預設 install 指令,透過 node-gyp rebuild 使用 node-gyp 編譯

這些指令碼會從 <pkg-name> 的指令碼執行

npm pack

  • prepack
  • prepare
  • postpack

npm publish

  • prepublishOnly
  • prepack
  • prepare
  • postpack
  • publish
  • postpublish

npm rebuild

  • preinstall
  • install
  • postinstall
  • prepare

prepare 僅在目前目錄為符號連結時執行(例如連結套件)

npm restart

如果已定義 restart 指令碼,則執行這些事件,否則如果存在,則執行 stopstart,包括其 prepost 迭代)

  • prerestart
  • restart
  • postrestart

npm run <user defined>

  • pre<user-defined>
  • <user-defined>
  • post<user-defined>

npm start

  • prestart
  • start
  • poststart

如果套件根目錄中有一個 server.js 檔案,則 npm 會將 start 指令預設為 node server.js。在這種情況下,prestartpoststart 仍會執行。

npm stop

  • prestop
  • stop
  • poststop

npm test

  • pretest
  • test
  • posttest

npm version

  • preversion
  • version
  • postversion

關於缺乏 npm uninstall 指令碼的注意事項

雖然 npm v6 有 uninstall 生命週期指令碼,但 npm v7 沒有。移除套件的原因可能有很多,目前沒有明確的方法可以為指令碼提供足夠的內容以使其有用。

移除套件的原因包括

  • 使用者直接移除此套件
  • 使用者移除依賴套件,因此此依賴項也正在移除
  • 使用者移除依賴套件,但其他套件也依賴此版本
  • 此版本已與另一個版本合併為重複版本

由於缺乏必要的內容,uninstall 生命周期腳本尚未實作,且無法運作。

使用者

當 npm 以 root 身分執行時,腳本總是會以工作目錄擁有者的有效 uid 和 gid 執行。

環境

套件腳本在環境中執行,其中提供了許多關於 npm 設定和目前處理程序狀態的資訊。

路徑

如果您依賴定義可執行腳本的模組,例如測試套件,則這些可執行檔會加入到 PATH 中,以執行腳本。因此,如果您的 package.json 具有以下內容

{
"name": "foo",
"dependencies": {
"bar": "0.1.x"
},
"scripts": {
"start": "bar ./test"
}
}

則您可以執行 npm start 來執行 bar 腳本,該腳本會在 npm install 時匯出到 node_modules/.bin 目錄中。

package.json 變數

package.json 欄位會附加到 npm_package_ 前置詞。因此,例如,如果您在 package.json 檔案中有 {"name":"foo", "version":"1.2.5"},則您的套件腳本會將 npm_package_name 環境變數設定為「foo」,並將 npm_package_version 設定為「1.2.5」。您可以在程式碼中使用 process.env.npm_package_nameprocess.env.npm_package_version 存取這些變數,其他欄位也一樣。

請參閱 package.json,以進一步瞭解套件組態。

目前的生命週期事件

最後,npm_lifecycle_event 環境變數會設定為正在執行的循環階段。因此,您可以使用單一腳本,針對處理程序的不同部分進行切換,具體取決於目前正在發生的事情。

物件會按照此格式扁平化,因此如果您在 package.json 中有 {"scripts":{"install":"foo.js"}},則您會在腳本中看到以下內容

process.env.npm_package_scripts_install === "foo.js"

範例

例如,如果您的 package.json 包含以下內容

{
"scripts": {
"install": "scripts/install.js",
"postinstall": "scripts/install.js"
}
}

然後 scripts/install.js 將會在生命週期的安裝和安裝後階段被呼叫。由於 scripts/install.js 會執行兩個不同的階段,因此在這種情況下,最好查看 npm_lifecycle_event 環境變數。

如果您想執行 make 指令,您可以這麼做。這運作良好

{
"scripts": {
"preinstall": "./configure",
"install": "make && make install",
"test": "make test"
}
}

結束

指令碼會透過將該行傳遞為指令碼引數給 sh 來執行。

如果指令碼以 0 以外的代碼結束,則會中止該程序。

請注意,這些指令碼檔案不必是 Node.js 或甚至是 JavaScript 程式。它們只需要是某種可執行檔即可。

最佳實務

  • 除非您真的這麼想,否則不要以非零錯誤代碼結束。如果失敗是輕微的,或者只會阻止某些選用功能,那麼最好只印出警告並成功結束。
  • 盡量不要使用指令碼來執行 npm 可以為您執行的動作。請詳閱 package.json,以查看您可以透過適當地描述您的套件來指定和啟用所有事項。一般來說,這將導致更強健且一致的狀態。
  • 檢查 env 以確定要放置的位置。例如,如果 npm_config_binroot 環境變數設定為 /home/user/bin,則不要嘗試將可執行檔安裝到 /usr/local/bin。使用者可能因為某個原因而這樣設定。
  • 不要使用「sudo」為您的指令碼指令加上前置詞。如果由於某些原因需要 root 權限,則會失敗並顯示該錯誤,而使用者會對有問題的 npm 指令使用 sudo。
  • 不要使用 install。請使用 .gyp 檔案進行編譯,並使用 prepare 執行其他任何動作。您幾乎不應該明確設定 preinstall 或 install 指令碼。如果您正在執行此操作,請考慮是否有其他選項。唯一有效的 installpreinstall 指令碼用途是編譯,而編譯必須在目標架構上執行。
  • 指令碼會從套件資料夾的根目錄執行,而不管在呼叫 npm 時目前的作業目錄為何。如果您希望您的指令碼根據您所在的子目錄使用不同的行為,您可以使用 INIT_CWD 環境變數,它會儲存您在執行 npm run 時所在的完整路徑。

另請參閱