測驗:Bun 進階功能
共 5 題,點選答案後會立即顯示結果
1. 在 Bun 中要使用內建測試框架,應該從哪裡引入 test 和 expect?
2. 以下是一個 Bun HTTP 伺服器的程式碼,其中 fetch 函式的作用是什麼?
Bun.serve({
port: 3000,
fetch(request) {
return new Response(“Hello!”);
},
});
3. 使用 bun build 打包時,如果目標是在瀏覽器中執行,應該使用哪個參數?
4. 關於 Bun 的檔案操作 API,以下敘述何者正確?
const file = Bun.file(“./data.txt”);
const content = await file.text();
5. 在 Bun 中使用內建的 SQLite 支援,應該如何引入 Database 類別?
一句話說明
Bun 不只是套件管理器,它內建了測試框架、打包工具和 HTTP 伺服器,讓你不用安裝一堆額外套件就能完成完整的開發流程。
為什麼要學這些?
當 AI 幫你產生專案時,你可能會看到:
// 測試檔案裡
import { expect, test } from "bun:test";
// 伺服器程式裡
Bun.serve({ port: 3000, fetch(req) { ... } });
// 打包指令
// bun build ./src/index.ts --outdir ./dist
Code language: JavaScript (javascript)這篇教你看懂這些 Bun 特有的寫法,以及它們跟你熟悉的工具有什麼不同。
一、bun test:內建測試框架
最小範例
// math.test.ts
import { expect, test } from "bun:test";
test("1 加 1 等於 2", () => {
expect(1 + 1).toBe(2);
});
Code language: JavaScript (javascript)執行測試:
bun test
逐行翻譯
import { expect, test } from "bun:test";
// ↑ 從 Bun 內建的測試模組引入 expect 和 test
// 注意是 "bun:test",不是安裝的套件
test("1 加 1 等於 2", () => {
// ↑ 定義一個測試案例,第一個參數是描述文字
expect(1 + 1).toBe(2);
// ↑ 斷言:預期 1+1 的結果要等於 2
});
Code language: JavaScript (javascript)常見變化
1. 群組測試(describe)
import { expect, test, describe } from "bun:test";
describe("數學運算", () => {
// ↑ 把相關測試群組在一起
test("加法", () => {
expect(2 + 3).toBe(5);
});
test("減法", () => {
expect(5 - 3).toBe(2);
});
});
Code language: PHP (php)2. 前置/後置處理
import { expect, test, beforeEach, afterEach } from "bun:test";
let counter = 0;
beforeEach(() => {
// ↑ 每個測試執行「之前」會跑這段
counter = 0;
});
afterEach(() => {
// ↑ 每個測試執行「之後」會跑這段
console.log("測試完成");
});
test("計數器從 0 開始", () => {
expect(counter).toBe(0);
});
Code language: JavaScript (javascript)3. 非同步測試
import { expect, test } from "bun:test";
test("非同步操作", async () => {
// ↑ 加上 async,裡面就能用 await
const response = await fetch("https://api.example.com/data");
expect(response.ok).toBe(true);
});
Code language: JavaScript (javascript)與 Jest 的對照
| Jest 寫法 | Bun 寫法 | 差異 |
|---|---|---|
import { test } from '@jest/globals' |
import { test } from "bun:test" |
來源不同 |
jest.fn() |
mock() |
Mock 函式名稱不同 |
jest.spyOn() |
spyOn() |
直接引入使用 |
大部分 Jest 語法都能直接用,只有 import 來源和部分 mock 相關 API 不同。
Vibe Coder 檢查點
看到 bun:test 時要確認:
- [ ] 測試檔案命名是否符合規則(
.test.ts或.spec.ts) - [ ] expect 的斷言邏輯是否正確
- [ ] 非同步測試有沒有加 async/await
二、bun build:打包工具
最小範例
bun build ./src/index.ts --outdir ./dist
這會把 src/index.ts(包含它引用的所有模組)打包成一個檔案,輸出到 dist 資料夾。
常見指令解釋
bun build ./src/index.ts --outdir ./dist
# ↑ 入口檔案 ↑ 輸出目錄
bun build ./src/index.ts --outfile ./bundle.js
# ↑ 指定輸出的單一檔案名稱
bun build ./src/index.ts --minify
# ↑ 壓縮程式碼(移除空白、縮短變數名)
bun build ./src/index.ts --target browser
# ↑ 目標環境:browser(瀏覽器)或 bun(伺服器)
bun build ./src/index.ts --splitting
# ↑ 啟用 code splitting(拆分共用模組)
Code language: PHP (php)用程式呼叫打包
// build.ts
const result = await Bun.build({
entrypoints: ["./src/index.ts"],
// ↑ 入口檔案,可以有多個
outdir: "./dist",
// ↑ 輸出目錄
minify: true,
// ↑ 是否壓縮
target: "browser",
// ↑ 目標環境
});
if (!result.success) {
console.error("打包失敗:", result.logs);
}
Code language: JavaScript (javascript)與 Webpack/Vite 的對照
| 功能 | Webpack | Vite | Bun |
|---|---|---|---|
| 設定檔 | webpack.config.js(複雜) | vite.config.ts | 不需要或很簡單 |
| TypeScript | 需要 ts-loader | 內建 | 內建 |
| 速度 | 較慢 | 快 | 非常快 |
| Tree Shaking | 需設定 | 內建 | 內建 |
Vibe Coder 檢查點
看到 bun build 時要確認:
- [ ] 入口檔案路徑是否正確
- [ ] 輸出目錄是否符合專案結構
- [ ] target 是 browser 還是 bun(影響可用的 API)
三、Bun.serve():HTTP 伺服器
最小範例
// server.ts
Bun.serve({
port: 3000,
fetch(request) {
return new Response("Hello!");
},
});
console.log("伺服器啟動於 http://localhost:3000");
Code language: JavaScript (javascript)執行:
bun run server.ts
Code language: CSS (css)逐行翻譯
Bun.serve({
// ↑ 啟動一個 HTTP 伺服器
port: 3000,
// ↑ 監聽 3000 埠
fetch(request) {
// ↑ 每當收到請求時,執行這個函式
// request 包含請求的所有資訊
return new Response("Hello!");
// ↑ 回傳一個 Response 物件給客戶端
},
});
Code language: JavaScript (javascript)常見變化
1. 處理不同路由
Bun.serve({
port: 3000,
fetch(request) {
const url = new URL(request.url);
// ↑ 解析請求的 URL
if (url.pathname === "/") {
return new Response("首頁");
}
if (url.pathname === "/api/users") {
return Response.json({ users: [] });
// ↑ 回傳 JSON 格式
}
return new Response("Not Found", { status: 404 });
// ↑ 找不到路由時回傳 404
},
});
Code language: JavaScript (javascript)2. 處理 POST 請求
Bun.serve({
port: 3000,
async fetch(request) {
// ↑ 加 async 因為要 await 讀取 body
if (request.method === "POST") {
const body = await request.json();
// ↑ 解析 JSON 格式的請求內容
console.log("收到資料:", body);
return Response.json({ received: true });
}
return new Response("Send a POST request");
},
});
Code language: JavaScript (javascript)3. 提供靜態檔案
Bun.serve({
port: 3000,
async fetch(request) {
const url = new URL(request.url);
const filePath = `./public${url.pathname}`;
// ↑ 將 URL 路徑對應到 public 資料夾
const file = Bun.file(filePath);
// ↑ Bun.file() 取得檔案參照
if (await file.exists()) {
return new Response(file);
// ↑ 直接回傳檔案
}
return new Response("Not Found", { status: 404 });
},
});
Code language: JavaScript (javascript)與 Express 的對照
// Express 寫法
import express from "express";
const app = express();
app.get("/", (req, res) => {
res.send("Hello!");
});
app.listen(3000);
Code language: JavaScript (javascript)// Bun.serve 寫法
Bun.serve({
port: 3000,
fetch(request) {
const url = new URL(request.url);
if (url.pathname === "/" && request.method === "GET") {
return new Response("Hello!");
}
return new Response("Not Found", { status: 404 });
},
});
Code language: JavaScript (javascript)| 特性 | Express | Bun.serve |
|---|---|---|
| 路由系統 | 內建完整路由 | 需自己判斷或用框架 |
| 中介軟體 | 豐富生態系 | 需自己實作或用框架 |
| 效能 | 普通 | 非常高 |
| 學習曲線 | 較平緩 | 需理解 Web API 標準 |
Vibe Coder 檢查點
看到 Bun.serve 時要確認:
- [ ] port 有沒有跟其他服務衝突
- [ ] fetch 函式有沒有處理所有可能的路由
- [ ] 錯誤情況有沒有回傳適當的狀態碼
四、其他實用內建 API
Bun.file():檔案操作
// 讀取檔案
const file = Bun.file("./data.txt");
const text = await file.text();
// ↑ 讀取為文字
const json = await Bun.file("./config.json").json();
// ↑ 直接解析為 JSON
// 寫入檔案
await Bun.write("./output.txt", "Hello, Bun!");
// ↑ 寫入文字到檔案
await Bun.write("./data.json", JSON.stringify({ name: "Bun" }));
// ↑ 寫入 JSON
Code language: JavaScript (javascript)逐行翻譯
const file = Bun.file("./data.txt");
// ↑ 取得檔案的參照(還沒真的讀取)
console.log(file.size); // 檔案大小(bytes)
console.log(file.type); // MIME 類型,如 "text/plain"
console.log(await file.exists()); // 檔案是否存在
const content = await file.text();
// ↑ 這時才真的讀取內容
Code language: JavaScript (javascript)bun:sqlite:內建 SQLite
import { Database } from "bun:sqlite";
// ↑ 從 Bun 內建模組引入
const db = new Database("mydb.sqlite");
// ↑ 開啟(或建立)資料庫檔案
// 建立資料表
db.run(`
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL
)
`);
// 插入資料
db.run("INSERT INTO users (name) VALUES (?)", ["Alice"]);
// ↑ ? 是參數佔位符,防止 SQL injection
// 查詢資料
const users = db.query("SELECT * FROM users").all();
// ↑ .all() 取得所有結果
console.log(users); // [{ id: 1, name: "Alice" }]
// 查詢單筆
const user = db.query("SELECT * FROM users WHERE id = ?").get(1);
// ↑ .get() 取得單筆結果
Code language: JavaScript (javascript)常見 API 快速對照表
| 需求 | Node.js | Bun |
|---|---|---|
| 讀檔案 | fs.readFileSync() |
await Bun.file().text() |
| 寫檔案 | fs.writeFileSync() |
await Bun.write() |
| HTTP 伺服器 | http.createServer() 或 Express |
Bun.serve() |
| SQLite | 需安裝 better-sqlite3 | 內建 bun:sqlite |
| 執行測試 | 需安裝 Jest/Vitest | 內建 bun test |
| 打包 | 需安裝 Webpack/Vite | 內建 bun build |
五、實戰:用 Bun 建立完整 API
把上面學到的組合起來:
// api.ts
import { Database } from "bun:sqlite";
// 初始化資料庫
const db = new Database("todos.sqlite");
db.run(`
CREATE TABLE IF NOT EXISTS todos (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
done INTEGER DEFAULT 0
)
`);
// 啟動伺服器
Bun.serve({
port: 3000,
async fetch(request) {
const url = new URL(request.url);
// GET /todos - 取得所有待辦事項
if (url.pathname === "/todos" && request.method === "GET") {
const todos = db.query("SELECT * FROM todos").all();
return Response.json(todos);
}
// POST /todos - 新增待辦事項
if (url.pathname === "/todos" && request.method === "POST") {
const { title } = await request.json();
db.run("INSERT INTO todos (title) VALUES (?)", [title]);
return Response.json({ success: true });
}
return new Response("Not Found", { status: 404 });
},
});
console.log("API 伺服器啟動於 http://localhost:3000");
Code language: JavaScript (javascript)測試 API:
# 新增待辦事項
curl -X POST http://localhost:3000/todos \
-H "Content-Type: application/json" \
-d '{"title": "學習 Bun"}'
# 取得所有待辦事項
curl http://localhost:3000/todos
Code language: PHP (php)六、必看懂 vs 知道就好
必看懂(常常會出現)
import { ... } from "bun:test"– 測試相關引入Bun.serve({ fetch() {} })– HTTP 伺服器基本結構Bun.file()/Bun.write()– 檔案讀寫new Response()/Response.json()– HTTP 回應
知道就好(遇到再查)
Bun.spawn()– 執行子程序Bun.Transpiler– 程式碼轉譯 APIBun.password– 密碼雜湊工具Bun.CryptoHasher– 雜湊運算- WebSocket 支援的詳細設定
總結
這篇介紹了 Bun 的三大內建功能:
| 功能 | 指令/API | 取代什麼 |
|---|---|---|
| 測試 | bun test |
Jest, Vitest |
| 打包 | bun build |
Webpack, Vite, esbuild |
| HTTP 伺服器 | Bun.serve() |
Express, Fastify |
加上其他實用 API:
Bun.file()/Bun.write()取代 Node.js 的 fs 模組bun:sqlite取代 better-sqlite3
Bun 的設計哲學是「All-in-One」,讓你用更少的套件完成更多事情。當 AI 產生的程式碼使用這些 Bun 特有的 API 時,你現在應該能看懂它們在做什麼了。
下一篇預告
下一篇是本系列最後一篇,我們會介紹 Bun 與現有生態系的整合,包括如何在 Bun 專案中使用 React、Next.js 等框架,以及遷移現有專案的注意事項。
進階測驗:Bun 進階功能
測驗目標:驗證你是否能在實際情境中應用所學。
共 5 題,包含情境題與錯誤診斷題。
共 5 題,包含情境題與錯誤診斷題。
1. 你正在開發一個待辦事項 API,需要同時使用資料庫和 HTTP 伺服器。以下哪種做法最適合 Bun 專案? 情境題
2. 你需要為前端 React 專案打包 TypeScript 程式碼,並且希望輸出的檔案盡可能小。應該使用哪個指令? 情境題
3. 你的 HTTP 伺服器需要根據 URL 路徑回傳不同內容:首頁回傳 HTML,/api/data 回傳 JSON,其他路徑回傳 404。以下哪個實作最正確? 情境題
Bun.serve({
port: 3000,
fetch(request) {
const url = new URL(request.url);
// 這裡要填入什麼?
},
});
4. 小明寫了一個測試但執行 bun test 後沒有任何輸出,測試似乎沒有被執行。請問最可能的原因是什麼? 錯誤診斷
// calculator.ts
import { expect, test } from “bun:test”;
test(“加法測試”, () => {
expect(2 + 2).toBe(4);
});
5. 以下程式碼嘗試讀取 JSON 檔案,但執行時發生錯誤。請問問題出在哪裡? 錯誤診斷
const file = Bun.file(“./config.json”);
const config = file.json();
console.log(config.name);