Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Module Harmony

Module Harmony

JSConf JP 2025

Avatar for petamoriken / 森建

petamoriken / 森建

November 16, 2025
Tweet

More Decks by petamoriken / 森建

Other Decks in Programming

Transcript

  1. 2 Self-Introduction • A Deno contributor • An advocate for

    ES2025 Float16Array • I like to keep up with Web Standards ◦ Sharing new stuff in the company's frontend community petamoriken pixiv WebDev engineer in Fukuoka
  2. 5 Table of Contents • ES Modules • Current Specification

    • Current Proposals ◦ Import Phase Modifiers ◦ Other Proposals • To conclude
  3. 7 ES Modules import { foo } from "./foo.mjs"; import

    * as bar from "./bar.mjs"; import baz from "./baz.mjs"; import qux from "./qux.json" with { type: "json" }; export { foo } from "./foo.mjs"; const namespace = await import("./foo.mjs");
  4. 10 ES Module Graph JS JS JS JS JSON JS

    JS * * ESM Integration for Wasm is progressing at the WasmWG : Module Record Wasm
  5. 11 Module Records (Abstract) Module Record Source Text Module Record

    Cyclic Module Record Synthetic Module Record
  6. 12 Module Records (Abstract) Module Record Source Text Module Record

    Cyclic Module Record Synthetic Module Record Wasm JS JSON, CSS
  7. 13 Module Records (Abstract) Module Record Source Text Module Record

    Cyclic Module Record Synthetic Module Record CommonJS Wasm JS JSON, CSS * no spec
  8. 14 Module Records (Abstract) Module Record Source Text Module Record

    Cyclic Module Record Synthetic Module Record CommonJS Wasm JS JSON, CSS * no spec Due to the spec, the cache cannot be purged (purgeable) cache
  9. 24

  10. 25

  11. 28 Import Phase Modifiers Resolve Load (dependencies) Link Evaluate modifier:

    asset source defer import asset ref from "./foo.mjs"; const module = await import.source("./bar.mjs");
  12. 29 Asset References Resolve Load (dependencies) Link Evaluate asset source

    defer import asset ref from "./foo.mjs"; console.log(ref); // AssetReference object const namespace = await import(ref); • No need to change the relative path even when the AssetReference object passes through modules
  13. 30 Asset References Resolve Load (dependencies) Link Evaluate asset source

    defer import asset imageRef from "./foo.png"; const img = new Image(); img.src = URL.createObjectURL(imageRef); • Allows notifying the host (runtime, bundler) about the existence of asset files statically
  14. 31 Module Sources Resolve Load (dependencies) Link Evaluate asset source

    defer (Abstract) Module Source WebAssembly.Module ModuleSource Wasm JS
  15. 32 Module Sources Resolve Load (dependencies) Link Evaluate asset source

    defer import source module from "./foo.wasm"; console.log(module); // WebAssembly.Module object const instance = await WebAssembly.instantiate(module, {/* imports */}); • Wasm modules can be statically added to ES Module Graph • CSP's wasm-unsafe-eval is no longer needed, improving security
  16. 33 Module Sources Resolve Load (dependencies) Link Evaluate asset source

    defer import source module from "./foo.mjs"; console.log(module); // ModuleSource object const worker = new Worker(module); • Modules for Web Workers can be statically added to ES Module Graph • Dynamic Imports work, too
  17. 34 Module Sources Resolve Load (dependencies) Link Evaluate asset source

    defer const workerModule = module { self.addEventListener("message", (e) => {}); }; const worker = new Worker(workerModule); Module Expressions • Possible to create inline modules for Web Workers
  18. 35 Deferring Module Eval Resolve Load (dependencies) Link Evaluate asset

    source defer import defer * as namespace from "./foo.mjs"; namespace.bar; // evaluate "./foo.mjs" • Defer execution until the namespace object's getter is invoked (namespace imports only supported) • Improve initial performance by delaying evaluation
  19. 36 Deferring Module Eval Resolve Load (dependencies) Link Evaluate asset

    source defer // math.mjs export defer { add } from "./math/add.mjs"; export defer { sub } from "./math/sub.mjs"; • Enable "Tree Shaking" without heuristics Deferred re-exports // do not evaluate "./math/sub.mjs" import { add } from "./math.mjs";
  20. 38 Module Declarations module Foo { export function foo() {}

    } import { foo } from Foo; • Bundlers' implementation complexity increases with ES Modules ◦ Proposal for additional syntax for bundlers • Optimizing bundled JS files is challenging for engines
  21. 39 Import Sync const namespace = import.sync("./foo.mjs"); • Bridge the

    gap with CommonJS using synchronous dynamic import ◦ Personally, the difference in whether cache can be purged seems like a big gap... • In a browser environment, the main thread cannot be blocked, so it might throw an exception
  22. 40 Import Bytes / Text import bytes from "./foo.png" with

    { type: "bytes" }; // Uint8Array backed by an Immutable ArrayBuffer console.log(bytes); • Add bytes and text support to Synthetic Module Records • Originally proposed in whatwg/html#9444 import text from "./foo.txt" with { type: "text" }; console.log(bytes); // string interpreted as UTF-8
  23. My Impressions 42 • ECMAScript has started accepting proposals for

    non-browser runtimes ◦ It is likely a result of WinterTC's activities ◦ Especially for Module Sources, Deno, Node.js, and Igalia are energetically pushing it forward • Also proposed with consideration for bundlers