Summary
Static component assets emitted by PR #360 are intentionally self-contained: each requested root embeds its full conservative dependency closure into one ESM module. This is correct and simple, but it duplicates shared component template/style bytes across multiple root assets.
We should investigate an ESM asset graph or shared-chunk strategy that deduplicates common dependencies while preserving the current runtime behavior.
Motivation
If multiple lazy roots depend on the same design-system components, each .webui.js asset repeats the same template metadata, CSS importmap entries, and condition functions. Runtime registration dedups via getTemplate(tag) / templatesAlreadyRegistered, but the browser still downloads and parses duplicated bytes.
This can become significant when:
- Many lazy roots share common shell/card/button/list components.
- Component templates include non-trivial JSON metadata and condition closures.
- Assets are CDN cached but users navigate through multiple lazy roots in one session.
Current behavior
Given roots settings-dialog and mail-thread, if both depend on shared-button, each emitted root asset contains shared-button in its components list and embeds its template payload. ESM module-graph dedup cannot help because the dependency is embedded as object literal data rather than imported as a shared module.
Correctness is fine: the loader avoids duplicate registration when templates are already present. The issue is network/parse byte duplication.
Proposed directions
Evaluate one or more of these designs:
-
One module per component
- Emit
<tag>.webui.js for every component in the closure.
- Root assets import dependency component modules.
- Browser ESM caching deduplicates shared dependencies.
-
Common shared asset chunks
- Compute overlap across requested roots at build time.
- Emit root assets plus one or more shared chunks.
- Keep root manifest ergonomic while avoiding repeated shared payloads.
-
Bundler-integrated virtual modules
- Let a Vite/webpack plugin map component tags to virtual modules.
- Use the bundler's existing chunking/dedup logic.
Constraints
- Do not regress the simple CLI case: one root should still be easy to load with
defineComponentAssets().
- Preserve current asset payload semantics and versioning, or introduce a versioned format upgrade.
- Keep CSS-module importmap dedup against
window.__webui.styles and already-injected asset styles.
- Avoid adding
.webui.js preload tags by default; only CSS assets should participate in CSS preload/link behavior.
- Maintain deterministic output names and content hashes.
Acceptance criteria
- Shared component payload bytes are downloaded once when two lazy roots share a dependency.
- Runtime still skips imports/registration for templates already present from SSR or prior assets.
- Tests cover two roots with a shared child component and verify no duplicate shared module fetch when using the new loader shape.
- A migration or compatibility story exists for current version 1 self-contained assets.
Related: PR #360 review discussion.
Summary
Static component assets emitted by PR #360 are intentionally self-contained: each requested root embeds its full conservative dependency closure into one ESM module. This is correct and simple, but it duplicates shared component template/style bytes across multiple root assets.
We should investigate an ESM asset graph or shared-chunk strategy that deduplicates common dependencies while preserving the current runtime behavior.
Motivation
If multiple lazy roots depend on the same design-system components, each
.webui.jsasset repeats the same template metadata, CSS importmap entries, and condition functions. Runtime registration dedups viagetTemplate(tag)/templatesAlreadyRegistered, but the browser still downloads and parses duplicated bytes.This can become significant when:
Current behavior
Given roots
settings-dialogandmail-thread, if both depend onshared-button, each emitted root asset containsshared-buttonin itscomponentslist and embeds its template payload. ESM module-graph dedup cannot help because the dependency is embedded as object literal data rather than imported as a shared module.Correctness is fine: the loader avoids duplicate registration when templates are already present. The issue is network/parse byte duplication.
Proposed directions
Evaluate one or more of these designs:
One module per component
<tag>.webui.jsfor every component in the closure.Common shared asset chunks
Bundler-integrated virtual modules
Constraints
defineComponentAssets().window.__webui.stylesand already-injected asset styles..webui.jspreload tags by default; only CSS assets should participate in CSS preload/link behavior.Acceptance criteria
Related: PR #360 review discussion.