npm 套件發布強化
目標
將 npm 套件從「本地可運作」狀態提升至「誠實、可審查且可安全發布」的狀態。優先進行真正的驗證而非感覺:套件壓縮包內容、執行環境契約、CI、GitHub 設定以及相依性更新衛生。
從這裡開始
- 確認確切的儲存庫:
pwd
git status --short --branch
git remote -v
- 檢查套件表面:
cat package.json
ls -la
find .github -maxdepth 3 -type f -print 2>/dev/null
- 從 lockfile 偵測套件管理工具:
package-lock.json-> npmpnpm-lock.yaml-> pnpmyarn.lock-> yarn
以下使用 npm 指令作為預設值,但請在需要時轉換為偵測到的套件管理工具對應指令。
套件契約
確保 package.json 說實話:
name:發布目標是有意圖且可用的version:當前預期發布的版本description、keywords:對註冊表搜尋足夠實用license:存在且與LICENSE檔案相符repository、homepage、bugs:指向公開儲存庫。如果公開儲存庫 URL 尚未最終確定,請將其標記為發布前的明確待辦事項,而不是默默地省略它們type、exports、main、bin:與使用者將匯入或執行的內容相符files:將壓縮包限制為可發布的成品engines.node:套件實際支援的最低執行環境prepublishOnly或等效指令:防止發布過時的建置輸出
對於 CLI 套件,請確認 bin 目標已建置、在相關情況下可執行,並透過使用者將執行的指令進行冒煙測試。
執行環境地板規則
Node 引擎是一個承諾,而非裝飾。
- 如果
engines.node設定為>=20,則 CI 必須測試 Node 20。 - 保持
@types/node與最低支援執行環境的主要版本行一致。 - 建議將
@types/node精確鎖定在該執行環境行的最新修補版本。 - 除非同時提高
engines.node,否則不要合併高於執行環境地板的@types/node主要版本變更。 engines.node是建議性質的:npm 只會發出警告,除非使用者設定engine-strict,否則不會強制阻止安裝,因此在地板版本上執行 CI 才是真正執行承諾的方式。
原因:Node 型別僅供開發使用,但它們會改變 TypeScript 所允許的內容。@types/node@26 可能會允許程式碼編譯,但會使用對 Node 20 使用者來說會失敗的 API。
驗證指令
對於 npm 專案:
npm ci
npm run build --if-present
npm test --if-present
npm audit --omit=dev
npm pack --dry-run
對於 pnpm/yarn,請使用等效的 install/build/test/audit/pack 指令。如果審計支援不同,請直接說明,不要假裝。
對於 CLI,也請至少執行一項由外向內的冒煙測試:
node dist/path/to/cli.js --help
npm pack --dry-run
如果可行,請將打包好的 .tgz 安裝在臨時目錄中,並完全按照使用者的方式執行二進位檔。
壓縮包審查
npm pack --dry-run 是註冊表的事實真相。檢查內容:
- 包含建置輸出
- 包含
README.md和LICENSE - 排除僅限原始碼的垃圾檔案、暫存檔、測試檔、私人文件、測試裝置、本地資料庫、機密資訊
- 套件大小合理
- CLI
bin路徑出現在壓縮包中
如果缺少 files 欄位,請新增它。不要依賴 .gitignore 作為發布政策。
GitHub 基礎設定
新增或驗證:
.github/workflows/ci.yml.github/dependabot.yml.github/CODEOWNERS.github/pull_request_template.mdSECURITY.md
對 GitHub 擁有的 action 使用目前支援的主要版本。如果 Actions 警告某個 action 執行環境已棄用,請在 CI 通過後更新該 action 的主要版本。
CI 通常應包含:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
test:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@CURRENT_MAJOR
- uses: actions/setup-node@CURRENT_MAJOR
with:
node-version: 20
cache: npm
- run: npm ci
- run: npm run build --if-present
- run: npm test --if-present
將 node-version 調整為套件的最低支援執行環境,並將每個 @CURRENT_MAJOR 替換為 action 的當前主要版本標籤(例如 actions/checkout@v4)——鎖定到一個真實的主要版本,切勿提交佔位符。
Dependabot 基礎設定
同時設定套件和 GitHub Actions 更新:
version: 2
updates:
- package-ecosystem: npm
directory: /
schedule:
interval: weekly
open-pull-requests-limit: 5
commit-message:
prefix: deps
include: scope
- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
open-pull-requests-limit: 5
commit-message:
prefix: deps
include: scope
當 Dependabot 在設定落地後立即開啟 PR 時,請將其視為設定已生效的證據。分類這些 PR;不要盲目地合併所有通過檢查的 PR。
Dependabot 分類
使用以下經驗法則:
- 執行環境相依性的修補/次要版本:如果檢查通過且發布說明無關緊要,則合併。
- 執行環境相依性的主要版本:檢查發布說明並對真實套件行為進行冒煙測試。
- 開發工具的主要版本:如果建置/測試/打包通過且不改變執行環境契約,則合併。
- 高於執行環境地板的
@types/node:關閉或替換為鎖定到執行環境地板的版本。 - GitHub Actions 的主要版本:如果 CI 通過且移除了棄用警告,則合併。
如果有兩個 PR 在小型設定檔中發生衝突,請合併其中一個並更新另一個,或直接應用第二個 PR,並附上明確的註解說明它已被取代。
GitHub 遠端強化
套用儲存庫/帳戶支援的設定,然後使用 gh 或 API 讀取來驗證實際設定。
有用的設定:
gh repo edit OWNER/REPO \
--delete-branch-on-merge \
--enable-squash-merge \
--enable-merge-commit=false \
--enable-rebase-merge=false \
--allow-update-branch
gh api --method PUT repos/OWNER/REPO/vulnerability-alerts --silent
gh api --method PUT repos/OWNER/REPO/automated-security-fixes --silent
gh api --method PUT repos/OWNER/REPO/actions/permissions/workflow \
-f default_workflow_permissions=read \
-F can_approve_pull_request_reviews=false --silent
對於 Actions 允許清單,當工作流程僅使用 GitHub 擁有的 action 時,建議僅使用 GitHub 擁有的 action。如果需要第三方 action,請明確允許最小的集合。
公開儲存庫通常會解鎖更多安全性控制項。免費方案上的私人儲存庫可能會封鎖:
- 分支保護或規則集
- 程式碼掃描
- 機密掃描
- 推送保護
直接說明封鎖項目。不要將不可用的控制項回報為已啟用。
分支保護
當可用時,使用以下設定保護預設分支:
- 合併前需要拉取請求
- 需要 CI 狀態檢查
- 如果需要,要求分支保持最新
- 需要解決對話
- 封鎖強制推送
- 封鎖刪除
- 如果使用僅限壓縮合併,則要求線性歷史
啟用保護後,除非使用者明確要求並理解繞過方式,否則停止直接推送到 main。
閘道 PR 工具
如果使用自動化審查/閘道工具,請在要求閘道建立 PR 之前,確保遠端有預設/基礎分支。新的空白遠端通常需要先進行初始的 main 推送;否則閘道可以驗證並推送功能分支,但會因為沒有基礎引用而無法建立 PR。
發布檢查清單
在 npm publish 之前:
npm whoami顯示預期的帳戶npm view PACKAGE_NAME name version確認名稱狀態- 要發布的提交上的 CI 為綠色
- 已審查
npm pack --dry-run的結果 - README 中的安裝/使用範例與實際行為相符
repository、homepage和bugs能解析到真實的公開儲存庫(如果 URL 尚未最終確定,則明確標記為待辦事項)- 沒有阻止發布的 Dependabot/安全性警示遺留
- 版本提升是有意圖的,已在 git 中標記(
git tag vX.Y.Z && git push --tags),並反映在 CHANGELOG 或 GitHub Release 中 - 作用域套件(
@scope/name)使用--access public發布(作用域套件預設為限制/私人)
對於使用網頁/通行金鑰/2FA 驗證的帳戶:
npm publish --auth-type=web
建議從 CI 發布,並使用 Provenance 來建立可驗證的供應鏈連結。Provenance 需要公開套件、支援的 CI(例如 GitHub Actions)以及工作上的 id-token: write 權限:
npm publish --provenance --access public
發布後:
npm view PACKAGE_NAME version
npm view PACKAGE_NAME bin files engines repository --json
npx -y PACKAGE_NAME --help
如果使用 Provenance 發布,請確認註冊表在套件頁面上顯示了 Provenance /「Built and signed」證明。
最終回報
僅報告實際驗證過的項目:
- 已執行的套件檢查
- 壓縮包結果
- 相依性 PR 決策
- 已建立或合併的提交/PR
- 已確認的 GitHub 設定
- 因方案/能見度而封鎖的控制項
- 發布標籤和 Provenance 狀態(如果已發布)
- 發布指令或發布後驗證(如果仍由使用者擁有)