4.3 Wrangler CLI:本地開發、測試與部署流程#
本節目標#
- 安裝並設定 wrangler,理解它作為 Workers 生态圈的瑞士刀的角色
- 掌握
wrangler dev、wrangler deploy/publish的日常流程,以及本地模擬的兩種模式 - 用 Vitest 對 Worker 做單元與整合測試
- 理解
wrangler deploy上傳前的 bundle 過程,以及它對程式碼寫法的約束
安裝與登入#
wrangler 是 Cloudflare 官方 CLI:
$ npm install --save-dev wrangler
$ npx wrangler login # 開瀏覽器 OAuth 授權
$ npx wrangler whoami # 驗證是否成功
典型專案結構:
my-worker/
├── src/index.ts
├── test/index.spec.ts
├── wrangler.toml
├── package.json
└── vitest.config.ts
建議在
package.json加上"dev": "wrangler dev"、"test": "vitest run"、"deploy": "wrangler deploy"三個捷徑。
wrangler dev:本地的兩種模式#
$ npx wrangler dev # 預設監聽 localhost:8787
本地模擬有兩種模式:
| 模式 | 作法 | 保真度 | 速度 |
|---|---|---|---|
| 本地(local) | workerd(Cloudflare 開源的 C++ Workers runtime)真正執行 | 高:與線上行為同源 | 快 |
| 遠端(remote) | 把程式碼丟到真實的邊緣節點執行 | 最高(含 KV/D1 真實資料) | 慢、需網路 |
$ npx wrangler dev --remote # 用真實 KV/D1 測試
日常以 local 模式迭代:KV/D1 在本地由 wrangler 以 SQLite 檔模擬(.wrangler/state),可隨時清除。
configuration 的載入規則#
組態優先序:
\[ \text{CLI flags} > \text{env.XXX 區塊} > \text{頂層欄位} \]
——flag 永遠最後說話:CI 用 flag 覆寫,本地用 toml 為主。
測試:Vitest + miniflare#
Cloudflare 官方維護 @cloudflare/vitest-pool-workers,讓測試直接跑在真實的 workerd 裡(而非 jsdom 模擬),因此 Request、Response、KV、D1 都是真的:
// vitest.config.ts
import { defineWorkersConfig } from "@cloudflare/vitest-pool-workers/config";
export default defineWorkersConfig({
test: {
poolOptions: {
workers: { wrangler: { configPath: "./wrangler.toml" } },
},
},
});
// test/index.spec.ts
import { SELF } from "cloudflare:test";
import { describe, expect, it } from "vitest";
describe("GET /hello", () => {
it("returns greeting", async () => {
const res = await SELF.fetch("https://example.com/hello");
expect(res.status).toBe(200);
expect(await res.text()).toMatch(/Hello/);
});
it("404 on unknown path", async () => {
const res = await SELF.fetch("https://example.com/nope");
expect(res.status).toBe(404);
});
});
SELF 是一個「把自己 fetch 回自己」的入口——測試腳本像真正的客戶端那樣發請求,但整個過程都在同一個 workerd 裡。若要驗證 env 的注入,可直接拿 env:
import { env } from "cloudflare:test";
it("uses binding", async () => {
expect(env.NAME).toBeDefined();
});
測試金字塔:
\[ \text{單元(純函式)} \subseteq \text{整合(SELF.fetch)} \subseteq \text{端對端(CI)} \]
部署:wrangler deploy 與 bundle#
$ npx wrangler deploy # 舊名:npx wrangler publish(別名仍可用)
$ npx wrangler deployments list # 檢視歷史版本
$ npx wrangler rollback [id] # 一鍵回滾到上一版
上傳前的 bundle:發生了什麼#
wrangler 內建 esbuild,把你的 TypeScript/多檔案專案打成單一 JS 模組:
src/index.ts ──┐
src/routes.ts ─┼── esbuild ──▶ dist/worker.js(單檔 bundle)──▶ 上傳至邊緣
node_modules ──┘
三個乘載而來的約束:
- 動態
await import("x")通常被 inline,部分情境不支援。 - Node API 有限:
fs、net不存在、process.env是 undefined;可開compatibility_flags = ["nodejs_compat"]獲得node:*相容層。 - 不含二進位:native 套件(含
.node)無法上傳;WASM 是唯一例外。
選依賴的心法:純 JS > 有 WASM > 帶 native——這也解釋了 Hono 這類零依賴框架在邊緣生態的受歡迎。
小結與練習#
- wrangler 的三位一體:
dev(本地迭代)、deploy(發佈)、rollback(回滾)。 - local 模式跑在真實的 workerd 上,組態優先序是 flag > env 區塊 > 頂層。
- 測試用
@cloudflare/vitest-pool-workers,SELF.fetch是整合測試的主要武器。 - deploy 前的 bundle 决定了你對依賴的選擇:純 JS、有限動態 import、無 native 模組。
練習:
- 用
npx wrangler dev --remote綁定一個真 KV namespace,與 local 模式的行為做對照,寫下兩點差異。 - 把
next或express塞進一個試著 deploy 的專案,觀察 bundle 報錯,體會邊緣運行時的約束。 - 為 4.2 的
/todosAPI 補一組 Vitest 測試,覆蓋 GET、POST、404 三種情況,在 CI (GitHub Actions) 上跑通。