@withl5e/l5e 1.1.0-alpha.1 → 1.1.0-alpha.2
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 +29 -0
- package/dist/index.js +2 -2
- package/dist/island/compact-runtime.js +20 -3
- package/dist/island/compact-runtime.js.map +1 -1
- package/dist/{server-BOdEiJoN.js → server-C35BtVu8.js} +157 -63
- package/dist/server-C35BtVu8.js.map +1 -0
- package/dist/server.js +1 -1
- package/dist/{vite-plugin-R3LFxv9a.js → vite-plugin-BOuzxmb2.js} +82 -64
- package/dist/vite-plugin-BOuzxmb2.js.map +1 -0
- package/dist/vite-plugin.js +1 -1
- package/package.json +1 -1
- package/src/core/bundler.ts +31 -18
- package/src/core/chunking.ts +52 -2
- package/src/core/script-bundle-policy.ts +42 -0
- package/src/core/server.ts +117 -16
- package/src/core/vite-plugin.ts +12 -2
- package/src/island/compact-runtime.ts +44 -7
- package/dist/server-BOdEiJoN.js.map +0 -1
- package/dist/vite-plugin-R3LFxv9a.js.map +0 -1
package/README.md
CHANGED
|
@@ -22,3 +22,32 @@ 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:
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
coreVite({
|
|
30
|
+
chunking: {
|
|
31
|
+
mode: 'compact',
|
|
32
|
+
shared: [{ name: 'state', modules: ['~/stores/session.ts'] }],
|
|
33
|
+
islandRuntime: {
|
|
34
|
+
packages: ['@tanstack/react-query'],
|
|
35
|
+
modules: ['~/client/query-client.ts'],
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Compact mode limits the initial shell and each later island/action activation to
|
|
42
|
+
at most three new JavaScript assets. `load` and already-visible islands activate
|
|
43
|
+
immediately after the shell, so the cumulative cold request count can be higher.
|
|
44
|
+
The runtime starts every known static dependency request in parallel, waits for
|
|
45
|
+
the island CSS, then evaluates and mounts or hydrates. Dynamic descendants remain
|
|
46
|
+
lazy. List state that must survive page-bundle swaps in `shared`; list React
|
|
47
|
+
contexts or client caches that multiple islands must share in `islandRuntime`.
|
|
48
|
+
Only the configured static closure is included, and dynamic imports are not
|
|
49
|
+
promoted. Compact mode requires native import-map support.
|
|
50
|
+
|
|
51
|
+
The alpha renderer bridge expects Vite to emit one entry facade and one canonical
|
|
52
|
+
renderer export chunk. A different renderer shape is rejected during server setup
|
|
53
|
+
because merging multiple minified export namespaces can make aliases ambiguous.
|
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-
|
|
8
|
-
import { t as U } from "./vite-plugin-
|
|
7
|
+
import { a as V, n as H } from "./server-C35BtVu8.js";
|
|
8
|
+
import { t as U } from "./vite-plugin-BOuzxmb2.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
|
|
60
|
-
|
|
61
|
-
|
|
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,
|
|
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(
|
|
69
|
-
if (!
|
|
70
|
-
let
|
|
71
|
-
return
|
|
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(
|
|
77
|
+
} : e.isGlobalOwned(s) && n ? {
|
|
75
78
|
id: n,
|
|
76
79
|
external: "absolute"
|
|
77
|
-
} :
|
|
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}`]] : []))
|
|
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
|
-
})),
|
|
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)
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
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:
|
|
127
|
+
hash: _.hash,
|
|
123
128
|
filename: g.fileName,
|
|
124
|
-
content:
|
|
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
|
|
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
|
|
182
|
-
for (let [e, t] of
|
|
183
|
-
let n =
|
|
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
|
|
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(
|
|
190
|
-
c.add(
|
|
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(
|
|
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 =
|
|
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 =
|
|
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
|
|
241
|
+
return g.has(e);
|
|
217
242
|
},
|
|
218
243
|
isGlobalOwned(e) {
|
|
219
|
-
return
|
|
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 [...
|
|
259
|
+
return [...g].map((e) => s(n, u.relative(a, e).replace(/\\/g, "/")));
|
|
223
260
|
},
|
|
224
261
|
globalOwnedScripts() {
|
|
225
|
-
return [...
|
|
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
|
-
|
|
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 &&
|
|
441
|
+
t && p.push(`/${t}`);
|
|
382
442
|
}
|
|
383
|
-
let
|
|
443
|
+
let v = [];
|
|
384
444
|
for (let e of h) {
|
|
385
445
|
let { file: t } = l(e.replace(/^\//, ""));
|
|
386
|
-
t && (
|
|
446
|
+
t && (v.push(`/${t}`), i.add(t));
|
|
387
447
|
}
|
|
388
|
-
if (
|
|
389
|
-
let n =
|
|
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 =
|
|
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
|
|
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
|
-
|
|
507
|
+
y && (y.css && y.css.length > 0 && y.css.forEach((e) => {
|
|
416
508
|
w(s(d, e), !0);
|
|
417
|
-
}),
|
|
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-
|
|
710
|
+
//# sourceMappingURL=server-C35BtVu8.js.map
|