@withl5e/l5e 1.1.0-alpha.1 → 1.1.0-alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -22,3 +22,40 @@ export default defineConfig({
22
22
  ```
23
23
 
24
24
  See the root README and `examples/basic` for a full app.
25
+
26
+ Compact chunking is experimental and opt-in. The staged activation behavior and
27
+ `islandRuntime` option below require the `1.1.0-alpha.3` prerelease:
28
+
29
+ ```ts
30
+ coreVite({
31
+ chunking: {
32
+ mode: 'compact',
33
+ shared: [{ name: 'state', modules: ['~/stores/session.ts'] }],
34
+ islandRuntime: {
35
+ packages: ['@tanstack/react-query'],
36
+ modules: ['~/client/query-client.ts'],
37
+ },
38
+ },
39
+ });
40
+ ```
41
+
42
+ Compact mode limits the initial shell and each later island/action activation to
43
+ at most three new JavaScript assets. `load` and already-visible islands activate
44
+ immediately after the shell, so the cumulative cold request count can be higher.
45
+ The runtime starts every known static dependency request in parallel, waits for
46
+ the island CSS, then evaluates and mounts or hydrates. Dynamic descendants remain
47
+ lazy. List state that must survive page-bundle swaps in `shared`; list React
48
+ contexts or client caches that multiple islands must share in `islandRuntime`.
49
+ Only the configured static closure is included, and dynamic imports are not
50
+ promoted. Compact mode requires native import-map support.
51
+
52
+ Compact chunking applies to production builds. Development keeps Vite source modules
53
+ and HMR, and its Network requests are not subject to the production three-file limit.
54
+
55
+ The alpha renderer bridge expects Vite to emit one entry facade and one canonical
56
+ renderer export chunk. A different renderer shape is rejected during server setup
57
+ because merging multiple minified export namespaces can make aliases ambiguous.
58
+
59
+ See [runtime script bundles and shared modules](../../docs/runtime-script-bundling.md)
60
+ for the download/evaluation/mount lifecycle, strategy behavior, ownership rules,
61
+ activation examples and current alpha limitations.
package/dist/index.js CHANGED
@@ -4,6 +4,6 @@ import { a as j, i as M, n as N, o as P, r as F, t as I } from "./exceptions-D4O
4
4
  import { render as L } from "./entry-server.js";
5
5
  import { n as R, t as z } from "./middleware-CnDqZobD.js";
6
6
  import { t as B } from "./defineMiddleware-D017PWDc.js";
7
- import { a as V, n as H } from "./server-BOdEiJoN.js";
8
- import { t as U } from "./vite-plugin-R3LFxv9a.js";
7
+ import { a as V, n as H } from "./server-C35BtVu8.js";
8
+ import { t as U } from "./vite-plugin-Bln1di66.js";
9
9
  export { I as BadRequestException, T as Fragment, _ as HEAD_PRIORITY, b as Head, N as HttpException, F as InternalServerErrorException, M as NotFoundException, j as RedirectException, P as ServiceUnavailableException, C as addCacheTag, g as cloneElement, U as coreVite, z as createContext, H as createServer, B as defineMiddleware, r as escapeHTML, t as escapeProp, l as getCacheTags, x as getClientJsEntries, w as getCssEntries, d as getHeadContent, v as getIslandEntries, E as getIslandProps, f as getSchemas, p as getSsrIslands, S as isIslandPropsExternalized, y as isValidElement, h as jsxFactory, m as pushIslandProps, c as pushMetadata, D as pushSchema, A as registerIsland, u as registerSsrIsland, L as render, n as renderJsxToHtmlString, e as renderToRenderedNode, k as resolveMetadata, o as runInRenderContext, R as sequence, i as setViewName, V as startServer, O as useClientJs, s as useCss, a as useRequest };
@@ -56,9 +56,26 @@ function s(e) {
56
56
  return;
57
57
  }
58
58
  try {
59
- let { reactDomClient: t, createElement: n, module: i } = await r(), a = i.default || i[e.exportName];
60
- if (!a) throw Error(`No export "default" or "${e.exportName}" in module`);
61
- e.ssr ? t.hydrateRoot(e.element, n(a, e.props)) : t.createRoot(e.element).render(n(a, e.props));
59
+ for (let e of r.js) {
60
+ if (document.querySelector(`link[rel="modulepreload"][href="${CSS.escape(e)}"]`)) continue;
61
+ let t = document.createElement("link");
62
+ t.rel = "modulepreload", t.crossOrigin = "anonymous", t.href = e, document.head.append(t);
63
+ }
64
+ await Promise.all(r.css.map((e) => new Promise((t, n) => {
65
+ let r = document.querySelector(`link[rel="stylesheet"][href="${CSS.escape(e)}"]`);
66
+ if (r?.sheet) return t();
67
+ let i = r || document.createElement("link");
68
+ i.rel = "stylesheet", i.crossOrigin = "anonymous", i.href = e, i.addEventListener("load", () => t(), { once: !0 }), i.addEventListener("error", () => n(/* @__PURE__ */ Error(`Failed to load ${e}`)), { once: !0 }), r || document.head.append(i);
69
+ })));
70
+ let [t, n] = await Promise.all([import(
71
+ /* @vite-ignore */
72
+ r.renderer
73
+ ), import(
74
+ /* @vite-ignore */
75
+ r.module
76
+ )]), { reactDomClient: i, createElement: a } = t, o = n.default || n[e.exportName];
77
+ if (!o) throw Error(`No export "default" or "${e.exportName}" in module`);
78
+ e.ssr ? i.hydrateRoot(e.element, a(o, e.props)) : i.createRoot(e.element).render(a(o, e.props));
62
79
  } catch (t) {
63
80
  console.error(`[l5e-island] Failed to mount "${e.registryKey}":`, t);
64
81
  }
@@ -1 +1 @@
1
- {"version":3,"file":"compact-runtime.js","names":[],"sources":["../../src/island/compact-runtime.ts"],"sourcesContent":["import type { IslandMeta } from './types';\nimport { strategies, registerMountStrategy } from './strategy-registry';\n\nregisterMountStrategy('load', (mount) => void mount());\nregisterMountStrategy('idle', (mount) => {\n if ('requestIdleCallback' in window) requestIdleCallback(() => mount());\n else setTimeout(() => mount(), 200);\n});\nregisterMountStrategy('visible', (mount, opts, el) => {\n const observer = new IntersectionObserver(\n (entries) => {\n if (entries.some((entry) => entry.isIntersecting)) {\n observer.disconnect();\n mount();\n }\n },\n { rootMargin: opts || '200px' },\n );\n observer.observe(el);\n return () => observer.disconnect();\n});\nregisterMountStrategy('media', (mount, opts) => {\n if (!opts) {\n console.error('[l5e-island] Strategy \"media\" requires mountOpts (media query)');\n return;\n }\n const query = window.matchMedia(opts);\n if (query.matches) mount();\n else {\n const handler = (event: MediaQueryListEvent) => event.matches && mount();\n query.addEventListener('change', handler, { once: true });\n return () => query.removeEventListener('change', handler);\n }\n});\nregisterMountStrategy('none', () => {});\n\nimport 'virtual:l5e-island-strategies';\n\ntype CompactIslandModule = {\n reactDomClient: typeof import('react-dom/client');\n createElement: typeof import('react').createElement;\n module: Record<string, any>;\n};\nconst registry: Record<string, () => Promise<CompactIslandModule>> = ((window as any)\n .__L5E_ISLANDS__ ||= {});\nlet islandData: unknown[] | null = null;\nconst scheduled = new WeakSet<Element>();\n\nfunction props(element: Element): Record<string, unknown> {\n const index = element.getAttribute('data-island-idx');\n if (index === null) return JSON.parse(element.getAttribute('data-island-props') || '{}');\n if (!islandData) {\n const store = document.getElementById('_l5e_data_');\n try {\n const parsed = JSON.parse(store?.textContent || '[]');\n islandData = Array.isArray(parsed) ? parsed : [];\n } catch (error) {\n console.error('[l5e-island] Failed to parse _l5e_data_ props store:', error);\n islandData = [];\n }\n }\n return (islandData[Number(index)] as Record<string, unknown>) || {};\n}\n\nfunction discover(): IslandMeta[] {\n return Array.from(document.querySelectorAll('[data-island]')).map((element) => ({\n element: element as HTMLElement,\n registryKey: element.getAttribute('data-island')!,\n exportName: element.getAttribute('data-island-name')!,\n props: props(element),\n mount: element.getAttribute('data-island-mount') || 'load',\n mountOpts: element.getAttribute('data-island-opts') || undefined,\n ssr: element.hasAttribute('data-island-ssr'),\n }));\n}\n\nfunction mount(island: IslandMeta) {\n let mounted = false;\n return async () => {\n if (mounted) return;\n mounted = true;\n const loader = registry[island.registryKey];\n if (!loader) {\n console.error(`[l5e-island] Component \"${island.registryKey}\" not found in page registry.`);\n return;\n }\n try {\n const { reactDomClient, createElement, module } = await loader();\n const Component = module.default || module[island.exportName];\n if (!Component) throw new Error(`No export \"default\" or \"${island.exportName}\" in module`);\n if (island.ssr) {\n reactDomClient.hydrateRoot(island.element, createElement(Component, island.props));\n } else {\n const root = reactDomClient.createRoot(island.element);\n root.render(createElement(Component, island.props));\n }\n } catch (error) {\n console.error(`[l5e-island] Failed to mount \"${island.registryKey}\":`, error);\n }\n };\n}\n\nfunction boot() {\n for (const island of discover()) {\n if (scheduled.has(island.element)) continue;\n // The compact global can execute before the page bundle registers its loaders.\n // The page bundle calls boot again after registration.\n if (!registry[island.registryKey]) continue;\n const strategy = strategies.get(island.mount);\n if (!strategy) {\n console.error(`[l5e-island] Strategy \"${island.mount}\" not found.`);\n continue;\n }\n scheduled.add(island.element);\n strategy(mount(island), island.mountOpts, island.element);\n }\n}\n\n(globalThis as any).__L5E_BOOT_ISLANDS__ = boot;\nif (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', boot);\nelse boot();\n"],"mappings":"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"}
1
+ {"version":3,"file":"compact-runtime.js","names":[],"sources":["../../src/island/compact-runtime.ts"],"sourcesContent":["import type { IslandMeta } from './types';\nimport { strategies, registerMountStrategy } from './strategy-registry';\n\nregisterMountStrategy('load', (mount) => void mount());\nregisterMountStrategy('idle', (mount) => {\n if ('requestIdleCallback' in window) requestIdleCallback(() => mount());\n else setTimeout(() => mount(), 200);\n});\nregisterMountStrategy('visible', (mount, opts, el) => {\n const observer = new IntersectionObserver(\n (entries) => {\n if (entries.some((entry) => entry.isIntersecting)) {\n observer.disconnect();\n mount();\n }\n },\n { rootMargin: opts || '200px' },\n );\n observer.observe(el);\n return () => observer.disconnect();\n});\nregisterMountStrategy('media', (mount, opts) => {\n if (!opts) {\n console.error('[l5e-island] Strategy \"media\" requires mountOpts (media query)');\n return;\n }\n const query = window.matchMedia(opts);\n if (query.matches) mount();\n else {\n const handler = (event: MediaQueryListEvent) => event.matches && mount();\n query.addEventListener('change', handler, { once: true });\n return () => query.removeEventListener('change', handler);\n }\n});\nregisterMountStrategy('none', () => {});\n\nimport 'virtual:l5e-island-strategies';\n\ntype CompactIslandModule = {\n reactDomClient: typeof import('react-dom/client');\n createElement: typeof import('react').createElement;\n module: Record<string, any>;\n};\ntype CompactIslandPlan = { module: string; renderer: string; js: string[]; css: string[] };\nconst registry: Record<string, CompactIslandPlan> = ((window as any).__L5E_ISLANDS__ ||= {});\nlet islandData: unknown[] | null = null;\nconst scheduled = new WeakSet<Element>();\n\nfunction props(element: Element): Record<string, unknown> {\n const index = element.getAttribute('data-island-idx');\n if (index === null) return JSON.parse(element.getAttribute('data-island-props') || '{}');\n if (!islandData) {\n const store = document.getElementById('_l5e_data_');\n try {\n const parsed = JSON.parse(store?.textContent || '[]');\n islandData = Array.isArray(parsed) ? parsed : [];\n } catch (error) {\n console.error('[l5e-island] Failed to parse _l5e_data_ props store:', error);\n islandData = [];\n }\n }\n return (islandData[Number(index)] as Record<string, unknown>) || {};\n}\n\nfunction discover(): IslandMeta[] {\n return Array.from(document.querySelectorAll('[data-island]')).map((element) => ({\n element: element as HTMLElement,\n registryKey: element.getAttribute('data-island')!,\n exportName: element.getAttribute('data-island-name')!,\n props: props(element),\n mount: element.getAttribute('data-island-mount') || 'load',\n mountOpts: element.getAttribute('data-island-opts') || undefined,\n ssr: element.hasAttribute('data-island-ssr'),\n }));\n}\n\nfunction mount(island: IslandMeta) {\n let mounted = false;\n return async () => {\n if (mounted) return;\n mounted = true;\n const plan = registry[island.registryKey];\n if (!plan) {\n console.error(`[l5e-island] Component \"${island.registryKey}\" not found in page registry.`);\n return;\n }\n try {\n // Schedule the complete known static closure before awaiting any response.\n // Modulepreload fetches without evaluating; native import retains ESM order.\n for (const href of plan.js) {\n if (document.querySelector(`link[rel=\"modulepreload\"][href=\"${CSS.escape(href)}\"]`))\n continue;\n const link = document.createElement('link');\n link.rel = 'modulepreload';\n link.crossOrigin = 'anonymous';\n link.href = href;\n document.head.append(link);\n }\n await Promise.all(\n plan.css.map(\n (href) =>\n new Promise<void>((resolve, reject) => {\n const existing = document.querySelector<HTMLLinkElement>(\n `link[rel=\"stylesheet\"][href=\"${CSS.escape(href)}\"]`,\n );\n if (existing?.sheet) return resolve();\n const link = existing || document.createElement('link');\n link.rel = 'stylesheet';\n link.crossOrigin = 'anonymous';\n link.href = href;\n link.addEventListener('load', () => resolve(), { once: true });\n link.addEventListener('error', () => reject(new Error(`Failed to load ${href}`)), {\n once: true,\n });\n if (!existing) document.head.append(link);\n }),\n ),\n );\n const [renderer, module] = await Promise.all([\n import(/* @vite-ignore */ plan.renderer),\n import(/* @vite-ignore */ plan.module),\n ]);\n const { reactDomClient, createElement } = renderer as Omit<\n CompactIslandModule,\n 'module'\n >;\n const Component = module.default || module[island.exportName];\n if (!Component) throw new Error(`No export \"default\" or \"${island.exportName}\" in module`);\n if (island.ssr) {\n reactDomClient.hydrateRoot(island.element, createElement(Component, island.props));\n } else {\n const root = reactDomClient.createRoot(island.element);\n root.render(createElement(Component, island.props));\n }\n } catch (error) {\n console.error(`[l5e-island] Failed to mount \"${island.registryKey}\":`, error);\n }\n };\n}\n\nfunction boot() {\n for (const island of discover()) {\n if (scheduled.has(island.element)) continue;\n // A fragment swap can expose an element before its activation plan is installed.\n if (!registry[island.registryKey]) continue;\n const strategy = strategies.get(island.mount);\n if (!strategy) {\n console.error(`[l5e-island] Strategy \"${island.mount}\" not found.`);\n continue;\n }\n scheduled.add(island.element);\n strategy(mount(island), island.mountOpts, island.element);\n }\n}\n\n(globalThis as any).__L5E_BOOT_ISLANDS__ = boot;\nif (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', boot);\nelse boot();\n"],"mappings":"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"}
@@ -62,37 +62,37 @@ function E(e) {
62
62
  }
63
63
  };
64
64
  }
65
- function D(e, t, n) {
65
+ function D(e, t, n, r = /* @__PURE__ */ new Set(), i = /* @__PURE__ */ new Map()) {
66
66
  return {
67
67
  name: "compact-build-graph",
68
- resolveId(r, i) {
69
- if (!i || r === w) return null;
70
- let a = u.isAbsolute(r) ? u.normalize(r) : r.startsWith("/") ? e.fileForAssetUrl(r) : r.startsWith(".") ? u.resolve(u.dirname(i), r) : null;
71
- return a ? e.isShared(a) && t ? {
68
+ resolveId(a, o) {
69
+ if (!o || a === w) return null;
70
+ let s = u.isAbsolute(a) ? u.normalize(a) : a.startsWith("/") ? e.fileForAssetUrl(a) : a.startsWith(".") ? u.resolve(u.dirname(o), a) : null;
71
+ return s ? i.has(s) ? {
72
+ id: i.get(s),
73
+ external: "absolute"
74
+ } : e.isShared(s) && t ? {
72
75
  id: t,
73
76
  external: "absolute"
74
- } : e.isGlobalOwned(a) && n ? {
77
+ } : e.isGlobalOwned(s) && n ? {
75
78
  id: n,
76
79
  external: "absolute"
77
- } : { id: a } : null;
80
+ } : e.isLazy(s) && !r.has(s) ? {
81
+ id: e.assetUrl(s),
82
+ external: "absolute"
83
+ } : { id: s } : null;
78
84
  }
79
85
  };
80
86
  }
81
87
  async function O(e, t, n = {}) {
82
- let r = e.map((e) => t.fileForScript(e)), i = n.compact && t.compact, a = t.inlineableRoots(r), o = new Map(r.flatMap((e, n) => !t.isPreserved(e) && !a.has(e) ? [[e, `entry-${n}`]] : [])), s = (n.islands || []).map(({ key: e, script: n }) => ({
88
+ let r = e.map((e) => t.fileForScript(e)), i = n.compact && t.compact, a = t.inlineableRoots(r), o = new Map(r.flatMap((e, n) => !t.isPreserved(e) && !a.has(e) ? [[e, `entry-${n}`]] : []));
89
+ (n.islands || []).map(({ key: e, script: n }) => ({
83
90
  key: e,
84
91
  file: t.fileForScript(n)
85
- })), c = n.renderer ? t.fileForScript(n.renderer) : void 0, l = (n.exportScripts || []).map((e) => t.fileForScript(e)), d = {
92
+ })), n.renderer && t.fileForScript(n.renderer);
93
+ let s = (n.exportScripts || []).map((e) => t.fileForScript(e)), c = n.inlineStaticRootClosure ? t.staticClosure(r) : /* @__PURE__ */ new Set(), l = new Map(Object.entries(n.externalScripts || {}).map(([e, n]) => [t.fileForScript(e), n])), d = {
86
94
  input: w,
87
- plugins: [T([
88
- ...r.map((e) => n.name === "shared" ? `export * from ${JSON.stringify(e)};` : `import ${JSON.stringify(e)};`),
89
- ...l.map((e) => `export * from ${JSON.stringify(e)};`),
90
- ...s.length ? [
91
- "globalThis.__L5E_ISLANDS__ ||= {};",
92
- ...s.map(({ key: e, file: t }) => `globalThis.__L5E_ISLANDS__[${JSON.stringify(e)}] = async () => { const [renderer, module] = await Promise.all([import(${JSON.stringify(c)}), import(${JSON.stringify(t)})]); return { reactDomClient: renderer.reactDomClient, createElement: renderer.createElement, module }; };`),
93
- "globalThis.__L5E_BOOT_ISLANDS__?.();"
94
- ] : []
95
- ].join("\n")), i ? D(t, n.sharedUrl, n.globalUrl) : E(t)],
95
+ plugins: [T([...r.map((e) => n.name === "renderer" ? `export { createElement, reactDomClient } from ${JSON.stringify(e)};` : n.name === "island" ? `import * as __island from ${JSON.stringify(e)}; export * from ${JSON.stringify(e)}; export default __island.default;` : n.name === "shared" ? `export * from ${JSON.stringify(e)};` : `import ${JSON.stringify(e)};`), ...s.map((e) => `export * from ${JSON.stringify(e)};`)].join("\n")), i ? D(t, n.sharedUrl, n.globalUrl, c, l) : E(t)],
96
96
  platform: "neutral",
97
97
  tsconfig: !1,
98
98
  treeshake: { moduleSideEffects: () => !0 },
@@ -110,18 +110,23 @@ async function O(e, t, n = {}) {
110
110
  } finally {
111
111
  await m.close();
112
112
  }
113
- for (let e of h) e.type === "chunk" && b.set(e.fileName, {
114
- content: e.code || "",
115
- hash: C(e.code || ""),
116
- filename: e.fileName,
117
- mimeType: "application/javascript"
118
- });
113
+ for (let e of h) {
114
+ if (e.type !== "chunk") continue;
115
+ let t = (e.code || "").replace(/^\/\/#(?:end)?region[^\r\n]*(?:\r?\n)?/gm, "");
116
+ b.set(e.fileName, {
117
+ content: t,
118
+ hash: C(t),
119
+ filename: e.fileName,
120
+ mimeType: "application/javascript"
121
+ });
122
+ }
119
123
  let g = h.find((e) => e.type === "chunk" && e.isEntry && e.facadeModuleId === w);
120
124
  if (!g) throw Error("[bundler] rolldown produced no entry chunk");
125
+ let _ = b.get(g.fileName);
121
126
  return {
122
- hash: C(g.code || ""),
127
+ hash: _.hash,
123
128
  filename: g.fileName,
124
- content: g.code || ""
129
+ content: _.content
125
130
  };
126
131
  }
127
132
  async function k(e, t, n, r = {}) {
@@ -172,25 +177,45 @@ function M(e) {
172
177
  //#endregion
173
178
  //#region src/core/script-bundle-policy.ts
174
179
  function N(e, t, n = "/", r) {
175
- let i = u.resolve(t), a = h(i), o = /* @__PURE__ */ new Set(), c = /* @__PURE__ */ new Set(), l = /* @__PURE__ */ new Map(), d = Object.entries(e).filter(([, e]) => /\.[cm]?js$/.test(e.file));
176
- function f(e) {
180
+ let i = u.resolve(t), a = h(i), o = /* @__PURE__ */ new Set(), c = /* @__PURE__ */ new Set(), l = /* @__PURE__ */ new Map(), d = /* @__PURE__ */ new Set(), f = Object.entries(e).filter(([, e]) => /\.[cm]?js$/.test(e.file));
181
+ function m(e) {
177
182
  let t = u.resolve(a, e), n = u.relative(a, t);
178
183
  if (!n || n === ".." || n.startsWith(`..${u.sep}`) || u.isAbsolute(n)) throw Error(`[bundler] Asset is outside the client output: ${e}`);
179
184
  return t;
180
185
  }
181
- let m = new Set((r?.chunks || []).filter((e) => r?.mode === "compact" && e.canonicalShared).map((e) => f(e.file))), g = new Set((r?.chunks || []).filter((e) => r?.mode === "compact" && e.canonicalGlobal).map((e) => f(e.file)));
182
- for (let [e, t] of d) {
183
- let n = f(t.file);
186
+ let g = new Set((r?.chunks || []).filter((e) => r?.mode === "compact" && e.canonicalShared).map((e) => m(e.file))), _ = new Set((r?.chunks || []).filter((e) => r?.mode === "compact" && e.canonicalGlobal).map((e) => m(e.file)));
187
+ for (let [e, t] of f) {
188
+ let n = m(t.file);
184
189
  o.add(n), (!t.isEntry || t.isDynamicEntry || e === "src/client.global.ts" || /(?:^|\/)react\//.test(t.src || e)) && c.add(n);
185
190
  }
186
- for (let [, t] of d) {
191
+ for (let [, t] of f) {
187
192
  for (let n of [...t.imports || [], ...t.dynamicImports || []]) {
188
193
  let t = e[n];
189
- if (!t || !o.has(f(t.file))) throw Error(`[bundler] Missing JavaScript manifest dependency: ${n}`);
190
- c.add(f(t.file));
194
+ if (!t || !o.has(m(t.file))) throw Error(`[bundler] Missing JavaScript manifest dependency: ${n}`);
195
+ c.add(m(t.file));
191
196
  }
192
- l.set(f(t.file), (t.imports || []).map((t) => f(e[t].file)));
197
+ l.set(m(t.file), (t.imports || []).map((t) => m(e[t].file)));
193
198
  }
199
+ let v = /* @__PURE__ */ new Set(), y = (t) => {
200
+ let n = e[t];
201
+ if (!n || !/\.[cm]?js$/.test(n.file)) return;
202
+ let r = m(n.file);
203
+ if (!v.has(r)) {
204
+ v.add(r);
205
+ for (let e of n.imports || []) y(e);
206
+ }
207
+ };
208
+ for (let [e, t] of f) t.isEntry && !t.isDynamicEntry && y(e);
209
+ let b = (t) => {
210
+ let n = e[t];
211
+ if (!n || !/\.[cm]?js$/.test(n.file)) return;
212
+ let r = m(n.file);
213
+ if (!(d.has(r) || v.has(r))) {
214
+ d.add(r);
215
+ for (let e of n.imports || []) b(e);
216
+ }
217
+ };
218
+ for (let [, e] of f) for (let t of e.dynamicImports || []) b(t);
194
219
  return {
195
220
  cacheKey: p("sha256").update(JSON.stringify([
196
221
  i,
@@ -201,28 +226,40 @@ function N(e, t, n = "/", r) {
201
226
  compact: r?.mode === "compact",
202
227
  directory: i,
203
228
  fileForScript(e) {
204
- let t = n === "/" ? "/" : `/${n.replace(/^\/+|\/+$/g, "")}/`, r = f(e.startsWith(t) ? e.slice(t.length) : e.replace(/^\/+/, ""));
229
+ let t = n === "/" ? "/" : `/${n.replace(/^\/+|\/+$/g, "")}/`, r = m(e.startsWith(t) ? e.slice(t.length) : e.replace(/^\/+/, ""));
205
230
  if (!o.has(r)) throw Error(`[bundler] Script is missing from manifest: ${e}`);
206
231
  return r;
207
232
  },
208
233
  fileForAssetUrl(e) {
209
- let t = n === "/" ? "/" : `/${n.replace(/^\/+|\/+$/g, "")}/`, r = f(e.startsWith(t) ? e.slice(t.length) : e.replace(/^\/+/, ""));
234
+ let t = n === "/" ? "/" : `/${n.replace(/^\/+|\/+$/g, "")}/`, r = m(e.startsWith(t) ? e.slice(t.length) : e.replace(/^\/+/, ""));
210
235
  return o.has(r) ? r : void 0;
211
236
  },
212
237
  isPreserved(e) {
213
238
  return c.has(e);
214
239
  },
215
240
  isShared(e) {
216
- return m.has(e);
241
+ return g.has(e);
217
242
  },
218
243
  isGlobalOwned(e) {
219
- return g.has(e);
244
+ return _.has(e);
245
+ },
246
+ isLazy(e) {
247
+ return d.has(e);
248
+ },
249
+ staticClosure(e) {
250
+ let t = /* @__PURE__ */ new Set(), n = (e) => {
251
+ if (!t.has(e)) {
252
+ t.add(e);
253
+ for (let t of l.get(e) || []) n(t);
254
+ }
255
+ };
256
+ return e.forEach(n), t;
220
257
  },
221
258
  sharedScripts() {
222
- return [...m].map((e) => s(n, u.relative(a, e).replace(/\\/g, "/")));
259
+ return [...g].map((e) => s(n, u.relative(a, e).replace(/\\/g, "/")));
223
260
  },
224
261
  globalOwnedScripts() {
225
- return [...g].map((e) => s(n, u.relative(a, e).replace(/\\/g, "/")));
262
+ return [..._].map((e) => s(n, u.relative(a, e).replace(/\\/g, "/")));
226
263
  },
227
264
  inlineableRoots(e) {
228
265
  let t = /* @__PURE__ */ new Set(), n = 0;
@@ -359,6 +396,10 @@ async function W({ rendered: e, template: t, manifest: r, root: i, distClientDir
359
396
  if (!n.filename) throw Error("[l5e chunking] Compact global bundle failed.");
360
397
  t = s(d, n.filename), T.push(t);
361
398
  }
399
+ let o = {};
400
+ if (e) for (let t of n) o[t] = e;
401
+ if (t) for (let e of f.globalOwnedScripts()) o[e] = t;
402
+ Object.keys(o).length > 0 && (S += `<script type="importmap">${(0, g.default)({ imports: o })}<\/script>`);
362
403
  }
363
404
  m = m.filter((e) => e.replace(/^\//, "") !== "src/client.global.ts"), h = h.filter((e) => !e.includes(".global."));
364
405
  let i = /* @__PURE__ */ new Set(), o = /* @__PURE__ */ new Set(), c = /* @__PURE__ */ new Set();
@@ -375,46 +416,97 @@ async function W({ rendered: e, template: t, manifest: r, root: i, distClientDir
375
416
  }
376
417
  return { file: t.file };
377
418
  }
378
- let u = [];
419
+ function u(e, t = /* @__PURE__ */ new Set()) {
420
+ let n = /* @__PURE__ */ new Set(), i = /* @__PURE__ */ new Set(), a = /* @__PURE__ */ new Set(), o = (e) => {
421
+ if (a.has(e)) return;
422
+ a.add(e);
423
+ let c = r[e];
424
+ if (c) {
425
+ for (let e of c.css || []) i.add(s(d, e));
426
+ if (!t.has(e) && c.file && /\.[cm]?js$/.test(c.file)) {
427
+ let e = f.fileForScript(`/${c.file}`);
428
+ !f.isShared(e) && !f.isGlobalOwned(e) && n.add(s(d, c.file));
429
+ }
430
+ for (let e of c.imports || []) o(e);
431
+ }
432
+ };
433
+ return e.forEach(o), {
434
+ js: [...n],
435
+ css: [...i]
436
+ };
437
+ }
438
+ let p = [];
379
439
  for (let e of m) {
380
440
  let { file: t } = l(e.replace(/^\//, ""));
381
- t && u.push(`/${t}`);
441
+ t && p.push(`/${t}`);
382
442
  }
383
- let p = [];
443
+ let v = [];
384
444
  for (let e of h) {
385
445
  let { file: t } = l(e.replace(/^\//, ""));
386
- t && (p.push(`/${t}`), i.add(t));
446
+ t && (v.push(`/${t}`), i.add(t));
387
447
  }
388
- if (u.length > 0 || f?.compact && _.length > 0) {
389
- let n = f?.compact ? _.flatMap((e) => {
390
- let t = r[e.src];
391
- return t?.file ? [{
392
- key: e.key,
393
- script: `/${t.file}`
394
- }] : [];
395
- }) : [], i = f?.compact ? Object.entries(r).find(([e]) => e.includes("l5e-compact-renderer"))?.[1]?.file : void 0;
396
- if (f?.compact && n.length > 0 && !i) throw Error("[l5e chunking] Compact renderer entry is missing from the manifest.");
397
- let o = await k(u, a, f, {
448
+ if (p.length > 0) {
449
+ let n = await k(p, a, f, {
398
450
  compact: f?.compact,
399
- islands: n,
400
451
  name: "bundle",
401
452
  sharedUrl: e,
402
- renderer: i ? `/${i}` : void 0,
403
453
  globalUrl: t
404
454
  });
405
- m = o.filename ? [s(d, o.filename)] : u.map((e) => s(d, e));
455
+ m = n.filename ? [s(d, n.filename)] : p.map((e) => s(d, e));
456
+ }
457
+ if (f?.compact && _.length > 0) {
458
+ let n = Object.entries(r).find(([e, t]) => t.isEntry && e.includes("l5e-compact-renderer"));
459
+ if (!n?.[1].file) throw Error("[l5e chunking] Compact renderer entry is missing from the manifest.");
460
+ let i = /* @__PURE__ */ new Set();
461
+ i.add(n[0]);
462
+ let o = (n[1].imports || []).filter((e) => r[e]?.file?.includes("compact-renderer"));
463
+ if (o.length !== 1) throw Error(`[l5e chunking] Compact renderer expected one canonical export chunk; found ${o.length}. Multiple chunks can have colliding emitted export aliases.`);
464
+ i.add(o[0]);
465
+ let c = await k([`/${n[1].file}`], a, f, {
466
+ compact: !0,
467
+ name: "renderer",
468
+ sharedUrl: e,
469
+ globalUrl: t,
470
+ inlineStaticRootClosure: !0,
471
+ exportScripts: [...i].filter((e) => e !== n[0]).map((e) => `/${r[e].file}`)
472
+ });
473
+ if (!c.filename) throw Error("[l5e chunking] Compact renderer bundle failed.");
474
+ let l = s(d, c.filename), p = Object.fromEntries([...i].filter((e) => r[e]?.file).map((e) => [`/${r[e].file}`, l])), m = Object.fromEntries([...i].filter((e) => r[e]?.file).map((e) => [s(d, r[e].file), l]));
475
+ Object.keys(m).length > 0 && (S += `<script type="importmap">${(0, g.default)({ imports: m })}<\/script>`);
476
+ let h = {};
477
+ for (let n of _) {
478
+ let o = r[n.src];
479
+ if (!o?.file) continue;
480
+ let c = await k([`/${o.file}`], a, f, {
481
+ compact: !0,
482
+ name: "island",
483
+ sharedUrl: e,
484
+ globalUrl: t,
485
+ inlineStaticRootClosure: !0,
486
+ externalScripts: p
487
+ });
488
+ if (!c.filename) throw Error(`[l5e chunking] Compact island bundle failed: ${n.src}`);
489
+ let m = s(d, c.filename), g = u([n.src], i);
490
+ h[n.key] = {
491
+ module: m,
492
+ renderer: l,
493
+ js: [l, m],
494
+ css: g.css
495
+ };
496
+ }
497
+ E = `<script>Object.assign(window.__L5E_ISLANDS__||={},${(0, g.default)(h)});window.__L5E_BOOT_ISLANDS__?.()<\/script>`;
406
498
  }
407
499
  if (i.size > 0) {
408
500
  let e = await j([...i].map((e) => `/${e}`), a);
409
501
  e.filename && (h = [s(d, e.filename)]);
410
502
  }
411
503
  i.clear();
412
- let v = r["src/client.global.ts"];
504
+ let y = r["src/client.global.ts"];
413
505
  l("src/client.global.ts");
414
506
  for (let e of i) w(s(d, e), !0);
415
- v && (v.css && v.css.length > 0 && v.css.forEach((e) => {
507
+ y && (y.css && y.css.length > 0 && y.css.forEach((e) => {
416
508
  w(s(d, e), !0);
417
- }), v.file && (f?.compact || T.push(s(d, v.file))));
509
+ }), y.file && (f?.compact || T.push(s(d, y.file))));
418
510
  for (let e of f?.compact ? [] : o) S += `<link rel="modulepreload" crossorigin href="${n(s(d, e))}">`;
419
511
  if (_.length > 0 && !f?.compact) {
420
512
  let e = {};
@@ -460,7 +552,9 @@ async function G(e = {}) {
460
552
  h.use(e()), h.use(n, t(_, { extensions: [] })), h.get([
461
553
  s(n, "global-:hash.:ext"),
462
554
  s(n, "bundle-:hash.:ext"),
463
- s(n, "shared-:hash.:ext")
555
+ s(n, "shared-:hash.:ext"),
556
+ s(n, "renderer-:hash.:ext"),
557
+ s(n, "island-:hash.:ext")
464
558
  ], async (e, t) => {
465
559
  try {
466
560
  let { hash: n, ext: r } = e.params, i = M(`${u.basename(e.path).split("-", 1)[0]}-${n}.${r}`);
@@ -613,4 +707,4 @@ function Y(e) {
613
707
  //#endregion
614
708
  export { K as a, Y as i, G as n, J as r, P as t };
615
709
 
616
- //# sourceMappingURL=server-BOdEiJoN.js.map
710
+ //# sourceMappingURL=server-C35BtVu8.js.map