celld中文文档v0.6.2
GitHub ↗
文档 / 入门与运行

WebAssembly

Worker 打包文件可以导入 .wasm 文件。与 Wrangler 一样,导入结果是已编译的模块,而不是原始字节。

js
import addModule from "./add.wasm";

const { exports } = new WebAssembly.Instance(addModule);

export default {
  fetch() {
    return new Response(String(exports.add(2, 3)));
  },
};

celld deploy 会将每个导入的 wasm 文件上传到打包文件旁边,并为部署标记 wasm-v1 特性。早于该特性的节点会拒绝部署,因此混合版本集群会在部署阶段失败,而不是等到处理请求时才失败。

celld 在每个进程中只编译每个 wasm 模块一次,后续的隔离实例和单元激活都会复用它。

示例#

WebAssembly 示例 编译一个 Rust Durable Object,并导入它的 WebAssembly 模块。

wrangler.jsonc

json
{
  "name": "counter-demo-rs",
  "main": "build/worker/shim.mjs",
  "compatibility_date": "2026-01-01",
  "durable_objects": {
    "bindings": [{ "name": "COUNTER", "class_name": "Counter" }]
  },
  "migrations": [{ "tag": "v1", "new_sqlite_classes": ["Counter"] }]
}

src/lib.rs

rust
use worker::*;

#[durable_object(fetch)]
pub struct Counter {
    state: State,
}

impl DurableObject for Counter {
    fn new(state: State, _env: Env) -> Self {
        Self { state }
    }

    async fn fetch(&self, req: Request) -> Result<Response> {
        let n: u64 = self.state.storage().get("n").await.ok().flatten().unwrap_or(0);
        let n = n + 1;
        self.state.storage().put("n", &n).await?;
        let path = req.path();
        let name = path.strip_prefix("/c/").unwrap_or("");
        Response::from_json(&serde_json::json!({ "name": name, "n": n, "lang": "rust" }))
    }
}

#[event(fetch)]
async fn fetch(req: Request, env: Env, _ctx: Context) -> Result<Response> {
    let path = req.path();
    if let Some(name) = path.strip_prefix("/c/").filter(|name| !name.is_empty()) {
        let namespace = env.durable_object("COUNTER")?;
        let stub = namespace.id_from_name(name)?.get_stub()?;
        return stub.fetch_with_request(req).await;
    }
    let status = if path == "/" { 200 } else { 404 };
    Ok(
        Response::ok("celld rust demo. Try: curl http://localhost:8080/c/hello\n")?
            .with_status(status),
    )
}

Cargo.toml

toml
[package]
name = "counter-demo-rs"
version = "0.1.0"
edition = "2021"

# 此配置表使示例独立于引擎工作区。
[workspace]

[lib]
crate-type = ["cdylib"]

[dependencies]
worker = "0.8.5"
serde_json = "1"

预构建的 Workers#

设置 no_bundle: true 时,celld 会逐字节保留入口 JavaScript,并在 main 所在目录下应用 Wrangler 的默认匹配规则 **/*.wasm 和 **/*.wasm?module。例如,main: "./dist/shim.mjs" 可以从 dist 导入 "./add.wasm" 或 "./lib/add.wasm",模块名保留这些相对路径。这种模式不需要 esbuild。

扫描也会上传 JavaScript 没有导入的 WASM 文件,因此应使用专门的构建输出目录。扫描会跳过 .git、.celld、.wrangler 和指向目录的符号链接。名称匹配 WASM 规则的符号链接会被拒绝,因此应将文件复制到构建输出目录中。

celld 不实现其他 Wrangler 模块发现设置。它不会发现额外的 JavaScript 模块,也不接受 rules、base_dir 或 find_additional_modules。JavaScript 必须已经完成打包,WASM 导入必须相对于入口目录。

使用 workers-rs 编写 Rust#

workers-rs 生成 JavaScript 适配文件(shim)和 wasm 文件,该适配文件可作为 celld deploy 的普通入口点。

  1. 安装构建工具:cargo install worker-build。
  2. 构建 crate:worker-build --release。
  3. 将配置指向适配文件:
jsonc
{
  "name": "my-app",
  "main": "./build/worker/shim.mjs",
  "compatibility_date": "2026-01-01",
}
  1. 部署:celld deploy。

celld 通过适配文件的 Proxy 包装器解析入口点和 Durable Object 类。如果 workers-rs API 依赖的运行时特性不在 Cloudflare 兼容性支持范围内,该 API 将无法使用。

动态 Workers#

在 modules 映射中以 { wasm: bytes } 形式将 wasm 传给动态加载的 Worker,Worker 导入时会得到已编译模块。与 workerd 一样,celld 拒绝直接传入裸字节。

js
const worker = env.loader.load({
  compatibilityDate: "2025-01-01",
  mainModule: "main.js",
  modules: {
    "main.js": `import m from "./add.wasm"; ...`,
    "add.wasm": { wasm: wasmBytes },
  },
});

限制#

与 JavaScript 模块一样,wasm 字节也计入部署大小限制。模块无法编译时,导入它的模块会失败,并抛出包含文件名的 WebAssembly.CompileError。

celld v0.6.2 · 简体中文文档
产品名、API、命令与示例代码保留原始写法。

输入关键词,搜索 20 篇中文文档。

支持中文术语、API 与环境变量 · Esc 关闭