For AI agents: the complete documentation index is available at /tc39-atlas/llms.txt, the full documentation bundle is available at /tc39-atlas/llms-full.txt, and this page is available as Markdown at /tc39-atlas/proposals/stage/3/proposal-source-phase-imports.md.
  • 简体中文
  • Source Phase Imports S3

    中文标题:源阶段导入

    提案概览
    提案速览

    该提案引入了一种新的导入阶段,允许将模块的已编译源作为具象对象导入。它提供了静态(import source x from "<specifier>")和动态(import.source("<specifier>"))两种形式。这支持了自定义模块加载器、打包器以及 WebAssembly 实例化等用例,无需手动进行 fetch 和编译即可访问模块源,同时保留了静态分析和安全优势。

    Note

    以下 README 来自上游仓库,其中的阶段或状态标注可能滞后;当前信息以提案概览为准。

    源阶段导入

    状态

    提案发起人:Luca Casonato, Guy Bedford

    作者:Luca Casonato, Guy Bedford, Nicolo Ribaudo

    阶段:3

    第 3 阶段审查人:Daniel Ehrenberg, Kris Kowal

    上游 PR:https://github.com/tc39/ecma262/pull/3492

    动机

    对于 JavaScript 和 WebAssembly 而言,都需要能够在标准宿主执行模型之外更细致地自定义模块的加载、链接和执行。

    对于 JavaScript,创建用户态加载器需要一种模块源类型,以便共享宿主的解析、执行、安全和缓存语义。

    对于 WebAssembly,WebAssembly 模块的导入和导出通常需要自定义检查和包装才能正确设置,这通常需要手动执行 fetch 和实例化工作,而当前的宿主 ESM 集成 提案并未提供这些。

    支持将模块源导入作为一种新的导入阶段的语法,创造了一个原语,可以将模块的静态、安全和工具优势从 ESM 集成扩展到这些动态实例化用例。

    提案

    本提案允许 ES 模块在宿主提供模块已编译源的具象表示(reified representation)时导入该表示:

    import source x from "<specifier>";

    source 模块源加载阶段名称被添加到 ImportStatement 的开头。

    仅支持上述形式——不支持命名导出和未绑定声明。

    动态形式

    与静态和动态导入一样,需要静态和动态地访问源,以支持那些在应用初始化期间需要从源文本实例化的源,以及那些在运行时可选或延迟创建的源。

    动态形式使用 import.<phase> 导入调用:

    const x = await import.source("<specifier>");

    通过将阶段作为显式语法的一部分,可以在静态上区分完整的动态导入和仅用于源的导入(后者不需要处理依赖)。

    可选的 导入属性 仍然可以通过第二个参数以 with 键指定,就像动态导入一样,并且由于分阶段评估的设计,不会发生冲突。

    加载阶段

    模块源导入可以被视为一种求值阶段。

    如果未来 资源引用提案 取得进展,它可能被视为代表加载过程更早阶段的另一种阶段。

    import asset x from "<specifier>";
    await import.asset("<specifier>");

    本提案仅规定 source 导入源阶段。

    定义模块源

    模块源阶段提供的对象必须是其原型链中包含 AbstractModuleSource.prototype 的对象,本规范将其定义为已编译模块化资源的最小共享基础原型。

    此外,它还定义了 @@toStringTag 获取器,返回与特定模块源子类名称对应的构造函数名称字符串,并带有强内部槽检查。

    JS 模块源

    对于 JavaScript 模块,模块源阶段随后被规定为返回一个 ModuleSource 对象,表示一个 ECMAScript 模块源,其中 ModuleSource.prototype.[[Proto]]%AbstractModuleSource%.prototype

    未来的提案可能会添加对 绑定查找方法、[ModuleSource 构造函数][module soruce] 和 实例化 的支持。

    新的属性可能会添加到基础 %AbstractModuleSource%.prototype 上,或通过 ModuleSource.prototype 的扩展与 ECMAScript 模块源共享。

    Wasm 模块源

    对于 WebAssembly 模块,需要更新现有的 WebAssembly.Module.prototype 对象,使其在 WebAssembly JS 集成 API 中拥有 %AbstractModuleSource%.prototype[[Proto]]

    这允许如动机中所述的工作流程,例如:

    import source FooModule from "./foo.wasm";
    FooModule instanceof WebAssembly.Module; // true
    
    // For example, to run a WASI execution with an API like Node.js WASI:
    import { WASI } from 'wasi';
    const wasi = new WASI({ args, env, preopens });
    
    const fooInstance = await WebAssembly.instantiate(FooModule, {
      wasi_snapshot_preview1: wasi.wasiImport
    });
    
    wasi.start(fooInstance);

    无需自定义 fetchWebAssembly.compileStreaming 所带来的静态分析优势不仅适用于代码分析和安全,也适用于打包器。

    这反过来使得 Wasm 组件未来能够导入 WebAssembly.Module 对象本身成为可能。

    其他模块类型

    任何其他宿主定义的模块类型都可以定义自己的宿主模块源。如果给定模块没有为其源定义源表示,则使用 "source" 阶段目标导入它会在链接时抛出 ReferenceError

    宿主定义的模块源必须在其原型链中包含 %AbstractModuleSource%.prototype,并支持包含 @@toStringTag 品牌检查及底层宿主源数据的 [[ModuleSourceRecord]] 内部槽。

    安全优势

    原生 ES 模块加载器能够实现安全策略,包括在浏览器中支持 内容安全策略。这一特性不仅影响使用 CSP 的平台,也影响其他具有限制权限系统的平台,例如 Deno。这些策略基于保护哪些 URL 被支持用于脚本或模块的编译和执行。

    将宿主模块系统的静态安全优势扩展到自定义加载器是本提案的一个安全优势。对于 Wasm,它将能够为动态 Wasm 实例化启用特定于源(source-specific)的 CSP 策略。

    缓存键语义

    由于 [[ModuleSourceObject]] 基于基础模块记录(base module record)作为键,因此它将始终对于被导入的模块是唯一的。

    问答

    :这与导入属性有什么关系?

    :导入属性是模块请求的属性,而源导入表示模块映射中该特定请求/键的阶段,不影响模块加载的幂等性。两者可以一起用于指示给定模块资源和属性的备选阶段。

    :这与模块表达式和隔离域(compartments)有什么关系?

    :这里提供的模块对象已经过谨慎规定,以与模块表达式和隔离域的链接模型兼容。

    :为什么不直接使用 const module = await WebAssembly.compileStreaming(fetch(new URL(\"./module.wasm\", import.meta.url)));

    :有几个好处:首先,如果模块在模块图中被静态引用,则更容易进行静态分析(例如由打包器分析)。其次,在使用 CSP 时,将不需要 script-src: unsafe-eval。更多细节请参阅安全改进部分。