跳轉到

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 ──┘

三個乘載而來的約束:

  1. 動態 await import("x") 通常被 inline,部分情境不支援。
  2. Node API 有限:fs、net 不存在、process.env 是 undefined;可開 compatibility_flags = ["nodejs_compat"] 獲得 node:* 相容層。
  3. 不含二進位: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 模組。

練習:

  1. 用 npx wrangler dev --remote 綁定一個真 KV namespace,與 local 模式的行為做對照,寫下兩點差異。
  2. 把 next 或 express 塞進一個試著 deploy 的專案,觀察 bundle 報錯,體會邊緣運行時的約束。
  3. 為 4.2 的 /todos API 補一組 Vitest 測試,覆蓋 GET、POST、404 三種情況,在 CI (GitHub Actions) 上跑通。