我们如何为Node.js兼容性重建Cloudflare Workers的模块注册表
内容提要
Cloudflare重写了Workers运行时workerd中的模块注册表,以提升Node.js兼容性。新实现将模块说明符视为URL,支持import.meta.url、import.meta.resolve()、正确的导入属性验证、Node.js风格的require(esm)规则、一致的错误处理、惰性编译及WebAssembly源阶段导入。用户可通过启用new_module_registry兼容标志来使用这些改进。
延伸解读
新模块注册表对现有部署的影响
新模块注册表目前不会自动启用,需要显式添加兼容性标志。现有Worker将继续使用旧实现,不会受到影响。这意味着开发者可以逐步测试新功能,而无需担心破坏现有应用。但需注意,一旦启用新标志,某些行为(如导入属性验证)将变得更加严格,可能暴露之前被忽略的错误。
URL说明符与查询字符串的模块隔离
新实现将模块说明符视为URL,查询字符串和片段的不同会导致模块实例的隔离。例如,'./counter.js?a'和'./counter.js?b'会加载同一份源码,但各自拥有独立的状态。这符合浏览器规范,但可能让依赖缓存或共享状态的开发者感到意外。建议避免在模块说明符中使用查询字符串,除非明确需要隔离实例。
require(esm)的同步限制
遵循Node.js的require(esm)规则,如果模块或其依赖包含顶层await,require()将抛出错误,因为require()必须同步返回。这提醒开发者,在CommonJS模块中require一个ES模块时,需确保该模块及其依赖没有顶层await,否则应改用动态import()。此限制与Node.js一致,有助于避免异步初始化带来的不确定性。
Q&A
如何启用Cloudflare Workers的新模块注册表?
在Worker的配置中添加兼容性标志"new_module_registry"即可启用,例如:{"compatibility_flags": ["new_module_registry"]}。
Cloudflare Workers新模块注册表与旧版相比有哪些改进?
新模块注册表将模块说明符视为URL,支持import.meta.url、import.meta.resolve(),正确验证导入属性,遵循Node.js的require(esm)规则,提供一致的错误处理,支持惰性编译和WebAssembly源阶段导入。
在Cloudflare Workers中,import.meta.resolve()是如何工作的?
import.meta.resolve()将说明符解析为URL,但不检查模块是否存在。它返回解析后的URL字符串,例如import.meta.resolve('./utils.js')返回'file:///bundle/utils.js'。如果说明符无法解析为URL,则抛出TypeError。
Cloudflare Workers如何处理带查询字符串的模块导入?
带不同查询字符串或片段的说明符被视为不同的模块实例,即使它们指向相同的源代码。例如,导入'./counter.js?a'和'./counter.js?b'会创建两个独立的模块实例,各自拥有自己的状态。
Cloudflare Workers新模块注册表如何验证导入属性?
新模块注册表会验证导入属性,如果遇到不支持的属性类型或键,会抛出TypeError。目前仅支持type: 'json',其他类型如text和bytes会被拒绝,并给出明确错误。
在Cloudflare Workers中,require()一个ES模块时遵循什么规则?
遵循Node.js的require(esm)规则:如果模块有名为'module.exports'的字符串导出,则返回该值;否则返回模块的命名空间对象。如果模块或其依赖包含顶层await,则require()会抛出错误。
Cloudflare Workers新模块注册表如何改进错误处理?
无论通过静态导入、动态import()还是require()触发错误,都会返回相同类别的错误和消息。例如,模块未找到时抛出Error,无效的模块说明符抛出TypeError。
Cloudflare Workers支持WebAssembly源阶段导入吗?
是的,新模块注册表支持WebAssembly源阶段导入,可以使用import source wasmModule from './add.wasm'或动态import.source('./add.wasm')来获取WebAssembly.Module对象。