@withl5e/l5e 1.0.1 → 1.1.0-alpha.1
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/dist/index.js +2 -2
- package/dist/island/compact-runtime.js +81 -0
- package/dist/island/compact-runtime.js.map +1 -0
- package/dist/island/runtime.js +7 -3
- package/dist/island/runtime.js.map +1 -1
- package/dist/{server-DXNRPyGJ.js → server-BOdEiJoN.js} +213 -115
- package/dist/server-BOdEiJoN.js.map +1 -0
- package/dist/server.js +1 -1
- package/dist/vite-plugin-R3LFxv9a.js +497 -0
- package/dist/vite-plugin-R3LFxv9a.js.map +1 -0
- package/dist/vite-plugin.js +2 -333
- package/package.json +7 -1
- package/src/core/bundler.ts +77 -7
- package/src/core/chunking.ts +256 -0
- package/src/core/script-bundle-policy.ts +57 -2
- package/src/core/server.ts +109 -28
- package/src/core/vite-plugin.ts +93 -8
- package/src/island/compact-runtime.ts +121 -0
- package/src/island/runtime.ts +22 -8
- package/dist/server-DXNRPyGJ.js.map +0 -1
- package/dist/vite-plugin.js.map +0 -1
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 {
|
|
7
|
+
import { a as V, n as H } from "./server-BOdEiJoN.js";
|
|
8
|
+
import { t as U } from "./vite-plugin-R3LFxv9a.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 };
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { n as e, t } from "../strategy-registry-wmHnsHQb.js";
|
|
2
|
+
import "virtual:l5e-island-strategies";
|
|
3
|
+
t("load", (e) => void e()), t("idle", (e) => {
|
|
4
|
+
"requestIdleCallback" in window ? requestIdleCallback(() => e()) : setTimeout(() => e(), 200);
|
|
5
|
+
}), t("visible", (e, t, n) => {
|
|
6
|
+
let r = new IntersectionObserver((t) => {
|
|
7
|
+
t.some((e) => e.isIntersecting) && (r.disconnect(), e());
|
|
8
|
+
}, { rootMargin: t || "200px" });
|
|
9
|
+
return r.observe(n), () => r.disconnect();
|
|
10
|
+
}), t("media", (e, t) => {
|
|
11
|
+
if (!t) {
|
|
12
|
+
console.error("[l5e-island] Strategy \"media\" requires mountOpts (media query)");
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
let n = window.matchMedia(t);
|
|
16
|
+
if (n.matches) e();
|
|
17
|
+
else {
|
|
18
|
+
let t = (t) => t.matches && e();
|
|
19
|
+
return n.addEventListener("change", t, { once: !0 }), () => n.removeEventListener("change", t);
|
|
20
|
+
}
|
|
21
|
+
}), t("none", () => {});
|
|
22
|
+
var n = window.__L5E_ISLANDS__ ||= {}, r = null, i = /* @__PURE__ */ new WeakSet();
|
|
23
|
+
function a(e) {
|
|
24
|
+
let t = e.getAttribute("data-island-idx");
|
|
25
|
+
if (t === null) return JSON.parse(e.getAttribute("data-island-props") || "{}");
|
|
26
|
+
if (!r) {
|
|
27
|
+
let e = document.getElementById("_l5e_data_");
|
|
28
|
+
try {
|
|
29
|
+
let t = JSON.parse(e?.textContent || "[]");
|
|
30
|
+
r = Array.isArray(t) ? t : [];
|
|
31
|
+
} catch (e) {
|
|
32
|
+
console.error("[l5e-island] Failed to parse _l5e_data_ props store:", e), r = [];
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return r[Number(t)] || {};
|
|
36
|
+
}
|
|
37
|
+
function o() {
|
|
38
|
+
return Array.from(document.querySelectorAll("[data-island]")).map((e) => ({
|
|
39
|
+
element: e,
|
|
40
|
+
registryKey: e.getAttribute("data-island"),
|
|
41
|
+
exportName: e.getAttribute("data-island-name"),
|
|
42
|
+
props: a(e),
|
|
43
|
+
mount: e.getAttribute("data-island-mount") || "load",
|
|
44
|
+
mountOpts: e.getAttribute("data-island-opts") || void 0,
|
|
45
|
+
ssr: e.hasAttribute("data-island-ssr")
|
|
46
|
+
}));
|
|
47
|
+
}
|
|
48
|
+
function s(e) {
|
|
49
|
+
let t = !1;
|
|
50
|
+
return async () => {
|
|
51
|
+
if (t) return;
|
|
52
|
+
t = !0;
|
|
53
|
+
let r = n[e.registryKey];
|
|
54
|
+
if (!r) {
|
|
55
|
+
console.error(`[l5e-island] Component "${e.registryKey}" not found in page registry.`);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
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));
|
|
62
|
+
} catch (t) {
|
|
63
|
+
console.error(`[l5e-island] Failed to mount "${e.registryKey}":`, t);
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
function c() {
|
|
68
|
+
for (let t of o()) {
|
|
69
|
+
if (i.has(t.element) || !n[t.registryKey]) continue;
|
|
70
|
+
let r = e.get(t.mount);
|
|
71
|
+
if (!r) {
|
|
72
|
+
console.error(`[l5e-island] Strategy "${t.mount}" not found.`);
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
i.add(t.element), r(s(t), t.mountOpts, t.element);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
globalThis.__L5E_BOOT_ISLANDS__ = c, document.readyState === "loading" ? document.addEventListener("DOMContentLoaded", c) : c();
|
|
79
|
+
//#endregion
|
|
80
|
+
|
|
81
|
+
//# sourceMappingURL=compact-runtime.js.map
|
|
@@ -0,0 +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":";;AAGA,EAAsB,SAAS,MAAU,KAAK,EAAM,CAAC,GACrD,EAAsB,SAAS,MAAU;CACvC,AAAI,yBAAyB,SAAQ,0BAA0B,EAAM,CAAC,IACjE,iBAAiB,EAAM,GAAG,GAAG;AACpC,CAAC,GACD,EAAsB,YAAY,GAAO,GAAM,MAAO;CACpD,IAAM,IAAW,IAAI,sBAClB,MAAY;EACX,AAAI,EAAQ,MAAM,MAAU,EAAM,cAAc,MAC9C,EAAS,WAAW,GACpB,EAAM;CAEV,GACA,EAAE,YAAY,KAAQ,QAAQ,CAChC;CAEA,OADA,EAAS,QAAQ,CAAE,SACN,EAAS,WAAW;AACnC,CAAC,GACD,EAAsB,UAAU,GAAO,MAAS;CAC9C,IAAI,CAAC,GAAM;EACT,QAAQ,MAAM,kEAAgE;EAC9E;CACF;CACA,IAAM,IAAQ,OAAO,WAAW,CAAI;CACpC,IAAI,EAAM,SAAS,EAAM;MACpB;EACH,IAAM,KAAW,MAA+B,EAAM,WAAW,EAAM;EAEvE,OADA,EAAM,iBAAiB,UAAU,GAAS,EAAE,MAAM,GAAK,CAAC,SAC3C,EAAM,oBAAoB,UAAU,CAAO;CAC1D;AACF,CAAC,GACD,EAAsB,cAAc,CAAC,CAAC;AAStC,IAAM,IAAgE,OACnE,oBAAoB,CAAC,GACpB,IAA+B,MAC7B,oBAAY,IAAI,QAAiB;AAEvC,SAAS,EAAM,GAA2C;CACxD,IAAM,IAAQ,EAAQ,aAAa,iBAAiB;CACpD,IAAI,MAAU,MAAM,OAAO,KAAK,MAAM,EAAQ,aAAa,mBAAmB,KAAK,IAAI;CACvF,IAAI,CAAC,GAAY;EACf,IAAM,IAAQ,SAAS,eAAe,YAAY;EAClD,IAAI;GACF,IAAM,IAAS,KAAK,MAAM,GAAO,eAAe,IAAI;GACpD,IAAa,MAAM,QAAQ,CAAM,IAAI,IAAS,CAAC;EACjD,SAAS,GAAO;GAEd,AADA,QAAQ,MAAM,wDAAwD,CAAK,GAC3E,IAAa,CAAC;EAChB;CACF;CACA,OAAQ,EAAW,OAAO,CAAK,MAAkC,CAAC;AACpE;AAEA,SAAS,IAAyB;CAChC,OAAO,MAAM,KAAK,SAAS,iBAAiB,eAAe,CAAC,CAAC,CAAC,KAAK,OAAa;EACrE;EACT,aAAa,EAAQ,aAAa,aAAa;EAC/C,YAAY,EAAQ,aAAa,kBAAkB;EACnD,OAAO,EAAM,CAAO;EACpB,OAAO,EAAQ,aAAa,mBAAmB,KAAK;EACpD,WAAW,EAAQ,aAAa,kBAAkB,KAAK,KAAA;EACvD,KAAK,EAAQ,aAAa,iBAAiB;CAC7C,EAAE;AACJ;AAEA,SAAS,EAAM,GAAoB;CACjC,IAAI,IAAU;CACd,OAAO,YAAY;EACjB,IAAI,GAAS;EACb,IAAU;EACV,IAAM,IAAS,EAAS,EAAO;EAC/B,IAAI,CAAC,GAAQ;GACX,QAAQ,MAAM,2BAA2B,EAAO,YAAY,8BAA8B;GAC1F;EACF;EACA,IAAI;GACF,IAAM,EAAE,mBAAgB,kBAAe,cAAW,MAAM,EAAO,GACzD,IAAY,EAAO,WAAW,EAAO,EAAO;GAClD,IAAI,CAAC,GAAW,MAAU,MAAM,2BAA2B,EAAO,WAAW,YAAY;GACzF,AAAI,EAAO,MACT,EAAe,YAAY,EAAO,SAAS,EAAc,GAAW,EAAO,KAAK,CAAC,IAGjF,EAD4B,WAAW,EAAO,OAC3C,CAAC,CAAC,OAAO,EAAc,GAAW,EAAO,KAAK,CAAC;EAEtD,SAAS,GAAO;GACd,QAAQ,MAAM,iCAAiC,EAAO,YAAY,KAAK,CAAK;EAC9E;CACF;AACF;AAEA,SAAS,IAAO;CACd,KAAK,IAAM,KAAU,EAAS,GAAG;EAI/B,IAHI,EAAU,IAAI,EAAO,OAAO,KAG5B,CAAC,EAAS,EAAO,cAAc;EACnC,IAAM,IAAW,EAAW,IAAI,EAAO,KAAK;EAC5C,IAAI,CAAC,GAAU;GACb,QAAQ,MAAM,0BAA0B,EAAO,MAAM,aAAa;GAClE;EACF;EAEA,AADA,EAAU,IAAI,EAAO,OAAO,GAC5B,EAAS,EAAM,CAAM,GAAG,EAAO,WAAW,EAAO,OAAO;CAC1D;AACF;AAEA,WAAoB,uBAAuB,GACvC,SAAS,eAAe,YAAW,SAAS,iBAAiB,oBAAoB,CAAI,IACpF,EAAK"}
|
package/dist/island/runtime.js
CHANGED
|
@@ -25,7 +25,7 @@ t("load", (e) => {
|
|
|
25
25
|
return n.addEventListener("change", t, { once: !0 }), () => n.removeEventListener("change", t);
|
|
26
26
|
}
|
|
27
27
|
}), t("none", () => {});
|
|
28
|
-
var n = window.__L5E_ISLANDS__
|
|
28
|
+
var n = window.__L5E_ISLANDS__ ||= {}, r = null;
|
|
29
29
|
function i() {
|
|
30
30
|
if (r) return r;
|
|
31
31
|
let e = document.getElementById("_l5e_data_");
|
|
@@ -64,14 +64,18 @@ function s(e) {
|
|
|
64
64
|
return;
|
|
65
65
|
}
|
|
66
66
|
try {
|
|
67
|
-
let
|
|
67
|
+
let { reactDomClient: t, createElement: n, module: i } = typeof r == "function" ? await r() : await Promise.all([
|
|
68
68
|
import("react-dom/client"),
|
|
69
69
|
import("react"),
|
|
70
70
|
import(
|
|
71
71
|
/* @vite-ignore */
|
|
72
72
|
r
|
|
73
73
|
)
|
|
74
|
-
]),
|
|
74
|
+
]).then(([e, t, n]) => ({
|
|
75
|
+
reactDomClient: e,
|
|
76
|
+
createElement: t.createElement,
|
|
77
|
+
module: n
|
|
78
|
+
})), a = i.default || i[e.exportName];
|
|
75
79
|
if (!a) {
|
|
76
80
|
console.error(`[l5e-island] No export "default" or "${e.exportName}" in module`);
|
|
77
81
|
return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.js","names":[],"sources":["../../src/island/runtime.ts"],"sourcesContent":["import type { IslandMeta } from './types';\nimport { strategies, registerMountStrategy } from './strategy-registry';\n\n// ============================================================\n// PART 1: Built-in strategies\n// ============================================================\n\nregisterMountStrategy('load', (mount) => {\n mount();\n});\n\nregisterMountStrategy('idle', (mount) => {\n if ('requestIdleCallback' in window) {\n requestIdleCallback(() => mount());\n } else {\n setTimeout(() => mount(), 200);\n }\n});\n\nregisterMountStrategy('visible', (mount, opts, el) => {\n const rootMargin = opts || '200px';\n const observer = new IntersectionObserver(\n (entries) => {\n entries.forEach((entry) => {\n if (entry.isIntersecting) {\n observer.disconnect();\n mount();\n }\n });\n },\n { rootMargin },\n );\n observer.observe(el);\n return () => observer.disconnect();\n});\n\nregisterMountStrategy('media', (mount, opts) => {\n if (!opts) {\n console.error('[l5e-island] Strategy \"media\" requires mountOpts (media query)');\n return;\n }\n const mql = window.matchMedia(opts);\n if (mql.matches) {\n mount();\n } else {\n const handler = (e: MediaQueryListEvent) => {\n if (e.matches) mount();\n };\n mql.addEventListener('change', handler, { once: true });\n return () => mql.removeEventListener('change', handler);\n }\n});\n\nregisterMountStrategy('none', () => {\n // Don't mount - keep placeholder as-is\n});\n\n// ============================================================\n// PART 2: Import custom strategies (if any)\n// ============================================================\n\nimport 'virtual:l5e-island-strategies';\n\n// ============================================================\n// PART 3: Island discovery + mount logic\n// ============================================================\n\n// Per-page island registry injected by server.ts as inline script\n// Format: { \"Counter_a3f2\": \"/assets/Counter-Abc123.js\" }\nconst islandRegistry: Record<string,
|
|
1
|
+
{"version":3,"file":"runtime.js","names":[],"sources":["../../src/island/runtime.ts"],"sourcesContent":["import type { IslandMeta } from './types';\nimport { strategies, registerMountStrategy } from './strategy-registry';\n\n// ============================================================\n// PART 1: Built-in strategies\n// ============================================================\n\nregisterMountStrategy('load', (mount) => {\n mount();\n});\n\nregisterMountStrategy('idle', (mount) => {\n if ('requestIdleCallback' in window) {\n requestIdleCallback(() => mount());\n } else {\n setTimeout(() => mount(), 200);\n }\n});\n\nregisterMountStrategy('visible', (mount, opts, el) => {\n const rootMargin = opts || '200px';\n const observer = new IntersectionObserver(\n (entries) => {\n entries.forEach((entry) => {\n if (entry.isIntersecting) {\n observer.disconnect();\n mount();\n }\n });\n },\n { rootMargin },\n );\n observer.observe(el);\n return () => observer.disconnect();\n});\n\nregisterMountStrategy('media', (mount, opts) => {\n if (!opts) {\n console.error('[l5e-island] Strategy \"media\" requires mountOpts (media query)');\n return;\n }\n const mql = window.matchMedia(opts);\n if (mql.matches) {\n mount();\n } else {\n const handler = (e: MediaQueryListEvent) => {\n if (e.matches) mount();\n };\n mql.addEventListener('change', handler, { once: true });\n return () => mql.removeEventListener('change', handler);\n }\n});\n\nregisterMountStrategy('none', () => {\n // Don't mount - keep placeholder as-is\n});\n\n// ============================================================\n// PART 2: Import custom strategies (if any)\n// ============================================================\n\nimport 'virtual:l5e-island-strategies';\n\n// ============================================================\n// PART 3: Island discovery + mount logic\n// ============================================================\n\n// Per-page island registry injected by server.ts as inline script\n// Format: { \"Counter_a3f2\": \"/assets/Counter-Abc123.js\" }\ntype CompactIslandModule = {\n reactDomClient: typeof import('react-dom/client');\n createElement: typeof import('react').createElement;\n module: Record<string, any>;\n};\ntype IslandLoader = string | (() => Promise<CompactIslandModule>);\nconst islandRegistry: Record<string, IslandLoader> = ((window as any).__L5E_ISLANDS__ ||= {});\n\n// Props for islands rendered in externalized mode live in a single\n// `<script type=\"application/json\" id=\"_l5e_data_\">` at the end of the document\n// (keeps the SSR body lean for crawlers). Parsed once, lazily.\nlet islandDataCache: unknown[] | null = null;\nfunction getIslandData(): unknown[] {\n if (islandDataCache) return islandDataCache;\n const el = document.getElementById('_l5e_data_');\n if (!el || !el.textContent) return (islandDataCache = []);\n try {\n const parsed = JSON.parse(el.textContent);\n islandDataCache = Array.isArray(parsed) ? parsed : [];\n } catch (err) {\n console.error('[l5e-island] Failed to parse _l5e_data_ props store:', err);\n islandDataCache = [];\n }\n return islandDataCache;\n}\n\nfunction readProps(el: Element): Record<string, unknown> {\n const idx = el.getAttribute('data-island-idx');\n if (idx !== null) {\n return (getIslandData()[Number(idx)] as Record<string, unknown>) || {};\n }\n return JSON.parse(el.getAttribute('data-island-props') || '{}');\n}\n\nfunction discoverIslands(): IslandMeta[] {\n return Array.from(document.querySelectorAll('[data-island]')).map((el) => ({\n element: el as HTMLElement,\n registryKey: el.getAttribute('data-island')!,\n exportName: el.getAttribute('data-island-name')!,\n props: readProps(el),\n mount: el.getAttribute('data-island-mount') || 'load',\n mountOpts: el.getAttribute('data-island-opts') || undefined,\n ssr: el.hasAttribute('data-island-ssr'),\n }));\n}\n\nfunction createMountFn(island: IslandMeta): () => Promise<void> {\n let mounted = false;\n return async () => {\n if (mounted) return;\n mounted = true;\n\n // Look up component URL from per-page registry\n const loader = islandRegistry[island.registryKey];\n if (!loader) {\n console.error(\n `[l5e-island] Component \"${island.registryKey}\" not found in page registry.`,\n `Available: ${Object.keys(islandRegistry).join(', ')}`,\n );\n return;\n }\n\n try {\n const loaded =\n typeof loader === 'function'\n ? await loader()\n : await Promise.all([\n import('react-dom/client'),\n import('react'),\n import(/* @vite-ignore */ loader),\n ]).then(([reactDomClient, react, module]) => ({\n reactDomClient,\n createElement: react.createElement,\n module,\n }));\n const { reactDomClient, createElement, module: mod } = loaded;\n\n const Component = mod.default || mod[island.exportName];\n if (!Component) {\n console.error(`[l5e-island] No export \"default\" or \"${island.exportName}\" in module`);\n return;\n }\n\n if (island.ssr) {\n // Server already rendered this component into the element → hydrate it.\n reactDomClient.hydrateRoot(island.element, createElement(Component, island.props));\n } else {\n // Client-only mount (default): fresh render into an empty placeholder.\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 scheduleMount(island: IslandMeta) {\n const strategy = strategies.get(island.mount);\n\n if (!strategy) {\n console.error(\n `[l5e-island] Strategy \"${island.mount}\" not found.`,\n `Available: ${[...strategies.keys()].join(', ')}`,\n `\\nDid you forget to registerMountStrategy(\"${island.mount}\", ...)?`,\n );\n return;\n }\n\n const mountFn = createMountFn(island);\n strategy(mountFn, island.mountOpts, island.element);\n}\n\n// ============================================================\n// PART 4: Boot\n// ============================================================\n\nfunction boot() {\n const islands = discoverIslands();\n islands.forEach(scheduleMount);\n}\n\nif (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', boot);\n} else {\n boot();\n}\n"],"mappings":"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"}
|