前言
使用 Apple Silicon Mac 開發前端專案時,你有沒有遇過這種情況:npm install 明明成功了,但執行 npm run dev 時 Vite 卻突然翻臉不認人,噴出一堆關於 rollup.darwin-arm64.node 的錯誤?
更慘的是,macOS 還會彈出一個視窗說「無法打開 rollup.darwin-arm64.node,因為無法驗證開發者」——彷彿你的電腦在暗示你下載了什麼奇怪的東西。
別擔心,這不是你的問題(好吧,也不完全是 Apple 的問題),而是 npm + Gatekeeper 的經典組合技。本文將帶你徹底理解並解決這個惱人的問題。
問題現象
當你在 Apple Silicon Mac 上執行 Vite/Rollup 專案時,可能會遇到以下錯誤:
錯誤 1:模組找不到
Error: Cannot find module '@rollup/rollup-darwin-arm64'
Require stack:
- /project/node_modules/rollup/dist/native.js
錯誤 2:系統策略拒絕載入
Error: dlopen(/project/node_modules/@rollup/rollup-darwin-arm64/rollup.darwin-arm64.node, 0x0001):
code signature in (...) not valid for use in process: library load disallowed by system policy
錯誤 3:Gatekeeper 彈窗警告
macOS 直接彈出視窗:「無法打開 rollup.darwin-arm64.node,因為無法驗證開發者」
問題根源分析
這個問題其實是兩個獨立問題的組合:
原因 1:npm optionalDependencies Bug
Rollup 使用 optionalDependencies 來管理多平台的原生二進位檔:
@rollup/rollup-darwin-arm64(Apple Silicon Mac)@rollup/rollup-darwin-x64(Intel Mac)@rollup/rollup-linux-x64(Linux)@rollup/rollup-win32-x64-msvc(Windows)
但 npm 有個已知 Bug:在某些情況下會漏裝或裝錯平台版本的 optional dependency,導致模組找不到。
原因 2:macOS Gatekeeper 隔離機制
macOS 會對從網路下載的可執行檔打上 com.apple.quarantine 隔離標籤。當 Node.js 嘗試載入這些 .node 原生模組時,Gatekeeper 會介入檢查,如果無法驗證簽章就會阻擋。
有趣的是:npm 下載的檔案會被標記為「從網路下載」,即使它來自官方 registry。這就是為什麼明明是合法套件,macOS 還是會擋。
快速修復步驟
90% 的情況,以下四個步驟就能解決問題:
Step 1:刪除舊依賴與鎖檔
rm -rf node_modules package-lock.json
Step 2:重新安裝所有依賴
npm install
Step 3:清除 Gatekeeper 隔離標籤
xattr -dr com.apple.quarantine node_modules/@rollup/rollup-darwin-arm64/*.node
如果你不確定檔案在哪,可以用:
find node_modules -name "*.node" -exec xattr -dr com.apple.quarantine {} \;
Step 4:重建原生模組(可選)
npm rebuild rollup
執行完以上步驟,通常就能順利 npm run dev 了。
進階解決方案
如果快速修復無效,或你想要更長久的解決方案,以下是幾個選項:
方案 A:升級 npm
npm v9.x 以上對 optionalDependencies 的處理更穩定:
npm install -g npm@latest
npm --version # 確認版本 >= 9.x
方案 B:改用 Yarn 或 PNPM
這兩個套件管理器對 optionalDependencies 的支援更完整:
# 使用 PNPM(推薦)
npm install -g pnpm
pnpm install
# 或使用 Yarn
npm install -g yarn
yarn install
方案 C:強制使用 JavaScript Fallback
Rollup 有純 JavaScript 實作,雖然較慢但完全不需要原生模組:
# 單次執行
ROLLUP_IGNORE_NATIVE=1 npm run dev
# 或加入 .env 檔案
echo "ROLLUP_IGNORE_NATIVE=1" >> .env
方案 D:在 .npmrc 關閉 optionalDependencies
# .npmrc
optional=false
這會讓 npm 完全跳過所有 optional dependencies,Rollup 會自動退回 JS 實作。
方案 E:自動化清除 quarantine(團隊協作推薦)
在 package.json 加入 postinstall 腳本:
{
"scripts": {
"postinstall": "xattr -dr com.apple.quarantine node_modules/**/*.node 2>/dev/null || true"
}
}
這樣每次 npm install 後都會自動清除隔離標籤。
各方案比較
| 方案 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|
| 重新安裝 | 簡單快速 | 治標不治本 | 臨時解決 |
| 升級 npm | 根本解決 | 可能影響其他專案 | 個人開發 |
| 改用 PNPM | 效能更好、更穩定 | 需要團隊配合 | 新專案 |
| JS Fallback | 完全避開問題 | 打包速度較慢 | CI/CD 環境 |
| postinstall | 自動化 | 只對 Mac 有效 | 團隊協作 |
預防措施
在專案 README 記錄
## macOS Apple Silicon 用戶注意
如果遇到 Rollup 相關錯誤,請執行:
\`\`\`bash
rm -rf node_modules package-lock.json
npm install
xattr -dr com.apple.quarantine node_modules/**/*.node
\`\`\`
在 CI/CD 中使用環境變數
# .gitlab-ci.yml 或 GitHub Actions
env:
ROLLUP_IGNORE_NATIVE: 1
結論
macOS Gatekeeper + npm optionalDependencies Bug 是 Apple Silicon Mac 開發者的常見痛點。好消息是,這個問題有明確的解決方案:
TL;DR 快速解法:
rm -rf node_modules package-lock.json && npm install && xattr -dr com.apple.quarantine node_modules/**/*.node
長期解法:
- 改用 PNPM 作為套件管理器
- 或在
package.json加入 postinstall 自動清除腳本
希望這篇文章能幫你省下幾小時的 debug 時間。畢竟人生苦短,不該浪費在跟 Gatekeeper 吵架上。
