用 Rust 写 Cloudflare Worker
Cloudflare Worker 一般用 JavaScript/TypeScript 写,但官方的 workers-rs 让我们可以用 Rust 写,再编译成 WASM 运行在 Worker 运行时上。这里记录一个最简项目的结构和构建链路。
项目结构
一个 workers-rs 项目的核心文件只有三个:
Cargo.toml—— Rust 包描述wrangler.toml—— Cloudflare Worker 配置src/lib.rs—— 入口(注意是lib.rs而不是main.rs)
入口代码
入口用 #[event(fetch)] 宏标注一个 async 函数,签名固定为 (Request, Env, Context) -> Result<Response>:
use worker::*;
#[event(fetch)]
async fn fetch(_req: Request, _env: Env, _ctx: Context) -> Result<Response> {
Response::ok("Hello World!")
}
如果要做定时任务(cron),则再加一个 #[event(scheduled)] 标注的函数:
#[event(scheduled)]
async fn cron_task(event: ScheduledEvent, env: Env, ctx: ScheduleContext) {
console_log!("Event: {:?}", event);
}
Cargo.toml 的关键点
最重要的是把 crate 类型设成 cdylib,这样才能编译出供 WASM 链接的动态库:
[lib]
crate-type = ["cdylib"]
[dependencies]
worker = { version = "0.8" }
worker-macros = { version = "0.8" }
构建链路
这是 workers-rs 和普通 Worker 最不一样的地方。Rust 代码不是直接跑,而是经过一条编译流水线:
Rust 源码 → WASM(wasm-bindgen / wasm-opt)→ worker-build 打包成 build/index.js
wrangler.toml 里通过 [build] 把这条链子接起来,main 指向打包产物 build/index.js:
name = "my-worker"
main = "build/index.js"
compatibility_date = "2026-06-18"
[build]
command = "cargo install -q worker-build && worker-build --release"
上面是 cargo generate 生成的默认配置。我自己又在 command 前面加了一段 export:
[build]
command = "export WASM_BINDGEN_BIN=$(which wasm-bindgen) WASM_OPT_BIN=$(which wasm-opt) && cargo install -q \"worker-build@^0.8\" && worker-build --release"
作用是让 worker-build 复用系统(或 mise)里已装好的 wasm-bindgen、wasm-opt,而不是让它自己去下载一份,避免下载慢或版本不匹配的问题。
worker-build --release 跑完后,build/ 目录里会生成:
index.js—— JS shim(约 20KB),Worker 实际加载的入口index_bg.wasm—— 编译出的 WASM(约 330KB),真正的业务逻辑
也就是说,部署到 Cloudflare 的本质上还是一段 JS(shim)+ 一个 WASM 模块,Rust 只是写法。
小结
用 Rust 写 Worker 的心智模型:照常写 Rust,借 worker crate 拿到 Request/Response/Env 等运行时能力,编译成 cdylib,再由 worker-build 把 WASM 包成 JS shim 部署。配置上记住三件事——入口是 lib.rs、crate 类型是 cdylib、wrangler.toml 的 main 指向 build/index.js。