From 7fb4cb4c8e535f06377c663e8576d4ec29d1f47a Mon Sep 17 00:00:00 2001 From: imccyu <276526105+imccyu@users.noreply.github.com> Date: Tue, 15 Sep 2026 20:23:21 +0800 Subject: [PATCH] fix(client): version lazy chunks by build generation --- ...7-23-client-plugin-loading-model.i18n.yaml | 4 +- .../2026-07-23-client-plugin-loading-model.md | 6 +- ...26-07-23-client-plugin-loading-model.zh.md | 6 +- docs/subsystems/client-modules.i18n.yaml | 4 +- docs/subsystems/client-modules.md | 4 +- docs/subsystems/client-modules.zh.md | 4 +- packages/client/AGENTS.md | 1 + packages/client/hmr/README.i18n.yaml | 4 +- packages/client/hmr/README.md | 4 +- packages/client/hmr/README.zh.md | 4 +- packages/client/hmr/src/index.ts | 9 ++- packages/client/modules/README.i18n.yaml | 4 +- packages/client/modules/README.md | 4 +- packages/client/modules/README.zh.md | 4 +- packages/client/modules/src/client/system.ts | 9 +++ packages/client/modules/src/index.ts | 74 +++++++++++-------- .../modules/tests/loader.client.spec.ts | 19 +++++ .../modules/tests/node-half.client.spec.ts | 32 +++++++- packages/client/tsdown.client.ts | 10 ++- .../extensions/tool-cordis/src/api-catalog.ts | 2 +- 20 files changed, 146 insertions(+), 62 deletions(-) diff --git a/.agents/notes/implemented/architecture/2026-07-23-client-plugin-loading-model.i18n.yaml b/.agents/notes/implemented/architecture/2026-07-23-client-plugin-loading-model.i18n.yaml index 4e70fc949c..730cfb413c 100644 --- a/.agents/notes/implemented/architecture/2026-07-23-client-plugin-loading-model.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-07-23-client-plugin-loading-model.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write .agents/notes/implemented/architecture/2026-07-23-client-plugin-loading-model.md -2026-07-23-client-plugin-loading-model.md: cfcd7802d04706264d25e061d663f11f4835bf97 -2026-07-23-client-plugin-loading-model.zh.md: 195273b69ca7743a8f800aa8228c773e5b57ba46 +2026-07-23-client-plugin-loading-model.md: a8d016a70792ad4ac6a71083677ce5d82a30af0a +2026-07-23-client-plugin-loading-model.zh.md: 1b94909c9611f01e5a6d7fcb50ec3f91ee88fab1 diff --git a/.agents/notes/implemented/architecture/2026-07-23-client-plugin-loading-model.md b/.agents/notes/implemented/architecture/2026-07-23-client-plugin-loading-model.md index cfcd7802d0..a8d016a707 100644 --- a/.agents/notes/implemented/architecture/2026-07-23-client-plugin-loading-model.md +++ b/.agents/notes/implemented/architecture/2026-07-23-client-plugin-loading-model.md @@ -34,7 +34,7 @@ The web kernel remains framework-free and imports no dynamic package value. Modu The browser mirrors the host's division of labor. `dsh-client-modules` (`ClientModuleSystem`) takes the module-system seat that Node's internal ESM loader holds host-side; the same vendored `@cordisjs/plugin-loader` keeps the governance seat on both sides. The line between them in one sentence: **the module system owns module identity and bytes — how code arrives, registers, and becomes an exports; the Loader owns plugin lifecycle — when a plugin mounts, what it waits for, and how it is torn down.** -`ClientModuleSystem` is a lazy CJS table. Executing a bundle only **registers** its factory — an entry calls `window.__ModuleLoader__.load({ id, factory })`, while a chunk also supplies its generated filename — and nothing else happens. Every module body side effect, CSS injection included, lives inside the factory closure and runs at materialization: the first `require`/import of that id, memoized after that. Import and prefetch recursively register declared dynamic requests before their consumer; a factory then materializes any registered-but-unmaterialized request synchronously. The callable `require` resolves synchronous module-table requests; its `require.async` operation returns a Promise that loads, registers, and materializes one package-local chunk. The shared tsdown preset compiles source `import()` expressions for package-local chunks to that distinct operation, while static relative imports remain inside their owning output chunk. The table resolves through a fixed branch order: seed word → memoized record → graph-row classic-script registration → registered-factory materialization → loud throw. The modules factory is the bootstrap exception: the HTML facade materializes it first, and construction places those same exports directly in the memoized table. That final throw is the runtime mirror of the build-time purity gate. The system also keeps per-module bookkeeping — owned `