@cloudflare/worker-bundler

中文文档
0.2.6发布于 2026/10/07MITTypeScriptES Module构建来源已验证近 30 天下载 40.8万

Cloudflare 工人装入器捆绑运行时构建和捆绑工人

中文使用文档
文档目录44 节
  1. 运行时间要求
  2. 安装
  3. 快速启动
  4. 装入工人
  5. 构建一个全Stack App
  6. API 密码
  7. createWorker(options)
  8. createApp(options)
  9. handleAssetRequest(request, manifest, storage, config?)
  10. 存储钩
  11. AssetStorage 接口
  12. 内建:内存存储
  13. 自定义: KV 存储
  14. 自定义: R2 存储
  15. 自定义: 工作空间存储
  16. 资产配置
  17. HTML 处理
  18. 非基金处理
  19. 重定向
  20. 自定义信头
  21. 缓存
  22. 出入口检测
  23. 挂载为永久对象
  24. 更多实例
  25. 多重依赖
  26. 与 Wrangler 配置
  27. 仅变形模式
  28. 高级捆绑选项
  29. jsx , (中文(简体) ), jsxImportSource
  30. define
  31. loader
  32. conditions
  33. virtualModules
  34. __dangerouslyUseEsBuildPluginsDoNotUseOrYouWillBeFired
  35. 工人加载器设置
  36. 文件系统
  37. 执行情况
  38. 从同步源抓取
  39. 总计前
  40. 语言服务
  41. 与 installDependencies
  42. 与工作空间融合
  43. 已知的限制
  44. 许可证

工人 -- -- 工人

实验:此软件包正在积极开发中,其API可能会不经通知而更改. 未建议用于生产.

在Cloudflare软件上装入并服务全高的应用程序 装入器装订 (闭塞β. 动态生成具有活性npm依赖性的工人,或者用客户端捆绑和静态资产服务来构建完整的应用程序.

运行时间要求

此软件包只运行 在Cloudflare工人运行时间(workerd(中文(简体) ) - 生产和生产 wrangler dev它通过一个 esbuild-wasm WebAssembly.Module 输入只有 Worker 模块加载器可以解析.

它会 没有 在平地节点下工作。 特别是,从使用默认节点池的 Vitest/Jest 测试中导入它,会显示一个指向这里的错误. 要测试取决于 @cloudflare/worker-bundler中的测试 @cloudflare/vitest-pool-workers 所以测试身体在内部执行 workerd。见 packages/worker-bundler/src/tests/vitest.config.ts 在此重播中进行示例设置.

安装

npm install @cloudflare/worker-bundler

快速启动

装入工人

提供源代码和依赖性——捆绑者处理其余:

import { createWorker } from "@cloudflare/worker-bundler";

const worker = env.LOADER.get("my-worker", async () => {
  const { mainModule, modules } = await createWorker({
    files: {
      "src/index.ts": `
        import { Hono } from 'hono';
        import { cors } from 'hono/cors';

        const app = new Hono();
        app.use('*', cors());
        app.get('/', (c) => c.text('Hello from Hono!'));
        app.get('/json', (c) => c.json({ message: 'It works!' }));

        export default app;
      `,
      "package.json": JSON.stringify({
        dependencies: { hono: "^4.0.0" }
      })
    }
  });

  return { mainModule, modules, compatibilityDate: "2026-01-01" };
});

await worker.getEntrypoint().fetch(request);

构建一个全Stack App

使用 createApp 将服务器 Worker、客户端 JavaScript 和静态资产捆绑在一起。 资产单独返还给东道方服务——它们没有嵌入隔离区:

import {
  createApp,
  handleAssetRequest,
  createMemoryStorage
} from "@cloudflare/worker-bundler";

const result = await createApp({
  files: {
    "src/server.ts": `
      export default {
        fetch(request) {
          return new Response("API response");
        }
      }
    `,
    "src/client.ts": `
      document.getElementById("app").textContent = "Hello from the client!";
    `
  },
  server: "src/server.ts",
  client: "src/client.ts",
  assets: {
    "/index.html":
      "<!DOCTYPE html><div id='app'></div><script src='/client.js'></script>",
    "/favicon.ico": favicon
  },
  assetConfig: {
    not_found_handling: "single-page-application"
  }
});

const worker = env.LOADER.get("my-app", () => ({
  mainModule: result.mainModule,
  modules: result.modules,
  compatibilityDate: "2026-01-01"
}));

// Serve assets on the host, forward the rest to the isolate
const storage = createMemoryStorage(result.assets);
const assetResponse = await handleAssetRequest(
  request,
  result.assetManifest,
  storage,
  result.assetConfig
);
if (assetResponse) return assetResponse;
return worker.getEntrypoint().fetch(request);

静态资产有适当的内容类型、ETags和缓存。 无法匹配资产的请求会落入您的服务器密码中 .

API 密码

createWorker(options)

Bundles 源文件输入一个工人.

选项类型默认说明
filesRecord<string, string> | FileSystem所需经费输入文件——普通对象或任何 FileSystem 执行
entryPointstring自动检测输入点文件路径
bundlebooleantrue将所有依赖性合并为一个文件
externalsstring[][]排除捆绑的模块cloudflare:* 总是外部)
targetstring'es2022'目标环境
minifybooleanfalse缩小输出
sourcemapbooleanfalse生成内线源图
registrystring'https://registry.npmjs.org'npm 注册 URL
jsx"transform" | "preserve" | "automatic"新建默认JSX 变换模式
jsxImportSourcestring新建默认JSX运行时间导入源(例如. "react", (中文(简体) ), "preact"(中文(简体) )
defineRecord<string, string>{}在捆绑时间应用的常数替换
loaderRecord<string, BundlerLoader>{}扩能加载器(如:. { ".svg": "text", ".wasm": "binary" }) (中文(简体) ). 见 高级捆绑选项 用于支持的集.
conditionsstring[]新建默认决议期间的一揽子出口条件
virtualModulesRecord<string, string>{}由生成的 JavaScript 模块源支持的精确导入指定别名 。 见 高级捆绑选项。 。 。 .
__dangerouslyUseEsBuildPluginsDoNotUseOrYouWillBeFiredunknown[][]逃出舱口:外置的esbuild插件,在内部虚拟-fs插件前运行. 不为铸币局所覆盖——见 高级捆绑选项。 。 。 .

回返情况:

{
  mainModule: string;
  modules: Record<string, string | Module>;
  wranglerConfig?: WranglerConfig;
  warnings?: string[];
}

createApp(options)

构建一个全存储应用程序:服务器Worker +客户端捆绑+静态资产.

选项类型默认说明
filesRecord<string, string> | FileSystem所需经费所有源文件——普通对象或任何 FileSystem
serverstring自动检测服务器入口( 工人获取处理器)
clientstring | string[]—— 说为浏览器捆绑的客户端入口
assetsRecord<string, string | ArrayBuffer>—— 说静态资产(路径名-内容)
assetConfigAssetConfig—— 说资产服务配置
bundlebooleantrueBundle 服务器依赖性
externalsstring[][]排除捆绑的模块
targetstring'es2022'服务器目标环境
minifybooleanfalse缩小输出
sourcemapbooleanfalse生成源地图
registrystringnpm 默认npm 注册 URL
jsx"transform" | "preserve" | "automatic"新建默认JSX 转换模式(适用于服务器和客户端捆绑)
jsxImportSourcestring新建默认JSX运行时间导入源(例如. "react", (中文(简体) ), "preact"(中文(简体) )
defineRecord<string, string>{}在捆绑时间(服务器和客户端)应用的常数替换
loaderRecord<string, BundlerLoader>{}扩能加载器(如:. { ".svg": "text" }) (中文(简体) ). 见 高级捆绑选项 用于支持的集.
conditionsstring[]新建默认决议期间的一揽子出口条件
virtualModulesRecord<string, string>{}由生成的 JavaScript 模块源支持的精确导入指定化名
__dangerouslyUseEsBuildPluginsDoNotUseOrYouWillBeFiredunknown[][]逃出舱门:外加出舱插件. 见 高级捆绑选项。 。 。 .

返回所有从 createWorker 加:

{
  assets: Record<string, string | ArrayBuffer>;  // Combined assets for host-side serving
  assetManifest: AssetManifest;        // Metadata (content types, ETags) per asset
  assetConfig?: AssetConfig;           // The asset config used
  clientBundles?: string[];            // Output paths of client bundles
}

handleAssetRequest(request, manifest, storage, config?)

独立的 Aync 资产请求处理器 。 该清单载有路由元数据(内容类型、ETags),而存储后端则按要求提供内容:

import { handleAssetRequest, buildAssets } from "@cloudflare/worker-bundler";

const { manifest, storage } = await buildAssets({
  "/index.html": "<h1>Hello</h1>",
  "/app.js": "console.log('hi')"
});

export default {
  async fetch(request) {
    const assetResponse = await handleAssetRequest(request, manifest, storage, {
      not_found_handling: "single-page-application"
    });
    if (assetResponse) return assetResponse;

    // Fall through to your API logic
    return new Response("API");
  }
};

回返a Promise<Response | null> a 包括: Response 如果资产匹配,或 null 掉下来.

存储钩

资产处理员离职 显示 (路径元数据) 存储 (内容检索). 这样可以插入任何后端.

AssetStorage 接口

interface AssetStorage {
  get(pathname: string): Promise<ReadableStream | ArrayBuffer | string | null>;
}

内建:内存存储

最简单的选择——将一切存储在记忆中:

import {
  buildAssetManifest,
  createMemoryStorage
} from "@cloudflare/worker-bundler";

const assets = { "/index.html": "<h1>Hi</h1>" };
const manifest = await buildAssetManifest(assets);
const storage = createMemoryStorage(assets);

或使用同时返回的便利函数:

import { buildAssets } from "@cloudflare/worker-bundler";

const { manifest, storage } = await buildAssets({
  "/index.html": "<h1>Hi</h1>"
});

自定义: KV 存储

import type { AssetStorage } from "@cloudflare/worker-bundler";

function createKVStorage(kv: KVNamespace): AssetStorage {
  return {
    async get(pathname) {
      return kv.get(pathname, "arrayBuffer");
    }
  };
}

自定义: R2 存储

function createR2Storage(bucket: R2Bucket, prefix = "assets"): AssetStorage {
  return {
    async get(pathname) {
      const obj = await bucket.get(`${prefix}${pathname}`);
      return obj?.body ?? null;
    }
  };
}

自定义: 工作空间存储

import type { Workspace } from "@cloudflare/shell";

function createWorkspaceStorage(workspace: Workspace): AssetStorage {
  return {
    async get(pathname) {
      return workspace.readFile(pathname);
    }
  };
}

所有存储后端都使用相同的功能 handleAssetRequest - 通过一个不同的 storage 参数.

资产配置

HTML 处理

控制如何解决 HTML 文件以及如何处理跟踪斜线 :

模式行为
auto-trailing-slash/about 服务 about.html· ; /blog/ 服务 blog/index.html
force-trailing-slash重定向 /about → /about/,从 index.html
drop-trailing-slash重定向 /about/ → /about,从 .html
none仅匹配精确路径

默认 : auto-trailing-slash

非基金处理

模式行为
single-page-application服务 /index.html 用于所有未匹配的路径
404-page服务于最近的 404.html 走进目录
none回返 null (通过你的工人)

默认 : none

重定向

{
  redirects: {
    static: {
      "/old-page": { status: 301, to: "/new-page" }
    },
    dynamic: {
      "/blog/:slug": { status: 302, to: "/posts/:slug" },
      "/docs/*": { status: 301, to: "/wiki/*" }
    }
  }
}

动态重定向支持 :placeholder 标志和 * 平板图案.

自定义信头

{
  headers: {
    "/*": {
      set: { "X-Frame-Options": "DENY" }
    },
    "/api/*": {
      set: { "Access-Control-Allow-Origin": "*" },
      unset: ["X-Frame-Options"]
    }
  }
}

图案使用格子语法. 规则按顺序适用——以后的规则可以优先于更早的规则.

缓存

资产处理器自动设置缓存头 :

  • HTML 和非阴影文件数字 : public, max-age=0, must-revalidate
  • 隐藏文件 (例如:. app.a1b2c3d4.js: public, max-age=31536000, immutable
  • ETag 支持: 有条件的请求 If-None-Match 返回时 304 Not Modified

出入口检测

优先权顺序 createWorker (和 createApp 服务器条目 :

  1. 明确 entryPoint 编号 : server 选项
  2. main 字段在 wrangler 配置中
  3. exports, (中文(简体) ), module,或 main 输入 package.json
  4. 默认路径 : src/index.ts, (中文(简体) ), src/index.js, (中文(简体) ), index.ts, (中文(简体) ), index.js

挂载为永久对象

createApp 捆绑代码并收集资产——产出如何挂载是呼叫者的担忧. 如果用户代码导出一个 DurableObject 子类,装入 getDurableObjectClass 并把它挂起,作为常存的表面.

getDurableObjectClass(name) 决定 a 名称 类导出- 因此导出类与 export class App没有 export default class App。默认的入站槽无法包含一个演员类,且默认导出 DurableObject 当引用面值时,将显示为不透明的内部错误.

const result = await createApp({
  files: {
    "src/server.ts": `
      import { DurableObject } from 'cloudflare:workers';

      export class App extends DurableObject {
        async fetch(request: Request) {
          const url = new URL(request.url);
          if (url.pathname === '/api/count') {
            const count = ((await this.ctx.storage.get('count')) as number) ?? 0;
            await this.ctx.storage.put('count', count + 1);
            return Response.json({ count });
          }
          return new Response('Not found', { status: 404 });
        }
      }
    `
  },
  assets: {
    "/index.html": "<!DOCTYPE html><h1>Counter</h1>"
  }
});

// Load the bundle and get the DO class
const worker = env.LOADER.get(loaderId, () => ({
  mainModule: result.mainModule,
  modules: result.modules,
  compatibilityDate: "2026-06-11"
}));

// Mount as a facet for persistent storage
const facet = this.ctx.facets.get("app", () => ({
  class: worker.getDurableObjectClass("App"),
  id: "app"
}));

// Serve assets on the host, forward the rest to the facet
const storage = createMemoryStorage(result.assets);
const assetResponse = await handleAssetRequest(
  request,
  result.assetManifest,
  storage,
  result.assetConfig
);
if (assetResponse) return assetResponse;
return facet.fetch(request);

面部获得自己孤立的SQLite存储器,这些存储器独立于主机DO存储器而持续. 在保存存储时中止代码更改的面取新代码 :

this.ctx.facets.abort("app", new Error("Rebuilding"));

更多实例

多重依赖

const { mainModule, modules } = await createWorker({
  files: {
    "src/index.ts": `
      import { Hono } from 'hono';
      import { zValidator } from '@hono/zod-validator';
      import { z } from 'zod';

      const app = new Hono();
      const schema = z.object({ name: z.string() });

      app.post('/greet', zValidator('json', schema), (c) => {
        const { name } = c.req.valid('json');
        return c.json({ message: \`Hello, \${name}!\` });
      });

      export default app;
    `,
    "package.json": JSON.stringify({
      dependencies: {
        hono: "^4.0.0",
        "@hono/zod-validator": "^0.4.0",
        zod: "^3.23.0"
      }
    })
  }
});

与 Wrangler 配置

const { mainModule, modules, wranglerConfig } = await createWorker({
  files: {
    "src/index.ts": `
      export default {
        fetch: () => new Response('Hello!')
      }
    `,
    "wrangler.toml": `
      main = "src/index.ts"
      compatibility_date = "2026-01-01"
      compatibility_flags = ["nodejs_compat"]
    `
  }
});

const worker = env.LOADER.get("my-worker", () => ({
  mainModule,
  modules,
  compatibilityDate: wranglerConfig?.compatibilityDate ?? "2026-01-01",
  compatibilityFlags: wranglerConfig?.compatibilityFlags
}));

仅变形模式

跳过捆绑以保留模块结构 :

const { mainModule, modules } = await createWorker({
  files: {
    /* ... */
  },
  bundle: false
});

高级捆绑选项

createWorker 财务报告和审定财务报表 createApp 涵盖常见情况(目标、缩小、来源图、外部)。 以下选项是高级消费者的逃生舱口——RSC型变换,定制资产管道,图书馆捆绑.

本节所有选项都需要 bundle: true (默认). 仅变形模式( E)bundle: false) 跳过 esbuild 全部并使用 sulrase + naive 模块分辨率代替,所以 define, (中文(简体) ), loader, (中文(简体) ), conditions,插件,和 JSX 选项在那里没有效果. 设置其中任何一种 bundle: false 添加一个警告到 result.warnings 而不是默默地失败.

jsx, (中文(简体) ), jsxImportSource

明确选择JSX运行时间. 与 jsx: "automatic" 您不需要在每个文件中导入 React(或任何运行时间) .

await createApp({
  files,
  client: "src/client.tsx",
  jsx: "automatic",
  jsxImportSource: "react"
});

define

编译时间常数替换. 每个值必须是一个有效的 JavaScript 表达式作为字符串(所以在多引号中将字符串值相接).

await createWorker({
  files,
  define: {
    "process.env.NODE_ENV": '"production"',
    __DEV__: "false",
    __VERSION__: JSON.stringify(pkg.version)
  }
});

loader

告诉捆绑者如何解释任意文件扩展名 。 内置处理 .ts 编号 : .tsx 编号 : .js 编号 : .jsx 编号 : .json 编号 : .css 保存,除非您超过它。 更长的扩展匹配,所以 ".d.ts" 胜过 ".ts"。 。 。 .

await createWorker({
  files,
  loader: {
    ".svg": "text",
    ".wasm": "binary",
    ".sql": "text"
  }
});

受支助者 BundlerLoader 值被故意缩小到每个现代捆绑者可以表达的可移植子集:

装入器含义
js普通 Java 脚本
jsxJSX(按 jsx 选项)
ts类型脚本
tsx类型脚本 + JSX
json解析为 JSON, 曝光为默认导出
css解析为 CSS
text嵌入文件内容为 UTF-8 字符串默认导出
binary嵌入文件内容为 Uint8Array 默认导出
base64嵌入文件内容作为 Base64 字符串默认导出
dataurl嵌入文件内容为 data: URL 字符串默认导出

兴起的 file 编号 : copy 加载器是故意不暴露的:它们释放出这个捆绑器目前丢弃的二次输出文件(只有第一个输出被读取). 如果你需要这个——或者其他任何特定建设——的帮助 __dangerouslyUseEsBuildPluginsDoNotUseOrYouWillBeFired 换句话说.

conditions

包出口条件,按优先顺序排列. 当捆绑运送多重建造的图书馆时有用 package.json#exports。 。 。 .

await createWorker({
  files,
  conditions: ["workerd", "worker", "browser"]
});

virtualModules

别用精确的导入指定符来生成 JavaScript 模块 。 这个有用 当主机框架想要提供虚拟运行时模块而不曝光时 创建插件细节给呼叫者 .

const { mainModule, modules } = await createWorker({
  files: {
    "src/index.ts": `
      import { readFileSync } from "node:fs";

      export default {
        fetch() {
          return new Response(readFileSync("/message.txt", "utf8"));
        }
      };
    `
  },
  virtualModules: {
    "node:fs": `
      const files = { "/message.txt": "hello from a virtual module" };
      export function readFileSync(path) {
        return files[path];
      }
      export default { readFileSync };
    `,
    fs: `export * from "node:fs"; export { default } from "node:fs";`
  }
});

virtualModules 键是精确的比对。 如果你想要两者 "fs" 财务报告和审定财务报表 "node:fs" 工作,提供两个别名。 生成源与 其余的工人,因此可以通过入境点或过境进口 依赖性.

__dangerouslyUseEsBuildPluginsDoNotUseOrYouWillBeFired

在使用前读取这个. 此选项是 没有 由铸币局负责 这个名称是API合同:它可以改变形状,被更名,或者在任何发行中被删除. 运行时间将您连接到 esbuild —— 如果此软件包切换捆绑器( 如滚动) , 编写此 API 的插件将会被打破 .

通过额外的 Esbuild 插件 。 他们逃跑了 在此之前 捆绑器的内部虚拟文件系统插件,所以插件 onResolve 编号 : onLoad 声称先起火(例如RSC插件声称) "server-function:*" 在虚拟fs试图从磁盘读取之前).

此选项为 unknown[] 在公共边界,所以公布 .d.ts 不取决于 esbuild-wasm类型 传送时将插件阵列投影 :

import type { Plugin } from "esbuild-wasm";

const myRscPlugin: Plugin = {
  name: "rsc",
  setup(build) {
    build.onResolve({ filter: /^server-function:/ }, (args) => ({
      path: args.path,
      namespace: "rsc"
    }));
    build.onLoad({ filter: /.*/, namespace: "rsc" }, (args) => ({
      contents: generateServerFunctionStub(args.path),
      loader: "ts"
    }));
  }
};

await createApp({
  files,
  client: "src/client.tsx",
  __dangerouslyUseEsBuildPluginsDoNotUseOrYouWillBeFired: [
    myRscPlugin
  ] as unknown[]
});

工人加载器设置

// wrangler.jsonc (host worker)
{
  "worker_loaders": [{ "binding": "LOADER" }]
}
interface Env {
  LOADER: WorkerLoader;
}

文件系统

捆绑人运行在一个 FileSystem 接口——用于读取、撰写和列出文件的最小同步抽象。 所有捆绑者 APIs (createWorker, (中文(简体) ), createApp(a) 接受一个平原 Record<string, string> (自动包装在 InMemoryFileSystem或任意 FileSystem 执行.

interface FileSystem {
  read(path: string): string | null;
  write(path: string, content: string): void;
  delete(path: string): void;
  list(prefix?: string): string[];
  flush(): Promise<void>;
}

执行情况

InMemoryFileSystem —— 说 Map- 支持,没有坚持。 接受种子对象或 Map数字 :

import { InMemoryFileSystem } from "@cloudflare/worker-bundler";

const fs = new InMemoryFileSystem({
  "src/index.ts": "export default { fetch() { return new Response('ok'); } };"
});

DurableObjectKVFileSystem ——写作在内存中被缓冲并冲入一批可持久对象KV. 见缓冲写道:

import { DurableObjectKVFileSystem } from "@cloudflare/worker-bundler";

const fs = new DurableObjectKVFileSystem(this.ctx.storage);
fs.write("src/index.ts", code);

const result = await createWorker({ files: fs });

// Persist everything (source + installed node_modules) to KV
await fs.flush();

冲洗后, 文件系统是可持久性的 createWorker 呼叫一个新的 DurableObjectKVFileSystem 在同一存储器上找到 node_modules 已全部显示并跳过安装 .

DurableObjectRawFileSystem ——每篇作文直接去KV,没有缓冲. 写出少数文件时使用, 其中每个字的耐久性优先 :

import { DurableObjectRawFileSystem } from "@cloudflare/worker-bundler";

const fs = new DurableObjectRawFileSystem(this.ctx.storage);

从同步源抓取

这个 FileSystem 接口是同步的,因为 esbuilding 和 TypeScript 需要同步文件访问。 从 Aync 存储后端桥接( 如 Workspace 从 @cloudflare/shell),使用时 createFileSystemSnapshot数字 :

import { createFileSystemSnapshot } from "@cloudflare/worker-bundler";

// Accepts any sync or async iterable of [path, content] pairs
async function* workspaceFiles(workspace) {
  for (const entry of workspace.glob("**/*.{ts,tsx,json}")) {
    const content = await workspace.readFile(entry.path);
    if (content !== null) yield [entry.path, content];
  }
}

const fs = await createFileSystemSnapshot(workspaceFiles(workspace));
const result = await createWorker({ files: fs });

总计前

installDependencies 单独导出, 这样您就可以将 npm 软件包与 npm 软件包分开预加温 createWorker数字 :

import {
  installDependencies,
  DurableObjectKVFileSystem,
  createWorker
} from "@cloudflare/worker-bundler";

const fs = new DurableObjectKVFileSystem(this.ctx.storage);
fs.write("package.json", JSON.stringify({ dependencies: { hono: "^4.0.0" } }));
fs.write("src/index.ts", code);

// Install once, flush to KV
await installDependencies(fs);
await fs.flush();

// On subsequent requests, createWorker finds node_modules already
// present and skips installation — no network requests
const result = await createWorker({ files: fs });

这对于将安装步骤(慢,网络绑定)从捆绑步骤(快,CPU-只)中分离出来,以及对于贯穿DO重启的持续安装软件包都是有益的.

语言服务

一个完整的TypeScript语言服务在工人运行时间内部运行。 从中导入 ./typescript 保存主条目 TypeScript 捆绑(~5 MB) 的子路径 :

import { createTypescriptLanguageService } from "@cloudflare/worker-bundler/typescript";
import { InMemoryFileSystem } from "@cloudflare/worker-bundler";

const fileSystem = new InMemoryFileSystem({
  "tsconfig.json": JSON.stringify({
    compilerOptions: {
      lib: ["es2024"],
      target: "ES2024",
      module: "ES2022",
      moduleResolution: "bundler",
      strict: true,
      skipLibCheck: true
    }
  }),
  "src/index.ts": `
    const worker: ExportedHandler = {
      async fetch() {
        return new Response("Hello, world!");
      }
    };
    export default worker;
  `
});

const { fileSystem: tsFileSystem, languageService } =
  await createTypescriptLanguageService({ fileSystem });

// Get diagnostics
const errors = languageService.getSemanticDiagnostics("src/index.ts");

回来的 fileSystem 将原始内容包裹并保持 TypeScript 环境同步——通过它写入以立即看到更新的诊断:

// Fix an error
tsFileSystem.write("src/index.ts", correctedCode);

// Diagnostics now reflect the fix
const errors = languageService.getSemanticDiagnostics("src/index.ts");
// => []

与 installDependencies

在创建语言服务之前, 在文件系统中安装类型包以获得全类型覆盖 :

import {
  installDependencies,
  InMemoryFileSystem
} from "@cloudflare/worker-bundler";
import { createTypescriptLanguageService } from "@cloudflare/worker-bundler/typescript";

const fs = new InMemoryFileSystem({
  "package.json": JSON.stringify({
    dependencies: { "@cloudflare/workers-types": "^4.20260405.1" }
  }),
  "tsconfig.json": JSON.stringify({
    compilerOptions: {
      lib: ["es2024"],
      strict: true,
      skipLibCheck: true,
      types: ["@cloudflare/workers-types/index.d.ts"]
    }
  }),
  "src/index.ts": workerSource
});

await installDependencies(fs);

const { languageService } = await createTypescriptLanguageService({
  fileSystem: fs
});
const diagnostics = languageService.getSemanticDiagnostics("src/index.ts");

与工作空间融合

使用时 Workspace 从 @cloudflare/shell 作为持久存储,将源文件抓取到 InMemoryFileSystem 用于类型检查 :

import { createFileSystemSnapshot } from "@cloudflare/worker-bundler";
import { createTypescriptLanguageService } from "@cloudflare/worker-bundler/typescript";

// 1. Snapshot source files from Workspace (async reads)
async function* sourceFiles(workspace) {
  for (const entry of workspace.glob("**/*.{ts,tsx,json}")) {
    const content = await workspace.readFile(entry.path);
    if (content !== null) yield [entry.path, content];
  }
}

const fs = await createFileSystemSnapshot(sourceFiles(workspace));

// 2. Create language service (synchronous reads during init)
const { fileSystem, languageService } = await createTypescriptLanguageService({
  fileSystem: fs
});

// 3. Get diagnostics
const errors = languageService.getSemanticDiagnostics("src/index.ts");

// 4. On edits, update both the TS environment and durable storage
fileSystem.write("src/index.ts", newContent);
await workspace.writeFile("src/index.ts", newContent);

已知的限制

  • 平分节点 模块 ——所有包被安装在一个单一的平面目录中. 如果两个包需要不同不相容的版本相同的过渡依赖,则只安装了一个版本.
  • 以 tarball 为单位的文件路径长 ——焦油解析器处理经典头头,但不处理POSIX扩展头. 路径超过100个字符的软件包可能默默地截取了这些文件.
  • 仅来自 npm 的文本文件 ——只有文本文件(.js, (中文(简体) ), .json, (中文(简体) ), .css)取自柏油丸. 二进制文件 .wasm 或者说 .node 被跳过.
  • 无重复深度限制 ——过渡性依赖性解决无深度限制. 病理依赖树可能造成过多的网络请求.
  • 运行时获取的脚本 lib 声明 —— 说 createTypescriptLanguageService 下载每个调用中的 TypeScript npm tarball (~23 MB) 以提取标准库 .d.ts 文件(~3.7 MB). 没有缓存——每个创建语言服务的持久对象的冷起步都会产生这种取回。 未来的改进将在构建时预先将这些声明捆绑起来(遵循与TypeScript编译器捆绑相同的模式).

许可证

麻省理工学院

版本与发布记录

@cloudflare/worker-bundler 共发布 14 个版本,首次发布于 2026/03/12;过去 12 个月发布了 14 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.2.6latest2026/10/071 个月前
0.2.52026/10/021 个月前
0.2.42026/09/181 个月前
0.2.32026/08/182 个月前
0.2.22026/07/233 个月前
0.2.12026/06/075 个月前

关于 @cloudflare/worker-bundler 的常见问题

@cloudflare/worker-bundler 是什么?

Cloudflare 工人装入器捆绑运行时构建和捆绑工人

如何安装 @cloudflare/worker-bundler?

在项目目录运行 npm install @cloudflare/worker-bundler,或使用 pnpm add / yarn add / bun add。

@cloudflare/worker-bundler 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@cloudflare/worker-bundler 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@cloudflare/worker-bundler 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=22。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@cloudflare/worker-bundler 可以商用吗?

@cloudflare/worker-bundler 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@cloudflare/worker-bundler 的下载量有多少?

根据 npm 官方下载统计,@cloudflare/worker-bundler 在 2026/10/10 – 2026/11/08 这 30 天内被下载 408,436 次,日均约 13,615 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@cloudflare/worker-bundler 还在维护吗?

最新版本 0.2.6 发布于 2026/10/07(1 个月前);至今共发布 14 个版本,其中过去 12 个月发布了 14 个;首次发布于 2026/03/12。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。