主決策矩陣(可貼進 Runbook)
下列欄位對齊實務「可執行」欄位:兩種 lock 的責任邊界、鏡像策略、併發上限、快取鍵片段、以及流程級重試停損(與「lock 不一致」類錯誤分離)。
| 決策維度 | 建議策略(遠端 Mac/跨境) | 建議閾值或命名片段 |
|---|---|---|
| Lock 真理來源 | 每個 workspace 目錄只允許一種安裝入口當「主真理」;另一工具僅做執行期(bun run 讀既有 node_modules)或獨立子目錄。禁止在 CI 內交替 bun install 與 npm install 寫同一樹。 |
變更檢查:bun.lockb 與 package-lock.json 的 git diff --exit-code 分開跑;任一失敗即 fail,不重試。 |
| Bun.lockb 凍結安裝 | 以 bun install --frozen-lockfile 為預設;鏡像與 scope 寫 bunfig.toml 或共用 .npmrc(Bun 會讀支援欄位)。 |
併發 HTTP:BUN_CONFIG_MAX_HTTP_REQUESTS 跨境起點建議 16–32;觀察 429 後階梯降到 8–12。 |
| package-lock 凍結安裝 | 使用 npm ci(非 npm install);.npmrc 的 registry/@scope:registry 與 Bun 側同一組端點,避免 resolved 分叉。 |
npm_config_fetch_retries=3;npm_config_fetch_retry_mintimeout=20000;npm_config_fetch_retry_maxtimeout=120000;可再加 npm_config_maxsockets=15 控連線池。 |
| Registry 鏡像 | 企業鏡像或地域加速時,先 ping/HEAD 再全量安裝;雙源(npmjs+GitHub Packages)分開 host 行與 token,勿共用一行半殘 _authToken。 |
鏡像切換屬於配置變更:應觸發 lockfile 審核 PR,而非只在 CI 改環境變數。 |
| 快取鍵命名 | 快取分層:os+cpu(darwin_arm64)+工具版本(bun --version、npm --version)+lock 指紋。 |
範例片段:macos-arm64-bun-1.2.x-sha256(bun.lockb) 與 …-npm-10.x-sha256(package-lock.json);混倉再加 sha256(bunfig.toml,.npmrc) 避免鏡像偷換。 |
| 失敗重試(僅網路類) | 對 ECONNRESET、ETIMEDOUT、502–504、偶發 429:指數退避 2s/4s/8s,最多 3 輪;同一 tarball URL 連續失敗改降併發或切換維護窗口。 |
frozen-lockfile 或 checksum 報錯:0 次流程重試;回到開發機重解後提交。 |
可複製命令與環境變數範例
以下假設倉庫根目錄同時存在 bun.lockb 與某子路徑的 package-lock.json;請依實際路徑改 cd。密文請用 CI 祕文注入,勿寫入 Git。
# —— 共用(遠端 Mac Runner shell)——
export NODE_ENV=ci
# npm 與多數工具鏈相容的 registry/重試
export NPM_CONFIG_REGISTRY="https://registry.npmjs.org/"
export npm_config_fetch_retries=3
export npm_config_fetch_retry_mintimeout=20000
export npm_config_fetch_retry_maxtimeout=120000
export npm_config_maxsockets=15
# Bun:限制同時 HTTP(跨境降 429)
export BUN_CONFIG_MAX_HTTP_REQUESTS=24
# —— 僅 Bun 工作區(範例)——
cd apps/bun-app
bun --version
bun install --frozen-lockfile
# —— 僅 npm lock 工作區(範例)——
cd ../legacy-npm-pkg
npm ci --ignore-scripts # 若需腳本再分階段開啟
# —— 可選:鏡像/私庫寫入一次性 .npmrc(示意)——
# printf '%s\n' "registry=https://你的鏡像/" "//npm.pkg.github.com/:_authToken=${GITHUB_PACKAGES_TOKEN}" >> .npmrc.ci
# NPM_CONFIG_USERCONFIG=$PWD/.npmrc.ci npm ci
bunfig.toml 可將 install.registry 指向鏡像並用 $NPM_TOKEN 占位;與 .npmrc 並存時,請在 staging Runner 上做一次「只改鏡像、不改依賴版本」的對照安裝,確認兩邊解析出的版本區間一致。
若使用雲端 CI 的快取服務,建議將指紋步驟與還原步驟分開命名,避免同一個 key 同時混用 Bun 全域快取目錄與 npm 的 ~/.npm 造成誤命中。本地或專用遠端 Mac 上,亦可掛載固定路徑(例如 /var/ci/bun-cache、/var/ci/npm-cache)並在每日維護窗口用時間戳子目錄滾動,降低壞快取與權限漂移風險。
混倉在遠端 Mac 上的落地順序
Apple Silicon 節點上,磁碟與 TLS 往往不是第一瓶頸,連線數 × RTT 才是。建議將安裝步驟排成「先凍結子專案 A → 產物或 node_modules 就位 → 再凍結子專案 B」,中間以目錄隔離或 workspace 邊界避免互相覆寫。若必須平行,請將 BUN_CONFIG_MAX_HTTP_REQUESTS 與 npm_config_maxsockets 的乘積視為出站壓力,並對照上一節矩陣逐步降階。
常見釐清
CI 能不能省略其中一份 lockfile?
可以,但要在 README/CODEOWNERS 寫清「哪個目錄歸誰維護」。省略的一方目錄不應再執行會改樹的安裝指令,以免 reviewer 無法從單一 diff 還原依賴圖。
鏡像加速後 frozen 安裝失敗,能只重試嗎?
若錯誤明確是 checksum/lock 不匹配,重試只會浪費分鐘數;應比對鏡像與上游的延遲同步策略,或在開發機用同一組 .npmrc/bunfig.toml 重解並提交 lock。
總結:2026 年在遠端 Mac CI 處理 Bun 與 npm 混倉,關鍵是「lockfile 真理單一化 per 目錄、鏡像端點雙邊一致、併發用環境變數顯式降階、快取鍵帶上工具版本與設定指紋、以及把網路重試與 lock 失敗分流」。若你需要長時間固定同一臺 Apple Silicon 校準上述閾值,可先瀏覽 macpull.com 繁中首頁 與免登入的 定價、說明中心。