Cloudflare Workers 对 Rust 的支持正在跨过一个重要的兼容性门槛:wasm-bindgen 新增了实验性的 Emscripten 目标支持。过去,一些依赖系统接口、C/C++ 代码或特定 WebAssembly ABI 的 Rust 库难以直接进入 Workers;现在,这类项目有机会通过 wasm32-unknown-emscripten 构建,并部署到 Cloudflare 的全球运行平台。
这里的“原生 Rust”并不意味着把 Linux ELF 或本机机器码直接放进 Worker。最终产物仍然是运行在 Workers 沙箱中的 WebAssembly。变化在于构建链能够覆盖更多 Rust 生态,而不再局限于对 wasm32-unknown-unknown 友好的库。
为什么 Emscripten 目标能扩大兼容范围
传统的 wasm32-unknown-unknown 目标非常精简:它不默认提供完整操作系统环境,也没有通常意义上的 libc、文件系统和线程模型。纯计算库往往容易移植,但包含以下依赖的项目通常需要额外改造:
- 通过
cccrate 编译 C 或 C++ 源码的库; - 假设 libc 接口存在的依赖;
- 使用更完整运行时抽象的应用;
- 对线程、时钟、随机数或文件接口有平台假设的代码。
Emscripten 提供了一层更完整的 WebAssembly 工具链和兼容接口。新的 wasm-bindgen 目标支持,则负责让 Rust、生成的 Wasm 模块以及 JavaScript 宿主之间更顺畅地连接起来。
这并不等于所有桌面或服务器端 crate 都会自动可用。Workers 仍然没有传统服务器的本地磁盘、任意 TCP socket 或无限生命周期进程。Emscripten 改善的是“能否构建”和“能否接入宿主”的问题,运行时能力仍由 Workers 平台边界决定。
先做一次最小构建验证
下面的项目可以用来检查本地 Rust、Emscripten 与 wasm-bindgen 工具链是否能够协同工作。示例只导出一个文本统计函数,重点是验证目标产物,而不是模拟完整的 Worker 请求处理器。
创建项目:
mkdir rust-emscripten-check
cd rust-emscripten-check
mkdir src
cat > Cargo.toml <<'EOF'
[package]
name = "rust-emscripten-check"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib"]
[dependencies]
wasm-bindgen = "0.2"
EOF
cat > src/lib.rs <<'EOF'
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn summarize(input: &str) -> String {
let bytes = input.len();
let lines = input.lines().count();
format!("bytes={bytes}, lines={lines}")
}
EOF
安装并启用 Emscripten。下面以官方 emsdk 的常见安装方式为例;在 CI 中应固定版本,而不是长期使用 latest:
git clone https://github.com/emscripten-core/emsdk.git
cd emsdk
./emsdk install latest
./emsdk activate latest
source ./emsdk_env.sh
cd ..
rustup target add wasm32-unknown-emscripten
cargo install wasm-bindgen-cli --locked
执行构建并生成绑定文件:
cargo build --release --target wasm32-unknown-emscripten
wasm-bindgen \
target/wasm32-unknown-emscripten/release/rust_emscripten_check.wasm \
--out-dir pkg \
--target web
find pkg -maxdepth 1 -type f -print
运行前需要注意两个版本问题:
wasm-bindgen-cli最好与Cargo.lock中的wasm-bindgencrate 保持兼容;- 这项 Emscripten 支持仍属实验功能,应记录 Rust、Emscripten 和
wasm-bindgen的具体版本。
如果构建失败,可以先打印环境信息,避免只在开发者机器上“碰巧成功”:
rustc --version
cargo --version
emcc --version
wasm-bindgen --version
rustup target list --installed
接入 Workers 时,应以当前 Cloudflare Rust 模板生成的适配层和部署配置为准,将上面验证过的库代码逐步迁入,而不是假设浏览器用的 --target web 胶水可以原样承担 Worker 请求生命周期。
迁移现有项目时,不要一次替换整条链路
更稳妥的迁移方式,是先把现有工程拆成“核心库”和“平台适配层”:
my-worker/
├── crates/
│ ├── core/ # 解析、校验、压缩、业务计算
│ └── worker-app/ # Request、Response、环境变量和平台 API
├── Cargo.toml
└── wrangler.toml
core crate 尽量不直接依赖 Workers API。先对它执行 Emscripten 目标检查:
cargo check -p core --target wasm32-unknown-emscripten
cargo test -p core
随后再处理 worker-app 的请求入口和部署配置。这样遇到错误时,可以快速区分三类问题:
- crate 本身无法为 Emscripten 编译;
wasm-bindgen绑定或链接阶段失败;- 代码调用了 Workers 沙箱不具备的系统能力。
对于带原生依赖的项目,还可以在 CI 中增加一个独立检查任务。以下 GitHub Actions 片段可以直接改造,关键是把 Emscripten 版本固定到团队验证过的版本:
name: rust-emscripten-check
on:
pull_request:
push:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
targets: wasm32-unknown-emscripten
- name: Install Emscripten
uses: mymindstorm/setup-emsdk@v14
with:
version: "3.1.64"
- name: Build for Emscripten
run: cargo build --release --target wasm32-unknown-emscripten
示例中的 Emscripten 版本只是可修改的固定值,不代表平台要求。项目应使用经过测试的版本,并配合依赖锁文件升级。
Tokio 值得期待,但现在不要预设完整兼容
来源信息提到 Tokio 异步支持即将到来。这一点对 Rust 服务开发者很重要,因为大量网络客户端、中间件和应用框架建立在 Tokio 生态上。
不过,“支持 Tokio async”不应被理解为 Workers 会变成一台传统 Tokio 服务器。边缘运行时仍可能在以下方面存在差异:
- 不允许监听任意 TCP 端口;
- 异步任务受请求生命周期约束;
- 文件系统和进程接口不可用或被虚拟化;
- 某些依赖多线程调度器的功能可能需要降级;
- 后台任务、定时器和出站连接必须遵循平台 API。
因此,在正式支持和对应文档落地之前,不要把 tokio::net、多线程 runtime 或常驻任务当成已可用能力。更适合提前做的工作,是把业务代码改为异步接口,并隔离网络、时间和存储实现。
上线前的检查清单
采用这条新构建路径时,可以按下面的顺序控制风险:
- 固定 Rust、Emscripten、
wasm-bindgen和 Workers 工具链版本; - 对每个关键依赖执行
cargo check --target wasm32-unknown-emscripten; - 检查依赖是否调用本地文件、进程、原始 socket 或线程 API;
- 分离纯 Rust 核心逻辑与 Workers 平台适配代码;
- 在预发布环境验证冷启动、包体积、内存和执行时间;
- 为实验目标保留现有构建链或回滚路径;
- 等待 Tokio 支持明确后,再逐项启用依赖它的功能。
Emscripten 目标的真正价值,不只是多出一个编译参数,而是让更多已有 Rust 代码进入 Workers 的候选范围。最合理的采用方式不是立刻迁移所有服务,而是先挑选一个依赖复杂、边界清晰的小型模块,验证构建、运行时能力和性能,再决定是否扩大使用范围。