你以为 import.meta.resolve() 只能靠 bundler?今天 Cloudflare 把这件事用运行时彻底原生化了

Workers 每次启动都要等整个 bundle 编译完——这件事今天被 Cloudflare 从根上翻了

以前部署 Workers 有个不成文的规矩:不套一层 bundler 根本没法跑。哪怕只是个简单函数,rollup/esbuild 也得先把整个模块图跑一遍,把所有 import 拍平、把路径解析好,再塞给 Workers。这是因为旧版 workerd 的模块注册表把模块说明符当文件系统路径处理,根本不支持 import.meta.resolve() 这类标准 web API,导致开发者只能靠 bundler 做路径转换。

Cloudflare 前几天正式发布了 workerd 模块注册表的完整重写,核心变化只有一件事:把路径型说明符换成 URL 型说明符。但这件小事带来的连锁反应,远比它听起来要大得多。

懒编译:不用再为没用的代码付启动代价

旧版在 V8 隔离实例启动时就会把整个 bundle 提前编译好,哪怕这个模块要等十分钟后才第一次 import。这意味着冷启动时间和 bundle 体积直接挂钩——代码越多,冷启动越慢。

新注册表实现了完全懒编译:每个模块只在第一次被 import 时才编译。用到哪个加载哪个,不用不动。第一次请求不再为空闲代码付编译代价,这对看重首字节时间的边缘函数场景来说是本质区别。

跨隔离实例的字节码缓存:同 bundle 不用重复编译

Cloudflare 的生产环境同一个 Workers 会起多个 V8 隔离副本来分散请求。旧版每个副本都会独立编译自己的 bundle 副本,16 核 CPU 上可能同时跑着 8 份相同的编译结果。

新注册表把编译好的 V8 字节码放在跨隔离实例共享的 kj::MutexGuarded 字段里,一个副本编译完,同 bundle 的其他副本直接读缓存,不需要重复编译。这对多副本部署的高吞吐场景是内存和 CPU 的双向节省。

import.meta 终于能用了

路径型转 URL 型后,import.meta.urlimport.meta.mainimport.meta.resolve() 全部变成原生支持。拿 import.meta.resolve('node:crypto') 来说,旧版会因为路径处理逻辑直接报错,新版正确识别为 node: 协议的 URL 并返回正确解析结果。

带查询字符串和片段的说明符现在也是独立的模块实例:import './foo.js?config=dev'import './foo.js?config=prod' 在新注册表下是两个完全独立的模块实例,可以同时以不同配置加载同一个模块。这个能力在旧系统下根本不存在。

require(esm) 和导入属性校验

CommonJS 和 ESM 混用场景下,require() 一个 ES 模块现在遵循 Node.js 的规则:ES 模块导出了 module.exports 字符串命名的导出时返回该值,否则返回模块的命名空间对象。若该模块或其依赖图有顶层 await,require() 会抛出 ERR_REQUIRE_ASYNC_MODULE 风格的错误,而不是阻塞。这解决了混用场景下一个长年的运行时不确定性。

导入属性校验也更严格了:import data from './data.json' with { type: 'json' } 这类带类型的导入现在会正确校验类型,与 Node.js 行为对齐,不再是静默放行。

怎么迁移:加一个 compatibility flag 就行

新增 new_module_registry 兼容性标志,在 wrangler.json 里加一行配置:

{
  "compatibility_flags": ["new_module_registry"]
}

现有部署的 Workers 继续用旧版注册表,不受影响。这个 flag 没有强制开启的时间节点,团队可以按自己的节奏灰度验证。新注册表还有一个额外好处:所有 Node.js 稳定 API 相关功能现在都默认启用,不再需要单独配 nodejs_compat flag。另外 bundle 体积上限也从原来的种种限制放宽到所有方案均为 64 MiB。

对前端团队来说,这意味着什么

以前部署到 Workers 几乎必然要带一个 bundler 把模块图拍平,这个 bundler 实际上是 Workers runtime 的补丁。今天这个补丁可以下岗了,runtime 本身把模块解析、懒编译、跨副本缓存这些全做了。

冷启动更快的边缘函数、内存占用更少的多副本部署、更标准的 import.meta 能力——这三个改进同时到来,对于已经在用 Workers 或者想迁移 Node.js 服务到边缘的团队,是个值得重新评估的理由。

评论区

0 条评论

登录后可评论。