【Bun 全面教學】#04 實戰應用:從 Node.js 專案遷移到 Bun

測驗:從 Node.js 專案遷移到 Bun

共 5 題,點選答案後會立即顯示結果

1. 將 Node.js 專案遷移到 Bun 的第一步驟是什麼?

  • A. 修改 package.json 的 scripts
  • B. 刪除 node_modules 和舊的 lock file
  • C. 執行 bun install
  • D. 修改 Dockerfile

2. 在 Bun 中取得目前檔案的目錄路徑,應該使用什麼語法?

  • A. __dirname(直接使用)
  • B. process.cwd()
  • C. import.meta.dir
  • D. Bun.dirname

3. 當遷移後遇到 native module 載入錯誤時,以下哪個是正確的處理方式?

  • A. 降級 Bun 版本
  • B. 尋找純 JavaScript 實作的替代套件
  • C. 修改 package.json 的 engines 欄位
  • D. 直接忽略錯誤繼續運行

4. 在 Docker 中部署 Bun 應用,Dockerfile 的 FROM 指令應該使用哪個映像檔?

FROM ??? AS base WORKDIR /app
  • A. oven/bun:1
  • B. node:18
  • C. bun/official:latest
  • D. alpine/bun:1

5. 根據漸進式遷移策略,以下哪個是正確的遷移順序?

  • A. 全面切換 → 測試環境 → 開發環境
  • B. 生產環境 → 開發環境 → 測試環境
  • C. 開發環境 → 測試環境 → 灰度發布 → 全面切換
  • D. 灰度發布 → 開發環境 → 測試環境 → 全面切換

一句話說明

把現有的 Node.js 專案「搬家」到 Bun,享受更快的速度,同時處理可能遇到的相容性問題。

為什麼要遷移?

先問自己:遷移能帶來什麼好處?

情境 遷移效益
專案啟動時間太長 Bun 冷啟動快 5-10 倍
npm install 等很久 bun install 快 10-20 倍
想用 TypeScript 但不想設定 Bun 原生支援,零設定
專案大量使用 native modules 可能不適合遷移

遷移前評估:相容性檢查清單

在動手之前,先檢查這些項目:

# 第一步:查看你的 dependencies
cat package.json | grep -A 100 '"dependencies"'
Code language: PHP (php)

必看懂:高相容套件(可以放心遷移)

Express / Fastify / Hono     # Web 框架
Prisma / Drizzle             # 資料庫 ORM
Zod / Yup                    # 驗證
Lodash / Date-fns            # 工具函式
Axios / node-fetch           # HTTP 請求
Code language: PHP (php)

需要注意:可能有問題的套件

bcrypt / argon2              # 有 native bindings
sharp                        # 圖片處理,需用 bun 版本
node-gyp 相關套件            # C++ 編譯的都要小心
Code language: PHP (php)

快速檢查指令

# 檢查是否有 native modules
grep -r "node-gyp\|prebuild\|node-pre-gyp" node_modules/*/package.json

# 檢查 engines 欄位
cat package.json | grep -A 5 '"engines"'
Code language: PHP (php)

實際遷移步驟

步驟 1:安裝 Bun

# macOS / Linux
curl -fsSL https://bun.sh/install | bash

# Windows(需要 WSL)
# 在 WSL 中執行上面的指令

# 確認安裝成功
bun --version
Code language: PHP (php)

步驟 2:刪除舊的 node_modules 和 lock file

# 刪除舊的依賴
rm -rf node_modules
rm package-lock.json    # npm 的 lock file
rm yarn.lock            # yarn 的 lock file
rm pnpm-lock.yaml       # pnpm 的 lock file
Code language: PHP (php)

步驟 3:用 Bun 重新安裝

# Bun 會讀取 package.json,重新安裝所有依賴
bun install
Code language: CSS (css)

執行後你會看到:

bun install v1.0.0

 + express@4.18.2
 + typescript@5.0.0
 + ... 其他套件

 156 packages installed [524ms]
#                        ↑ 注意這個速度
Code language: CSS (css)

步驟 4:修改 package.json 的 scripts

修改前(Node.js):

{
  "scripts": {
    "dev": "ts-node src/index.ts",
    "start": "node dist/index.js",
    "build": "tsc",
    "test": "jest"
  }
}
Code language: JSON / JSON with Comments (json)

修改後(Bun):

{
  "scripts": {
    "dev": "bun run --watch src/index.ts",
    "start": "bun run src/index.ts",
    "build": "bun build src/index.ts --outdir dist",
    "test": "bun test"
  }
}
Code language: JSON / JSON with Comments (json)

逐行解釋變化

"dev": "bun run --watch src/index.ts"
#       ↑ 用 bun 執行
#              ↑ --watch 檔案變更自動重啟
#                    ↑ 直接跑 TypeScript,不需要 ts-node

"start": "bun run src/index.ts"
#        ↑ 生產環境也可以直接跑 .ts 檔

"test": "bun test"
#       ↑ Bun 內建測試框架,不需要 Jest
Code language: PHP (php)

步驟 5:測試是否正常運作

# 跑跑看開發模式
bun run dev

# 跑測試
bun test

# 如果有問題,看錯誤訊息
Code language: PHP (php)

常見問題處理

問題 1:找不到模組

error: Cannot find module 'some-package'
Code language: JavaScript (javascript)

解法:

# 重新安裝該套件
bun add some-package

# 如果還是不行,可能是 Node.js 專用模組
# 試試看安裝 polyfill
bun add @aspect-build/bazel-lib
Code language: PHP (php)

問題 2:Native module 錯誤

error: dyld: Library not loaded...
# 或
error: Cannot load native module
Code language: PHP (php)

解法:

# 方法 1:找 Bun 相容的替代套件
# 例如 bcrypt → bcryptjs(純 JS 實作)
bun remove bcrypt
bun add bcryptjs

# 方法 2:讓 Bun 重新編譯
bun add sharp --rebuild
Code language: PHP (php)

問題 3:環境變數讀不到

// Node.js 寫法(在 Bun 也能用)
const port = process.env.PORT

// Bun 專屬寫法(更推薦)
const port = Bun.env.PORT
Code language: JavaScript (javascript)

兩種都可以用,但 Bun.env 有更好的 TypeScript 型別支援。

問題 4:__dirname 和 __filename

// Node.js ESM 寫法
import { fileURLToPath } from 'url'
import { dirname } from 'path'
const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)

// Bun 寫法(簡單很多)
const __dirname = import.meta.dir
const __filename = import.meta.file
Code language: JavaScript (javascript)

問題 5:測試框架不相容

// Jest 語法(部分相容,但建議改用 Bun 內建)
describe('math', () => {
  it('adds numbers', () => {
    expect(1 + 1).toBe(2)
  })
})

// Bun 內建測試(語法幾乎一樣)
import { describe, it, expect } from 'bun:test'

describe('math', () => {
  it('adds numbers', () => {
    expect(1 + 1).toBe(2)
  })
})
Code language: PHP (php)

差別只在 import 來源,語法完全相容。

漸進式遷移策略

不確定要不要全面遷移?用這個策略:

階段 1:開發環境先試

# 只在本機用 Bun
bun install
bun run dev

# CI/CD 和生產環境還是用 Node.js
# 這樣出問題可以隨時退回去
Code language: PHP (php)

階段 2:測試環境試跑

# 在測試環境部署 Bun 版本
# 觀察是否有問題
# 壓力測試比較效能
Code language: PHP (php)

階段 3:灰度發布

# 只讓一部分流量走 Bun 版本
# 例如 10% 流量
Code language: PHP (php)

階段 4:全面切換

確認沒問題後,再全面使用 Bun。

生產環境部署

Docker 部署

# Dockerfile
FROM oven/bun:1 AS base
WORKDIR /app

# 安裝依賴
FROM base AS install
COPY package.json bun.lockb ./
RUN bun install --frozen-lockfile

# 複製原始碼並啟動
FROM base AS release
COPY --from=install /app/node_modules node_modules
COPY . .

EXPOSE 3000
CMD ["bun", "run", "src/index.ts"]
Code language: PHP (php)

逐行解釋 Dockerfile

FROM oven/bun:1 AS base
#    ↑ 使用官方 Bun 映像檔
#                ↑ AS base 是多階段建構的命名

RUN bun install --frozen-lockfile
#               ↑ 確保使用 lock file 的精確版本

CMD ["bun", "run", "src/index.ts"]
#   ↑ 容器啟動時執行這個指令
Code language: PHP (php)

Fly.io 部署

# 建立 fly.toml
fly launch

# 部署
fly deploy
Code language: PHP (php)

fly.toml 範例:

[build]
  dockerfile = "Dockerfile"

[http_service]
  internal_port = 3000
  force_https = true

[env]
  NODE_ENV = "production"
Code language: JavaScript (javascript)

Railway 部署

Railway 自動偵測 Bun 專案,只需要:

# 確保有 bun.lockb 檔案
bun install

# 推送到 GitHub,Railway 會自動部署
git push
Code language: PHP (php)

何時該遷移?

適合遷移的情況

  • 新專案或小型專案
  • 主要是 API server 或工具腳本
  • 想要更快的開發體驗
  • 團隊願意學習新工具

不適合遷移的情況

  • 大型單體應用,風險太高
  • 大量使用 native modules
  • 團隊沒有時間學習
  • 穩定運行中,沒有效能問題

遷移決策流程圖

專案有效能問題嗎?
├─ 沒有 → 維持 Node.js,不用遷移
└─ 有 →
    套件都相容嗎?
    ├─ 不確定 → 先在開發環境試用
    └─ 相容 →
        團隊有時間學習嗎?
        ├─ 沒有 → 維持 Node.js
        └─ 有 → 開始遷移
Code language: CSS (css)

Vibe Coder 檢查點

當你看到「Node.js 遷移到 Bun」的相關程式碼時,確認這些:

遷移前

# 有沒有 lock file?
ls bun.lockb           # Bun 的 lock file

# package.json 的 scripts 改了嗎?
cat package.json | grep -A 10 '"scripts"'
Code language: PHP (php)

遷移後

# 能正常啟動嗎?
bun run dev

# 測試有過嗎?
bun test
Code language: PHP (php)

部署時

# Dockerfile 用的是 Bun 映像檔嗎?
FROM oven/bun:1   # 對
FROM node:18      # 錯,這還是 Node.js
Code language: PHP (php)

完整遷移範例

假設有一個 Express 專案:

my-express-app/
├── package.json
├── package-lock.json
├── src/
│   └── index.ts
└── tests/
    └── app.test.ts

遷移前

// package.json
{
  "scripts": {
    "dev": "ts-node-dev src/index.ts",
    "test": "jest"
  },
  "dependencies": {
    "express": "^4.18.0"
  },
  "devDependencies": {
    "typescript": "^5.0.0",
    "ts-node-dev": "^2.0.0",
    "jest": "^29.0.0",
    "@types/express": "^4.17.0"
  }
}
Code language: JSON / JSON with Comments (json)

遷移指令

# 1. 刪除舊的
rm -rf node_modules package-lock.json

# 2. 用 Bun 安裝
bun install

# 3. 移除不需要的 devDependencies
bun remove ts-node-dev jest ts-jest @types/jest
Code language: PHP (php)

遷移後

// package.json
{
  "scripts": {
    "dev": "bun run --watch src/index.ts",
    "test": "bun test"
  },
  "dependencies": {
    "express": "^4.18.0"
  },
  "devDependencies": {
    "typescript": "^5.0.0",
    "@types/express": "^4.17.0"
  }
}
Code language: JSON / JSON with Comments (json)

測試檔案調整

// tests/app.test.ts
// 只需要改 import
import { describe, it, expect } from 'bun:test'

describe('GET /', () => {
  it('returns hello', async () => {
    const res = await fetch('http://localhost:3000/')
    expect(res.status).toBe(200)
  })
})
Code language: JavaScript (javascript)

對 Vibe Coding 的幫助

學會這些遷移概念後,你可以:

  • 更精準地下指令:當你請 AI 幫忙建立新專案時,可以明確指定「用 Bun 而非 Node.js」,並告訴 AI 專案是否有 native modules 的限制,讓 AI 選擇正確的套件
  • 更有效地 Review AI 產出:看到 AI 生成的 package.json,能快速判斷 scripts 是否正確使用 bun run 而非 node,Dockerfile 是否使用 oven/bun 映像檔
  • 更快速地除錯:遇到 Cannot find moduleCannot load native module 錯誤時,知道這是遷移常見問題,能用本文的解法快速處理,而非讓 AI 反覆嘗試錯誤方向

本篇重點回顧

遷移評估:
├─ 檢查 dependencies 相容性
├─ 識別 native modules
└─ 評估團隊準備度

遷移步驟:
├─ 刪除 node_modules 和舊 lock file
├─ bun install 重新安裝
├─ 修改 package.json scripts
└─ 測試是否正常

常見問題:
├─ native modules → 找純 JS 替代
├─ 環境變數 → Bun.env
├─ __dirname → import.meta.dir
└─ Jest → bun:test

部署方式:
├─ Docker (oven/bun:1)
├─ Fly.io
└─ Railway
Code language: JavaScript (javascript)

系列總結

恭喜完成【Bun 全面教學】系列!

回顧這四篇學到的:

篇章 主題 你學會了
#01 快速入門 安裝、基本指令
#02 內建功能 檔案操作、HTTP、SQLite
#03 套件管理 bun install、workspace
#04 實戰遷移 Node.js → Bun 完整流程

現在你已經具備:

  • 閱讀 Bun 專案程式碼的能力
  • 評估是否該用 Bun 的判斷力
  • 必要時遷移專案的實戰技能

下一步建議:挑一個小型的個人專案,實際用 Bun 跑跑看!

進階測驗:從 Node.js 專案遷移到 Bun

測驗目標:驗證你是否能在實際情境中應用所學。
共 5 題,包含情境題與錯誤診斷題。

1. 你接手一個 Node.js 專案,想評估是否適合遷移到 Bun。你發現 package.json 中有以下依賴,哪個可能造成遷移困難? 情境題

{ “dependencies”: { “express”: “^4.18.0”, “prisma”: “^5.0.0”, “bcrypt”: “^5.1.0”, “zod”: “^3.22.0” } }
  • A. express – 因為是舊版框架
  • B. prisma – 因為是資料庫 ORM
  • C. bcrypt – 因為有 native bindings
  • D. zod – 因為使用 TypeScript

2. 你的團隊想嘗試 Bun,但對穩定性有疑慮。最適合的做法是什麼? 情境題

  • A. 直接在生產環境部署,觀察問題再處理
  • B. 先在開發環境使用,CI/CD 和生產環境維持 Node.js
  • C. 等 Bun 2.0 穩定版再評估
  • D. 建一個全新專案來測試,不動現有專案

3. 你要將已遷移到 Bun 的專案部署到 Docker。以下哪個 Dockerfile 設定是正確的? 情境題

# 選項 A FROM node:18 AS base RUN npm install -g bun # 選項 B FROM oven/bun:1 AS base RUN bun install –frozen-lockfile # 選項 C FROM alpine:latest AS base RUN apk add bun # 選項 D FROM ubuntu:22.04 AS base RUN curl -fsSL https://bun.sh/install | bash
  • A. 選項 A – 在 Node 基礎上安裝 Bun
  • B. 選項 B – 使用官方 Bun 映像檔
  • C. 選項 C – 使用 Alpine 的 apk 安裝
  • D. 選項 D – 從 Ubuntu 手動安裝

4. 小明遷移專案到 Bun 後,執行 bun run dev 出現以下錯誤。最可能的原因是什麼? 錯誤診斷

$ bun run dev error: Cannot load native module ‘bcrypt’ at node_modules/bcrypt/bcrypt.js:6:16
  • A. bcrypt 套件版本太舊,需要升級
  • B. 沒有執行 bun install 安裝依賴
  • C. bcrypt 是 native module,需換成純 JS 的 bcryptjs
  • D. Bun 不支援任何密碼雜湊套件

5. 小華將 Node.js 專案遷移到 Bun,但執行測試時所有 Jest 測試都失敗了。她的 package.json 如下,問題出在哪裡? 錯誤診斷

// package.json { “scripts”: { “test”: “bun test” } } // tests/math.test.ts describe(‘math’, () => { it(‘adds numbers’, () => { expect(1 + 1).toBe(2) }) })
  • A. bun test 不支援 TypeScript 測試檔案
  • B. 測試檔案需要加入 import { describe, it, expect } from 'bun:test'
  • C. 需要安裝 @types/bun 才能執行測試
  • D. 測試檔案必須放在 __tests__ 目錄下

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *