@useavalon/avalon 0.1.66 → 0.1.68
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/src/build/bundle-audit.d.ts +68 -0
- package/dist/src/build/bundle-audit.js +2 -2
- package/dist/src/build/island-client-bundler.d.ts +2 -1
- package/dist/src/build/island-client-bundler.js +3 -3
- package/dist/src/islands/per-island-script.js +1 -1
- package/dist/src/post-build/index.js +4 -4
- package/dist/src/post-build/isolated-island-builder.d.ts +28 -9
- package/dist/src/post-build/isolated-island-builder.js +3 -4
- package/dist/src/vite-plugin/nitro-integration.js +1 -1
- package/package.json +1 -1
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
* @module build/bundle-audit
|
|
12
12
|
*/
|
|
13
13
|
import type { Plugin } from "vite";
|
|
14
|
+
import { z } from "zod";
|
|
14
15
|
/** Represents a single chunk in the build output. */
|
|
15
16
|
export interface ChunkInfo {
|
|
16
17
|
fileName: string;
|
|
@@ -42,6 +43,14 @@ export interface DuplicatedModule {
|
|
|
42
43
|
/** File names of chunks containing this module. */
|
|
43
44
|
chunks: string[];
|
|
44
45
|
}
|
|
46
|
+
/** Per-framework size thresholds for island chunks (in bytes). */
|
|
47
|
+
export interface PerFrameworkThresholds {
|
|
48
|
+
solid: number;
|
|
49
|
+
preact: number;
|
|
50
|
+
react: number;
|
|
51
|
+
vue: number;
|
|
52
|
+
svelte: number;
|
|
53
|
+
}
|
|
45
54
|
/** Options for the bundle audit Vite plugin. */
|
|
46
55
|
export interface BundleAuditOptions {
|
|
47
56
|
/** Maximum allowed size (in bytes) for any single island chunk. Default: 20480 (20 KiB). */
|
|
@@ -52,11 +61,69 @@ export interface BundleAuditOptions {
|
|
|
52
61
|
logReport?: boolean;
|
|
53
62
|
/** Whether to emit warnings for oversized chunks. Default: true. */
|
|
54
63
|
warnOnOversized?: boolean;
|
|
64
|
+
/** Per-framework size thresholds for island chunks. When provided, islands are also checked against their framework-specific limit. */
|
|
65
|
+
perFrameworkThresholds?: Partial<PerFrameworkThresholds>;
|
|
66
|
+
/** Path to the benchmark baseline JSON file. When set, enables benchmark comparison mode. */
|
|
67
|
+
benchmarkBaseline?: string;
|
|
68
|
+
/** Maximum allowed regression in bytes before flagging. Default: 500. */
|
|
69
|
+
regressionThreshold?: number;
|
|
70
|
+
}
|
|
71
|
+
/** Zod schema for the benchmark baseline file used to track island bundle sizes over time. */
|
|
72
|
+
export declare const BenchmarkBaselineSchema: z.ZodObject<{
|
|
73
|
+
version: z.ZodNumber;
|
|
74
|
+
timestamp: z.ZodString;
|
|
75
|
+
islands: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
76
|
+
size: z.ZodNumber;
|
|
77
|
+
framework: z.ZodString;
|
|
78
|
+
}, z.core.$strip>>;
|
|
79
|
+
references: z.ZodObject<{
|
|
80
|
+
astroSolidCounter: z.ZodNumber;
|
|
81
|
+
}, z.core.$strip>;
|
|
82
|
+
}, z.core.$strip>;
|
|
83
|
+
/** Benchmark baseline data parsed from the baseline JSON file. */
|
|
84
|
+
export type BenchmarkBaseline = z.infer<typeof BenchmarkBaselineSchema>;
|
|
85
|
+
/** Result of comparing a single island's current size against the benchmark baseline. */
|
|
86
|
+
export interface BenchmarkResult {
|
|
87
|
+
island: string;
|
|
88
|
+
currentSize: number;
|
|
89
|
+
baselineSize: number | null;
|
|
90
|
+
deltaBytes: number;
|
|
91
|
+
deltaPercent: number;
|
|
92
|
+
framework: string;
|
|
93
|
+
astroReferenceSize?: number;
|
|
55
94
|
}
|
|
95
|
+
/**
|
|
96
|
+
* Compare current island sizes against a stored benchmark baseline.
|
|
97
|
+
*
|
|
98
|
+
* This is a pure function — the caller is responsible for loading and parsing
|
|
99
|
+
* the baseline JSON file. For each island in `currentIslands`, the function
|
|
100
|
+
* looks up the baseline entry by island name and computes the delta.
|
|
101
|
+
*
|
|
102
|
+
* @param currentIslands - Array of current island build results with name, size, and framework
|
|
103
|
+
* @param baseline - Parsed benchmark baseline data
|
|
104
|
+
* @param regressionThreshold - Maximum allowed regression in bytes before flagging (default: 500)
|
|
105
|
+
* @returns Results per island and whether any regression was detected
|
|
106
|
+
*/
|
|
107
|
+
export declare function compareBenchmarkBaseline(currentIslands: Array<{
|
|
108
|
+
island: string;
|
|
109
|
+
size: number;
|
|
110
|
+
framework: string;
|
|
111
|
+
}>, baseline: BenchmarkBaseline, regressionThreshold?: number): {
|
|
112
|
+
results: BenchmarkResult[];
|
|
113
|
+
hasRegression: boolean;
|
|
114
|
+
};
|
|
56
115
|
/** Default per-chunk size threshold: 20 KiB */
|
|
57
116
|
export declare const DEFAULT_CHUNK_THRESHOLD: number;
|
|
58
117
|
/** Default total JS size threshold: 20 KiB (from requirements) */
|
|
59
118
|
export declare const DEFAULT_TOTAL_THRESHOLD: number;
|
|
119
|
+
/** Default per-framework island chunk thresholds. Solid: 6 KiB, others: 10 KiB. */
|
|
120
|
+
export declare const DEFAULT_PER_FRAMEWORK_THRESHOLDS: PerFrameworkThresholds;
|
|
121
|
+
/**
|
|
122
|
+
* Detect the framework from an island chunk file name.
|
|
123
|
+
* Looks for `.solid.`, `.preact.`, `.react.`, `.vue.`, `.svelte.` in the file name.
|
|
124
|
+
* Returns the framework name or `null` if none is detected.
|
|
125
|
+
*/
|
|
126
|
+
export declare function detectFrameworkFromFileName(fileName: string): string | null;
|
|
60
127
|
/** Shape of a bundle asset — loose enough to handle both Rollup and Rolldown. */
|
|
61
128
|
export type BundleAsset = Record<string, unknown> & {
|
|
62
129
|
type: string;
|
|
@@ -87,6 +154,7 @@ export declare function findDevOnlyModules(chunks: ChunkInfo[]): Array<{
|
|
|
87
154
|
export declare function generateAuditReport(chunks: ChunkInfo[], options?: {
|
|
88
155
|
chunkSizeThreshold?: number;
|
|
89
156
|
totalSizeThreshold?: number;
|
|
157
|
+
perFrameworkThresholds?: Partial<PerFrameworkThresholds>;
|
|
90
158
|
}): BundleAuditReport;
|
|
91
159
|
/**
|
|
92
160
|
* Format a byte count as a human-readable KiB string.
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const DEFAULT_CHUNK_THRESHOLD=20*1024;export const DEFAULT_TOTAL_THRESHOLD=20*1024;const
|
|
2
|
-
`)}export function auditBuildConfig(e){let t=[],n=[],r=e.build?.minify??`esbuild`,i=r!==!1;i?n.push(`Minification enabled: ${r}`):t.push(`build.minify is disabled — production builds should be minified`);let a=e.build?.target??`modules`,o=a!==`es5`&&a!==`es3`;o?n.push(`Modern build target: ${JSON.stringify(a)}`):t.push(`build.target is "${a}" — consider "es2020" or higher for smaller output`);let s=e.define??{},c=`process.env.NODE_ENV`in s||`__DEV__`in s||`__PROD__`in s;c?n.push(`process.env.NODE_ENV / __DEV__ / __PROD__ defined for dead code elimination`):t.push(`No process.env.NODE_ENV define — dev-only code may leak into production`);let l=e.build?.rollupOptions?.treeshake!=null;return l?n.push(`Custom treeshake.moduleSideEffects configured`):t.push(`No custom treeshake config — solid-js may not be fully tree-shaken`),{hasMinify:i,minifyValue:r,hasModernTarget:o,targetValue:a,hasNodeEnvDefine:c,hasTreeshakeConfig:l,issues:t,optimizations:n}}export function bundleAuditPlugin(t={}){let{chunkSizeThreshold:
|
|
1
|
+
import{readFileSync as e}from"node:fs";import{z as t}from"zod";export const BenchmarkBaselineSchema=t.object({version:t.number(),timestamp:t.string(),islands:t.record(t.string(),t.object({size:t.number(),framework:t.string()})),references:t.object({astroSolidCounter:t.number()})});export function compareBenchmarkBaseline(e,t,n=500){let r=t.references.astroSolidCounter,i=e.map(e=>{let n=t.islands[e.island];if(n){let t=e.size-n.size,i=t/n.size*100;return{island:e.island,currentSize:e.size,baselineSize:n.size,deltaBytes:t,deltaPercent:i,framework:e.framework,astroReferenceSize:r}}return{island:e.island,currentSize:e.size,baselineSize:null,deltaBytes:0,deltaPercent:0,framework:e.framework,astroReferenceSize:r}});return{results:i,hasRegression:i.some(e=>e.deltaBytes>n)}}export const DEFAULT_CHUNK_THRESHOLD=20*1024;export const DEFAULT_TOTAL_THRESHOLD=20*1024;export const DEFAULT_PER_FRAMEWORK_THRESHOLDS={solid:6*1024,preact:10*1024,react:10*1024,vue:10*1024,svelte:10*1024};const s=[`.solid.`,`.preact.`,`.react.`,`.vue.`,`.svelte.`];export function detectFrameworkFromFileName(e){for(let t of s)if(e.includes(t))return t.slice(1,-1);return null}const l=[/\/dev\.js$/,/\/dev\.mjs$/,/__DEV__/,/hot-reload/,/hmr-coordinator/,/hmr-error-overlay/,/solid-refresh/];export function extractChunks(e){let t=[];for(let[n,r]of Object.entries(e)){if(r.type!==`chunk`)continue;let e=r.fileName??n,i=r.code??``,a=r.moduleIds??Object.keys(r.modules??{});t.push({fileName:e,size:Buffer.byteLength(i,`utf-8`),moduleIds:a,isIsland:e.startsWith(`islands/`)||e.includes(`/islands/`),isEntry:r.isEntry??!1})}return t.sort((e,t)=>t.size-e.size)}export function findDuplicatedModules(e){let t=new Map;for(let n of e)for(let e of n.moduleIds){if(e.startsWith(`\0`))continue;let r=t.get(e)??[];r.push(n.fileName),t.set(e,r)}let n=[];for(let[e,r]of t)r.length>1&&n.push({moduleId:e,chunks:r});return n.sort((e,t)=>t.chunks.length-e.chunks.length)}export function findDevOnlyModules(e){let t=[];for(let n of e)for(let e of n.moduleIds)for(let r of l)r.test(e)&&t.push({chunkFileName:n.fileName,moduleId:e,pattern:r.source});return t}export function generateAuditReport(e,t={}){let n=t.chunkSizeThreshold??DEFAULT_CHUNK_THRESHOLD,r=e.reduce((e,t)=>e+t.size,0),a=e.filter(e=>e.isIsland).reduce((e,t)=>e+t.size,0),s=new Set(e.filter(e=>e.isIsland&&e.size>n).map(e=>e.fileName)),l=new Set;if(t.perFrameworkThresholds){let n={...DEFAULT_PER_FRAMEWORK_THRESHOLDS,...t.perFrameworkThresholds};for(let t of e){if(!t.isIsland)continue;let e=detectFrameworkFromFileName(t.fileName);if(e&&e in n){let r=n[e];t.size>r&&l.add(t.fileName)}}}let u=new Set([...s,...l]);return{chunks:e,totalJsBytes:r,islandJsBytes:a,oversizedChunks:e.filter(e=>u.has(e.fileName)),duplicatedModules:findDuplicatedModules(e)}}export function formatKiB(e){return`${(e/1024).toFixed(2)} KiB`}function f(e){return e.isIsland?` [island]`:e.isEntry?` [entry]`:` `}function p(e,t){return e.length<=t?e:`...${e.slice(-(t-3))}`}export function formatAuditReport(e){let t=[`┌─────────────────────────────────────────────────────┐`,`│ Bundle Audit Report │`,`├─────────────────────────────────────────────────────┤`,`│ Total JS: ${formatKiB(e.totalJsBytes).padStart(12)} │`,`│ Island JS: ${formatKiB(e.islandJsBytes).padStart(12)} │`,`│ Chunks: ${String(e.chunks.length).padStart(12)} │`,`├─────────────────────────────────────────────────────┤`,`│ Chunks by size: │`];for(let n of e.chunks){let e=f(n),r=p(n.fileName,32);t.push(`│ ${e} ${r.padEnd(32)} ${formatKiB(n.size).padStart(10)} │`)}if(e.oversizedChunks.length>0){t.push(`├─────────────────────────────────────────────────────┤`),t.push(`│ Oversized island chunks: │`);for(let n of e.oversizedChunks)t.push(`│ ${n.fileName.padEnd(38)} ${formatKiB(n.size).padStart(10)} │`)}if(e.duplicatedModules.length>0){t.push(`├─────────────────────────────────────────────────────┤`),t.push(`│ Duplicated modules: ${e.duplicatedModules.length} │`);for(let n of e.duplicatedModules.slice(0,5)){let e=p(n.moduleId,40);t.push(`│ ${e.padEnd(40)} x${n.chunks.length} │`)}e.duplicatedModules.length>5&&t.push(`│ ... and ${e.duplicatedModules.length-5} more │`)}return t.push(`└─────────────────────────────────────────────────────┘`),t.join(`
|
|
2
|
+
`)}export function auditBuildConfig(e){let t=[],n=[],r=e.build?.minify??`esbuild`,i=r!==!1;i?n.push(`Minification enabled: ${r}`):t.push(`build.minify is disabled — production builds should be minified`);let a=e.build?.target??`modules`,o=a!==`es5`&&a!==`es3`;o?n.push(`Modern build target: ${JSON.stringify(a)}`):t.push(`build.target is "${a}" — consider "es2020" or higher for smaller output`);let s=e.define??{},c=`process.env.NODE_ENV`in s||`__DEV__`in s||`__PROD__`in s;c?n.push(`process.env.NODE_ENV / __DEV__ / __PROD__ defined for dead code elimination`):t.push(`No process.env.NODE_ENV define — dev-only code may leak into production`);let l=e.build?.rollupOptions?.treeshake!=null;return l?n.push(`Custom treeshake.moduleSideEffects configured`):t.push(`No custom treeshake config — solid-js may not be fully tree-shaken`),{hasMinify:i,minifyValue:r,hasModernTarget:o,targetValue:a,hasNodeEnvDefine:c,hasTreeshakeConfig:l,issues:t,optimizations:n}}export function bundleAuditPlugin(t={}){let{chunkSizeThreshold:a=DEFAULT_CHUNK_THRESHOLD,totalSizeThreshold:o=20480,logReport:s=!0,warnOnOversized:l=!0,perFrameworkThresholds:d,benchmarkBaseline:f,regressionThreshold:p}=t,h=!1;return{name:`avalon:bundle-audit`,enforce:`post`,config(e,{command:t}){h=t===`build`},configResolved(e){if(h&&s){let t=e.build,n=t?.rollupOptions,r=auditBuildConfig({build:{minify:t?.minify,target:t?.target,rollupOptions:{treeshake:n?.treeshake}},define:e.define});if(r.issues.length>0)for(let e of r.issues)console.warn(`⚠️ [bundle-audit] ${e}`)}},generateBundle(t,i){if(!h)return;let m=extractChunks(i),g=generateAuditReport(m,{chunkSizeThreshold:a,totalSizeThreshold:o,perFrameworkThresholds:d});if(s&&console.log(formatAuditReport(g)),l&&g.oversizedChunks.length>0)for(let e of g.oversizedChunks)this.warn(`Island chunk "${e.fileName}" is ${formatKiB(e.size)} (threshold: ${formatKiB(a)})`);l&&g.totalJsBytes>o&&this.warn(`Total JS size ${formatKiB(g.totalJsBytes)} exceeds threshold of ${formatKiB(o)}`);let _=findDevOnlyModules(m);if(_.length>0)for(let e of _)this.warn(`Dev-only module "${e.moduleId}" found in chunk "${e.chunkFileName}"`);if(f)try{let t=e(f,`utf-8`),i=BenchmarkBaselineSchema.parse(JSON.parse(t)),{results:a,hasRegression:o}=compareBenchmarkBaseline(g.chunks.filter(e=>e.isIsland).map(e=>({island:e.fileName,size:e.size,framework:detectFrameworkFromFileName(e.fileName)??`unknown`})),i,p);for(let e of a){let t=e.baselineSize==null?`N/A`:formatKiB(e.baselineSize),n=e.baselineSize==null?`new`:`${e.deltaBytes>0?`+`:``}${e.deltaBytes}B (${e.deltaPercent.toFixed(1)}%)`;console.log(`📊 [benchmark] ${e.island}: ${formatKiB(e.currentSize)} (baseline: ${t}, delta: ${n})`)}o&&this.error(`Bundle size regression detected — one or more islands exceed the baseline by more than the allowed threshold`)}catch(e){if(e.code===`ENOENT`)this.warn(`Benchmark baseline file not found: ${f}`);else throw e}}}}
|
|
@@ -11,8 +11,9 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import type { Plugin } from "vite";
|
|
13
13
|
import type { AvalonNitroConfig } from "../nitro/config.ts";
|
|
14
|
+
import type { TreeshakeConfig } from "../post-build/isolated-island-builder.ts";
|
|
14
15
|
import type { ResolvedAvalonConfig } from "../vite-plugin/types.ts";
|
|
15
16
|
/**
|
|
16
17
|
* Creates a Vite plugin that emits island components as separate client chunks.
|
|
17
18
|
*/
|
|
18
|
-
export declare function islandClientBundlerPlugin(config: ResolvedAvalonConfig, _nitroConfig?: AvalonNitroConfig): Plugin;
|
|
19
|
+
export declare function islandClientBundlerPlugin(config: ResolvedAvalonConfig, _nitroConfig?: AvalonNitroConfig, treeshakeOverrides?: Partial<TreeshakeConfig>): Plugin;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{existsSync as e,readdirSync as t,readFileSync as n,statSync as r}from"node:fs";import{dirname as i,relative as a,resolve as o}from"node:path";export function islandClientBundlerPlugin(e,t){let
|
|
1
|
+
import{existsSync as e,readdirSync as t,readFileSync as n,statSync as r}from"node:fs";import{dirname as i,relative as a,resolve as o}from"node:path";export function islandClientBundlerPlugin(e,t,n){let r=process.cwd(),i=new Map,a=!1,o=c(e,r);for(let e of o)d(e,r,i);let s=`\0avalon-island-entry:`,l=!1,u=[],f={},p=`dist`;return{name:`avalon:island-client-bundler`,enforce:`pre`,configResolved(e){l=e.command===`serve`,a=e.command===`build`,u=e.resolve?.alias??[],f=e.define??{},p=e.build?.outDir??`dist`},resolveId(e){return e.startsWith(s)?e:null},load(e){if(!e.startsWith(s))return null;let t=e.slice(21),n=JSON.stringify(t);if(t.includes(`.qwik.`))return a?[`export * from ${n};`,`export { _hW } from "@builder.io/qwik";`].join(`
|
|
2
2
|
`):[`export * from ${n};`,`export { _hW } from "@builder.io/qwik";`,`import __C from ${n};`,`export default __C;`,`if(typeof globalThis<"u")globalThis.__avalonIsland=__C;`].join(`
|
|
3
|
-
`);let r=t.includes(`.lit.`),
|
|
4
|
-
`)},async buildStart(){if(
|
|
3
|
+
`);let r=t.includes(`.lit.`),i=t.includes(`.solid.`),o=t.includes(`.preact.`),c=t.includes(`.react.`),l=t.includes(`.vue.`),u=t.includes(`.svelte.`),d=[];if(r&&a&&d.push(`import "@useavalon/lit/client";`),d.push(`import __C from ${n};`,`var Component = __C;`,`export { Component as default, Component };`,`if(typeof globalThis<"u")globalThis.__avalonIsland=Component;`),a){let e={solid:`@useavalon/solid/client`,preact:`@useavalon/preact/client`,react:`@useavalon/react/client`,vue:`@useavalon/vue/client`,svelte:`@useavalon/svelte/client`,lit:`@useavalon/lit/client`},t=i?`solid`:o?`preact`:c?`react`:l?`vue`:u?`svelte`:r?`lit`:null;t&&e[t]?d.push(`export { hydrate as __hydrateIsland } from ${JSON.stringify(e[t])};`):d.push(`export { loadIntegrationModule } from "virtual:avalon/integration-loader";`)}return d.join(`
|
|
4
|
+
`)},async buildStart(){if(l)return;let t=this.environment;if(!(t&&t.name!==`client`)&&i.size>0){for(let[,e]of i)this.emitFile({type:`chunk`,id:s+e.filePath,fileName:`islands/${e.bundleKey}.js`,preserveSignature:`exports-only`});e.verbose&&console.log(`🏝️ Emitting ${i.size} island client bundles`)}},async closeBundle(){if(l||!a||i.size===0||globalThis.__avalonIslandsRebuilt)return;globalThis.__avalonIslandsRebuilt=!0;let{buildIsolatedIslands:e}=await import(`../post-build/isolated-island-builder.js`),t=new Map;for(let[e,n]of i){let r=n.filePath.includes(`.solid.`)?`solid`:n.filePath.includes(`.preact.`)?`preact`:n.filePath.includes(`.react.`)?`react`:n.filePath.includes(`.vue.`)||n.filePath.endsWith(`.vue`)?`vue`:n.filePath.includes(`.svelte.`)||n.filePath.endsWith(`.svelte`)?`svelte`:n.filePath.includes(`.lit.`)?`lit`:n.filePath.includes(`.qwik.`)?`qwik`:`preact`;t.set(e,{...n,framework:r})}await e(r,p,t,u,f,n?{treeshake:n}:void 0)}}}function c(n,r){let i=[];if(n.pagesDir){let t=o(r,n.pagesDir);e(t)&&i.push(t)}if(n.layoutsDir){let t=o(r,n.layoutsDir);e(t)&&i.push(t)}if(n.modules){let a=o(r,n.modules.dir);if(e(a))try{for(let n of t(a,{withFileTypes:!0}))if(n.isDirectory())for(let t of[`pages`,`layouts`,`components`]){let r=o(a,n.name,t);e(r)&&i.push(r)}}catch{}}return i}const l=[`.qwik.`];function u(e){return l.some(t=>e.includes(t))}function d(e,r,i){let a;try{a=t(e,{withFileTypes:!0})}catch{return}for(let t of a){let a=o(e,t.name);if(t.isDirectory()){d(a,r,i);continue}if(/\.(tsx?|jsx?|mdx?)$/.test(t.name))try{let e=n(a,`utf-8`),t=e.includes(`island=`)||e.includes(`island `),o=/import\s+\w+\s+from\s+['"][^'"]*\.qwik\.[^'"]*['"]/m.test(e);if(!t&&!o)continue;f(e,a,r,i)}catch{}}}function f(e,t,n,r){let i=/<([A-Z]\w*)\s+[^>]*\bisland\b/g,o=new Set,s=null;for(s=i.exec(e);s!==null;s=i.exec(e))o.add(s[1]);let c=/import\s+(\w+)\s+from\s+['"]([^'"]+)['"]/g,l=new Set,d=[];for(s=c.exec(e);s!==null;s=c.exec(e))d.push([s[1],s[2]]),u(s[2])&&RegExp(`<${s[1]}[\\s/>]`).test(e)&&l.add(s[1]);if(!(o.size===0&&l.size===0))for(let[e,i]of d){if(!o.has(e)&&!l.has(e))continue;let s=p(i,t,n);if(!s)continue;let c=a(n,s).replaceAll(`\\`,`/`).replace(/\.(tsx?|jsx?)$/,``);r.has(s)||r.set(s,{filePath:s,bundleKey:c})}}function p(t,n,a){let s;if(t.startsWith(`@shared/`))s=o(a,`app/shared`,t.slice(8));else if(t.startsWith(`@modules/`))s=o(a,`app/modules`,t.slice(9));else if(t.startsWith(`@/`))s=o(a,`app`,t.slice(2));else if(t.startsWith(`.`))s=o(i(n),t);else return null;if(e(s)&&r(s).isFile())return s;for(let t of[`.tsx`,`.ts`,`.jsx`,`.js`,`.vue`,`.svelte`])if(e(s+t))return s+t;return null}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export function generatePerIslandScript(e){let{islandId:r,componentSrc:i,framework:a,condition:o,conditionArg:s,propsJson:c,isCustomDirective:l,directiveScript:u}=e;return`<script type="module">${n(r,o,t(r,i,a,c),s,l,u)}<\/script>`}function t(e,t,n,r){return[`async function h(){`,`var e=document.getElementById(${JSON.stringify(e)});`,`if(!e||e.dataset.hydrated)return;`,`try{`,`var p=${r};`,`var m=await import(${JSON.stringify(t)});`,`var C=m.default||Object.values(m).find(function(v){return typeof v==="function"&&v.prototype})||m;`,`if(m.__hydrateIsland){await m.__hydrateIsland(e,C,p)}`,`else if(m.loadIntegrationModule){var i=await m.loadIntegrationModule(${JSON.stringify(n)});if(i.hydrate)await i.hydrate(e,C,p)}`,`e.dataset.hydrated="true";`,`}catch(err){console.error("Hydration error:",err)}`,`}`].join(``)}function n(e,t,n,r,i,a){if(t===`on:client`)return`${n}
|
|
1
|
+
export function generatePerIslandScript(e){let{islandId:r,componentSrc:i,framework:a,condition:o,conditionArg:s,propsJson:c,isCustomDirective:l,directiveScript:u}=e;return`<script type="module">${n(r,o,t(r,i,a,c),s,l,u)}<\/script>`}function t(e,t,n,r){return[`async function h(){`,`var e=document.getElementById(${JSON.stringify(e)});`,`if(!e||e.dataset.hydrated)return;`,`try{`,`var p=${r};`,`var m=await import(${JSON.stringify(t)});`,`var C=m.default||Object.values(m).find(function(v){return typeof v==="function"&&v.prototype})||m;`,`if(m.__hydrateIsland){await m.__hydrateIsland(e,C,p)}`,`else if(m.loadIntegrationModule){var i=await m.loadIntegrationModule(${JSON.stringify(n)});if(i.hydrate)await i.hydrate(e,C,p)}`,`e.dataset.hydrated="true";`,`}catch(err){console.error("Hydration error:",err)}`,`}`].join(``)}function n(e,t,n,r,i,a){if(t===`on:client`)return`${n}h();`;if(t===`on:visible`)return[n,`var e=document.getElementById(${JSON.stringify(e)});`,`if(e){try{var o=new IntersectionObserver(function(n){`,`if(n[0].isIntersecting){h();o.disconnect()}`,`},{rootMargin:"50px",threshold:0});o.observe(e)}catch(_){h()}}`].join(``);if(t===`on:idle`)return[n,`if("requestIdleCallback" in globalThis){`,`globalThis.requestIdleCallback(function(){h()},{timeout:5000})`,`}else if(document.readyState==="complete"){`,`setTimeout(function(){h()},200)`,`}else{globalThis.addEventListener("load",function(){setTimeout(function(){h()},200)},{once:true})}`].join(``);if(t===`on:interaction`)return[n,`var e=document.getElementById(${JSON.stringify(e)});`,`if(e){var d=false;var ev=["click","touchstart","mouseenter","focusin"];`,`var fn=function(){if(d)return;d=true;ev.forEach(function(n){e.removeEventListener(n,fn)});h()};`,`ev.forEach(function(n){e.addEventListener(n,fn,{once:true,passive:true})})}`].join(``);if(t.startsWith(`media:`)){let e=t.slice(6);return[n,`try{var mq=globalThis.matchMedia(${JSON.stringify(e)});`,`if(mq.matches){h()}else{mq.addEventListener("change",function x(ev){`,`if(ev.matches){h();mq.removeEventListener("change",x)}},{once:true})}}catch(_){h()}`].join(``)}return i&&a?[n,`var e=document.getElementById(${JSON.stringify(e)});`,`if(e){var dir=(${a});`,`dir(e,function(){h()}${r?`,${JSON.stringify(r)}`:``})}`].join(``):`${n}h();`}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import{copyFileSync as e,cpSync as t,existsSync as n,mkdirSync as r,readdirSync as i,readFileSync as a,unlinkSync as o,writeFileSync as s}from"node:fs";import{dirname as c,join as l,relative as u}from"node:path";function d(e,t,r=[]){if(!n(e))return r;for(let n of i(e,{withFileTypes:!0})){let i=l(e,n.name);n.isDirectory()?d(i,t,r):t(n.name)&&r.push(i)}return r}function f(e){if(!n(e))return!1;let t=a(e,`utf-8`);return t.length<500&&!t.includes(`data-framework`)&&!t.includes(`avalon`)}function p(e){for(let t of[`dist/index.html`,`.netlify/functions-internal/server/public/index.html`]){let r=l(e,t);f(r)?(o(r),console.log(`[cleanup] Removed stale Vite template ${t}`)):n(r)&&console.log(`[cleanup] Preserved prerendered ${t}`)}}function m(e,t,r){if(!n(e))return;let i=[l(t,`assets`),l(r,`.netlify`,`functions-internal`,`server`,`public`,`assets`),l(r,`.output`,`public`,`assets`)].find(e=>n(e));if(!i)return;let o=d(i,e=>e.endsWith(`.css`)).map(e=>`/assets${e.substring(i.length).replaceAll(`\\`,`/`)}`);console.log(`[patch] Found ${o.length} CSS files in ${i}`);let c=a(e,`utf-8`);for(let{re:t,hrefRe:n,q:r}of[{re:/css:\[(\{href:`[^`]+`\}(?:,\{href:`[^`]+`\})*)\]/,hrefRe:/href:`([^`]+)`/g,q:"`"},{re:/css:\[(\{href:"[^"]+"\}(?:,\{href:"[^"]+"\})*)\]/,hrefRe:/href:"([^"]+)"/g,q:`"`}]){let i=t.exec(c);if(!i)continue;let a=new Set([...i[1].matchAll(n)].map(e=>e[1])),l=o.filter(e=>!a.has(e));if(l.length===0){console.log(`[patch] All CSS already included`);return}let u=l.map(e=>`{href:${r}${e}${r}}`).join(`,`);c=c.replace(i[0],`css:[${i[1]},${u}]`),s(e,c),console.log(`[patch] ✅ Added ${l.length} CSS files to SSR bundle`);return}console.warn(`[patch] Could not find CSS array in SSR bundle`)}function h(t
|
|
1
|
+
import{copyFileSync as e,cpSync as t,existsSync as n,mkdirSync as r,readdirSync as i,readFileSync as a,unlinkSync as o,writeFileSync as s}from"node:fs";import{dirname as c,join as l,relative as u}from"node:path";function d(e,t,r=[]){if(!n(e))return r;for(let n of i(e,{withFileTypes:!0})){let i=l(e,n.name);n.isDirectory()?d(i,t,r):t(n.name)&&r.push(i)}return r}function f(e){if(!n(e))return!1;let t=a(e,`utf-8`);return t.length<500&&!t.includes(`data-framework`)&&!t.includes(`avalon`)}function p(e){for(let t of[`dist/index.html`,`.netlify/functions-internal/server/public/index.html`,`.output/public/index.html`]){let r=l(e,t);f(r)?(o(r),console.log(`[cleanup] Removed stale Vite template ${t}`)):n(r)&&console.log(`[cleanup] Preserved prerendered ${t}`)}}function m(e,t,r){if(!n(e))return;let i=[l(t,`assets`),l(r,`.netlify`,`functions-internal`,`server`,`public`,`assets`),l(r,`.output`,`public`,`assets`)].find(e=>n(e));if(!i)return;let o=d(i,e=>e.endsWith(`.css`)).filter(e=>{let t=(e.split(`/`).pop()||``).toLowerCase();return t.includes(`_isolated-island-entry`)?!1:!!(t.startsWith(`ssr-index`)||t.startsWith(`index-`)||t.startsWith(`entry-client`))}).map(e=>`/assets${e.substring(i.length).replaceAll(`\\`,`/`)}`);console.log(`[patch] Found ${o.length} CSS files in ${i}`);let c=a(e,`utf-8`);for(let{re:t,hrefRe:n,q:r}of[{re:/css:\[(\{href:`[^`]+`\}(?:,\{href:`[^`]+`\})*)\]/,hrefRe:/href:`([^`]+)`/g,q:"`"},{re:/css:\[(\{href:"[^"]+"\}(?:,\{href:"[^"]+"\})*)\]/,hrefRe:/href:"([^"]+)"/g,q:`"`}]){let i=t.exec(c);if(!i)continue;let a=new Set([...i[1].matchAll(n)].map(e=>e[1])),l=o.filter(e=>!a.has(e));if(l.length===0){console.log(`[patch] All CSS already included`);return}let u=l.map(e=>`{href:${r}${e}${r}}`).join(`,`);c=c.replace(i[0],`css:[${i[1]},${u}]`),s(e,c),console.log(`[patch] ✅ Added ${l.length} CSS files to SSR bundle`);return}console.warn(`[patch] Could not find CSS array in SSR bundle`)}function h(e){return e.replaceAll(/\/\*[\s\S]*?\*\//g,``).replaceAll(/\s+/g,` `).replaceAll(/\s*([{}:;,>~+])\s*/g,`$1`).replaceAll(/;}/g,`}`).trim()}function g(e,t){let o=[l(e,`node_modules`,`.nitro`,`vite`,`services`,`ssr`,`assets`)];for(let c of o){if(!n(c))continue;let o=i(c).filter(e=>e.endsWith(`.css`));if(o.length===0)continue;let u=[l(t,`assets`),l(e,`.output`,`public`,`assets`),l(e,`.netlify`,`functions-internal`,`server`,`public`,`assets`)];for(let e of u){r(e,{recursive:!0});for(let t of o){let n=a(l(c,t),`utf-8`);n=h(n),s(l(e,`ssr-${t}`),n)}}let d=`ssr-${o[0]}`,f=l(u.find(e=>n(e))||u[0],d),p=n(f)?a(f).length:0;console.log(`[ssr-css] Copied SSR CSS → /assets/${d} (${p} bytes, minified)`);let m=[l(e,`.output`,`server`,`index.mjs`),l(e,`.netlify`,`functions-internal`,`server`,`main.mjs`)];for(let e of m){if(!n(e))continue;let t=a(e,`utf-8`),r=`/assets/${d}`;if(t.includes(r))continue;let i=/"\/assets\/[^"]+\.css":\{type:`text\/css[^}]+\}/.exec(t);if(i){let n=new Date().toISOString(),a=`,"${r}":{type:\`text/css; charset=utf-8\`,etag:\`${`"${p.toString(16)}-ssr"`}\`,mtime:\`${n}\`,size:${p},path:\`../public/assets/${d}\`}`;t=t.replace(i[0],i[0]+a),s(e,t),console.log(`[ssr-css] ✅ Patched asset manifest in ${e}`)}}return}console.log(`[ssr-css] No SSR CSS files found`)}function _(t){let i=[l(t,`assets`,`islands`),l(t,`islands`)].find(e=>n(e));if(!i)return;let o=d(i,e=>e.endsWith(`.js`)&&!e.endsWith(`.js.map`));if(o.length===0)return;let f=o.filter(e=>/-[A-Za-z0-9_-]{6,12}\.js$/.test(e));if(f.length===0){console.log(`[redirects] ${o.length} island(s) found with clean paths — no redirects needed`);return}let p=[];for(let n of f){let i=`/${u(t,n).replaceAll(`\\`,`/`)}`,a=i.replace(`/assets/`,`/`).replace(/-[A-Za-z0-9_-]{6,12}\.js$/,`.js`);p.push(`${a} ${i} 200`);let o=l(t,a.slice(1));r(c(o),{recursive:!0}),e(n,o)}let m=l(t,`_redirects`),h=n(m)?a(m,`utf-8`):``;h=h.replaceAll(/# Island JS path rewrites[^\n]*\n(?:\/islands\/[^\n]*\n)*/g,``).trim();let g=`# Island JS path rewrites (generated by Avalon post-build)
|
|
2
2
|
`;s(m,h?`${h}\n\n${g}${p.join(`
|
|
3
3
|
`)}\n`:`${g+p.join(`
|
|
4
|
-
`)}\n`),console.log(`[redirects] ✅ Wrote ${p.length} island redirects + local copies`)}function
|
|
4
|
+
`)}\n`),console.log(`[redirects] ✅ Wrote ${p.length} island redirects + local copies`)}function v(t,a){let o=[l(t,`.output`,`public`,`_adapters`),l(a,`_adapters`)];for(let t of o){if(!n(t))continue;let o=i(t).filter(e=>e.endsWith(`.js`));if(o.length===0)continue;let s=l(a,`_adapters`);r(s,{recursive:!0});for(let n of o){let r=l(t,n),i=l(s,n);r!==i&&e(r,i)}console.log(`[adapters] ✅ Copied ${o.length} framework adapters`);return}console.log(`[adapters] No _adapters/ directory found`)}function y(e){let r=l(e,`.netlify`,`functions-internal`,`server`);if(!n(r))return;let i=[l(e,`.netlify`,`v1`,`functions`,`server`)];for(let n of i){t(r,n,{recursive:!0,force:!0});let i=n.substring(e.length).replaceAll(`\\`,`/`);console.log(`[netlify-fn] ✅ Copied server function to ${i}/`)}}function b(e){let t=a(e,`utf-8`);return t.includes(`path: "/*"`)||t.includes("path:`/*`")}function x(e,t,r){let i=l(c(e),`_prerender-server.mjs`),a=``,o=[l(r,`node_modules`,`urlpattern-polyfill`,`index.js`),l(r,`node_modules`,`urlpattern-polyfill`,`dist`,`urlpattern.js`)].find(e=>n(e));return o&&(a=`import '${o.replaceAll(`\\`,`/`)}';`),s(i,`
|
|
5
5
|
${a}
|
|
6
6
|
import { createServer } from 'node:http';
|
|
7
7
|
import handler from './main.mjs';
|
|
@@ -27,5 +27,5 @@ const server = createServer(async (req, res) => {
|
|
|
27
27
|
server.listen(PORT, '127.0.0.1', () => {
|
|
28
28
|
console.log('[prerender-wrapper] Listening on http://127.0.0.1:' + PORT);
|
|
29
29
|
});
|
|
30
|
-
`),i}function
|
|
31
|
-
<!-- SSG: prerendered at build time -->`)),E.push(t),console.log(`[prerender] ✅ ${t} → ${i}`),h.crawlLinks)for(let e of
|
|
30
|
+
`),i}function S(e){let t=[],n=/<a\s[^>]*href=["']([^"'#?]+)/gi,r=null;for(r=n.exec(e);r!==null;r=n.exec(e)){let e=r[1];e.startsWith(`/`)&&!e.startsWith(`//`)&&!e.startsWith(`/assets/`)&&!e.startsWith(`/islands/`)&&!e.startsWith(`/chunks/`)&&!e.startsWith(`/_`)&&!e.match(/\.\w{2,5}$/)&&t.push(e)}return[...new Set(t)]}async function C(t,i,d,f){let p=[l(t,`.netlify`,`functions-internal`,`server`,`server.mjs`),l(t,`.netlify`,`v1`,`functions`,`server`,`server.mjs`),l(t,`.output`,`server`,`index.mjs`)].find(e=>n(e));if(!p){console.log(`[prerender] No server entry found, skipping prerender`);return}let m=[l(t,`.output`,`public`),i].find(e=>n(e));if(!m){console.log(`[prerender] No output directory found, skipping prerender`);return}let h={routes:d.routes??[`/`],crawlLinks:d.crawlLinks??!0,ignore:d.ignore??[],failOnError:d.failOnError??!1,concurrency:d.concurrency??4,autoSubfolderIndex:d.autoSubfolderIndex??!0,retry:d.retry??3,retryDelay:d.retryDelay??500},g=`http://localhost:${f}`,_=b(p),v=p;if(_){let e=l(c(p),`main.mjs`);if(!n(e)){console.error(`[prerender] Netlify handler detected but main.mjs not found`);return}v=x(e,f,t),console.log(`[prerender] Netlify handler detected — using wrapper`)}{let e=[p,l(c(p),`main.mjs`)].filter(e=>n(e));for(let n of e){let e=a(n,`utf-8`),r=/"\/[^"]*\.html":\{[^}]+\},?/g,i=e.length;e=e.replaceAll(r,``),i!==e.length&&(s(n,e),console.log(`[prerender] Patched ${u(t,n)}: removed HTML asset entries`))}}console.log(`[prerender] Starting prerender with server: ${u(t,v)}`);let{spawn:y}=await import(`node:child_process`),C;try{C=y(`node`,[v],{env:{...process.env,PORT:String(f),NITRO_PORT:String(f),HOST:`127.0.0.1`,NITRO_HOST:`127.0.0.1`,NODE_ENV:`production`},stdio:[`ignore`,`pipe`,`pipe`]}),C.stdout?.on(`data`,e=>{let t=e.toString().trim();t&&console.log(`[prerender:server] ${t}`)}),C.stderr?.on(`data`,e=>{let t=e.toString().trim();t&&console.error(`[prerender:server:err] ${t}`)});let e=Date.now(),t=!1;for(;Date.now()-e<15e3;){try{let e=await fetch(`${g}/`);if(e.ok||e.status<500){t=!0;break}}catch{}await new Promise(e=>setTimeout(e,200))}if(!t)throw Error(`Server did not become ready within 15s`);console.log(`[prerender] Server ready at ${g}`)}catch(e){C?.kill(`SIGKILL`),console.error(`[prerender] Failed to start server:`,e.message);return}let w=new Set,T=[...h.routes],E=[],D=[];function O(e){for(let t of h.ignore)if(typeof t==`string`&&e===t||typeof t==`string`&&t.endsWith(`/**`)&&e.startsWith(t.slice(0,-2)))return!0;return!1}try{for(;T.length>0;){let e=T.splice(0,h.concurrency);await Promise.all(e.map(async e=>{let t=e.endsWith(`/`)&&e!==`/`?e.slice(0,-1):e;if(w.has(t)||(w.add(t),O(t)))return;let n=null;for(let e=1;e<=h.retry;e++)try{let e=await fetch(`${g}${t}`);n={html:await e.text(),status:e.status};break}catch{e<h.retry&&await new Promise(e=>setTimeout(e,h.retryDelay))}if(!n){D.push({route:t,error:`Failed after ${h.retry} attempts`});return}if(n.status>=400){D.push({route:t,error:`Returned ${n.status}`});return}let i=h.autoSubfolderIndex?l(t,`index.html`):`${t}.html`,a=l(m,i);if(r(c(a),{recursive:!0}),s(a,n.html.replace(`<!DOCTYPE html>`,`<!DOCTYPE html>
|
|
31
|
+
<!-- SSG: prerendered at build time -->`).replaceAll(/<link rel="stylesheet" href="\/assets\/[^"]*\.css">\n?/g,e=>e.includes(`_isolated-island-entry`)?``:e)),E.push(t),console.log(`[prerender] ✅ ${t} → ${i}`),h.crawlLinks)for(let e of S(n.html)){let t=e.endsWith(`/`)&&e!==`/`?e.slice(0,-1):e;!w.has(t)&&!O(t)&&T.push(t)}}))}}finally{console.log(`[prerender] Shutting down server...`),C?.kill(`SIGKILL`)}if(console.log(`[prerender] Done: ${E.length} page(s) prerendered`+(D.length>0?`, ${D.length} error(s)`:``)),_){let e=l(c(p),`_prerender-server.mjs`);n(e)&&(o(e),console.log(`[prerender] Cleaned up wrapper script`))}if(E.length>0){let a=[i,l(t,`.netlify`,`functions-internal`,`server`,`public`),l(t,`.netlify`,`v1`,`functions`,`server`,`public`)].filter(e=>e!==m&&n(c(e)));for(let t of a)for(let i of E){let a=l(i,`index.html`),o=l(m,a),s=l(t,a);n(o)&&(r(c(s),{recursive:!0}),e(o,s))}a.length>0&&console.log(`[prerender] Copied prerendered HTML to ${a.length} additional output dir(s)`)}}export async function runPostBuild(e={}){let t=e.cwd??process.cwd(),r=l(t,`dist`),i=e.prerenderPort??13172;p(t),g(t,r);for(let e of[l(t,`.netlify`,`functions-internal`,`server`,`_ssr`,`ssr.mjs`),l(t,`.netlify`,`v1`,`functions`,`server`,`_ssr`,`ssr.mjs`),l(t,`.output`,`server`,`_ssr`,`ssr.mjs`)])n(e)&&(console.log(`[patch] Patching ${e}`),m(e,r,t));_(r),v(t,r),y(t),e.prerender!==!1&&await C(t,r,e.prerender??{},i),console.log(`[post-build] ✅ Complete`)}
|
|
@@ -13,25 +13,44 @@
|
|
|
13
13
|
*
|
|
14
14
|
* Runs as a post-build step after the main Vite build.
|
|
15
15
|
*/
|
|
16
|
-
interface IslandBuildResult {
|
|
16
|
+
export interface IslandBuildResult {
|
|
17
17
|
island: string;
|
|
18
18
|
success: boolean;
|
|
19
19
|
size?: number;
|
|
20
20
|
error?: string;
|
|
21
|
+
elapsedMs?: number;
|
|
21
22
|
}
|
|
22
23
|
interface IslandSource {
|
|
23
24
|
filePath: string;
|
|
24
25
|
bundleKey: string;
|
|
25
26
|
framework: string;
|
|
26
27
|
}
|
|
28
|
+
/** Tree-shaking configuration for isolated island builds */
|
|
29
|
+
export interface TreeshakeConfig {
|
|
30
|
+
annotations: boolean;
|
|
31
|
+
moduleSideEffects: boolean;
|
|
32
|
+
propertyReadSideEffects: false | "always";
|
|
33
|
+
unknownGlobalSideEffects: boolean;
|
|
34
|
+
manualPureFunctions: string[];
|
|
35
|
+
}
|
|
36
|
+
/** Default tree-shaking config with aggressive settings and Solid runtime pure functions */
|
|
37
|
+
export declare const DEFAULT_TREESHAKE_CONFIG: TreeshakeConfig;
|
|
27
38
|
/**
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
39
|
+
* Deep-merge treeshake overrides into defaults.
|
|
40
|
+
* Scalar fields from overrides replace defaults.
|
|
41
|
+
* `manualPureFunctions` is concatenated (not replaced).
|
|
42
|
+
*/
|
|
43
|
+
export declare function mergeTreeshakeConfig(defaults: TreeshakeConfig, overrides: Partial<TreeshakeConfig>): TreeshakeConfig;
|
|
44
|
+
/** Options for the isolated island builder */
|
|
45
|
+
export interface IsolatedIslandBuilderOptions {
|
|
46
|
+
treeshake?: Partial<TreeshakeConfig>;
|
|
47
|
+
}
|
|
48
|
+
/** Generate the wrapper code for an island. */
|
|
49
|
+
export declare function generateWrapperCode(filePath: string, framework: string): string;
|
|
50
|
+
/** Generate the integration loader module for a specific framework */
|
|
51
|
+
export declare function generateIntegrationLoaderForFramework(framework: string): string;
|
|
52
|
+
/**
|
|
53
|
+
* Build all islands in isolation using Vite.
|
|
35
54
|
*/
|
|
36
|
-
export declare function buildIsolatedIslands(cwd: string, distDir: string, islands: Map<string, IslandSource>, resolveAliases: any[], defineValues: Record<string, unknown
|
|
55
|
+
export declare function buildIsolatedIslands(cwd: string, distDir: string, islands: Map<string, IslandSource>, resolveAliases: any[], defineValues: Record<string, unknown>, options?: IsolatedIslandBuilderOptions): Promise<IslandBuildResult[]>;
|
|
37
56
|
export {};
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import{existsSync as e,statSync as t}from"node:fs";import{resolve as n}from"node:path";function
|
|
2
|
-
`);let r=[]
|
|
3
|
-
`)}async function
|
|
4
|
-
`):`export async function loadIntegrationModule() { return {}; }`}async function o(e){let{createRequire:t}=await import(`node:module`),n=t(`${e}/package.json`),r=e=>{try{return n.resolve(e).replace(/\.js$/,`.mjs`)}catch{return null}},i={preact:r(`preact`),"preact/hooks":r(`preact/hooks`),"preact/compat":r(`preact/compat`),"preact/compat/client":r(`preact/compat/client`),"preact/compat/server":r(`preact/compat/server`),"preact/jsx-runtime":r(`preact/jsx-runtime`),react:r(`preact/compat`),"react/jsx-runtime":r(`preact/jsx-runtime`),"react/jsx-dev-runtime":r(`preact/jsx-runtime`),"react-dom":r(`preact/compat`),"react-dom/client":r(`preact/compat/client`),"react-dom/server":r(`preact/compat/server`)};return{name:`avalon:isolated-preact-compat`,enforce:`pre`,resolveId(e){return i[e]||null}}}export async function buildIsolatedIslands(s,c,l,u,d){if(l.size===0)return[];let{build:f}=await import(`vite`);console.log(`🏝️ Building ${l.size} islands in isolation...`);let p=performance.now(),m=[];for(let[,p]of l){let{filePath:l,bundleKey:h,framework:g}=p,_=`islands/${h}.js`;if(g===`qwik`||g===`lit`){m.push({island:_,success:!0});continue}let v=r(l,g),y=`\0isolated-island-entry`,b=`\0virtual:avalon/integration-loader`;try{let r=await i(g,s);await f({configFile:!1,root:s,logLevel:`silent`,plugins:[{name:`avalon:isolated-island-virtual`,resolveId(e){return e===y?e:e===`virtual:avalon/integration-loader`||e===b?b:null},load(e){return e===y?v:e===b?a(g):null}},await o(s),...r],build:{write:!0,outDir:n(s,c),emptyOutDir:!1,minify:`oxc`,target:`es2020`,rollupOptions:{input:y,output:{format:`es`,entryFileNames:_},preserveEntrySignatures:`exports-only`}},resolve:{alias:u},define:{...d,__DEV__:`false`,__PROD__:`true`,"process.env.NODE_ENV":`"production"`}});let l=n(s,c,_),p=e(l)?t(l).size:0;m.push({island:_,success:!0,size:p}),console.log(` ✅ ${h} (${g}): ${(p/1024).toFixed(1)} KiB`)}catch(e){let t=e instanceof Error?e.message:String(e);console.error(` ❌ ${h} (${g}): ${t}`),m.push({island:_,success:!1,error:t})}}let h=((performance.now()-p)/1e3).toFixed(1),g=m.filter(e=>e.success).length,_=m.filter(e=>!e.success).length;return console.log(`🏝️ Done in ${h}s: ${g} built${_?`, ${_} failed`:``}`),m}
|
|
1
|
+
import{existsSync as e,statSync as t}from"node:fs";import{resolve as n}from"node:path";export const DEFAULT_TREESHAKE_CONFIG={annotations:!0,moduleSideEffects:!1,propertyReadSideEffects:!1,unknownGlobalSideEffects:!1,manualPureFunctions:[`createSignal`,`createEffect`,`createMemo`,`createComponent`,`template`,`insert`,`delegateEvents`,`setAttribute`,`effect`,`memo`,`spread`,`mergeProps`,`splitProps`,`className`,`classList`,`style`,`addEventListener`]};export function mergeTreeshakeConfig(e,t){return{annotations:t.annotations??e.annotations,moduleSideEffects:t.moduleSideEffects??e.moduleSideEffects,propertyReadSideEffects:t.propertyReadSideEffects??e.propertyReadSideEffects,unknownGlobalSideEffects:t.unknownGlobalSideEffects??e.unknownGlobalSideEffects,manualPureFunctions:[...e.manualPureFunctions,...t.manualPureFunctions??[]]}}const a={solid:`@useavalon/solid/client`,preact:`@useavalon/preact/client`,react:`@useavalon/react/client`,vue:`@useavalon/vue/client`,svelte:`@useavalon/svelte/client`};export function generateWrapperCode(e,t){let n=JSON.stringify(e);if(t===`qwik`)return[`export * from ${n};`,`export { _hW } from "@builder.io/qwik";`].join(`
|
|
2
|
+
`);let r=a[t],i=[`import __C from ${n};`,`var Component = __C;`,`export { Component as default, Component };`,`if(typeof globalThis<"u")globalThis.__avalonIsland=Component;`];return r&&i.push(`export { hydrate as __hydrateIsland } from ${JSON.stringify(r)};`),i.join(`
|
|
3
|
+
`)}export function generateIntegrationLoaderForFramework(e){let t=a[e];return t?`export { hydrate } from ${JSON.stringify(t)};`:`export {};`}async function c(e,t){let n=[],{resolve:r}=await import(`node:path`),{existsSync:i}=await import(`node:fs`),{pathToFileURL:a}=await import(`node:url`),o={solid:{pkg:`vite-plugin-solid`,esmEntry:`dist/esm/index.mjs`},vue:{pkg:`@vitejs/plugin-vue`,esmEntry:`dist/index.mjs`},svelte:{pkg:`@sveltejs/vite-plugin-svelte`,esmEntry:`src/index.js`}}[e];if(!o)return n;try{let s=null,c=t;for(let e=0;e<8;e++){let e=r(c,`node_modules`,o.pkg,o.esmEntry);if(i(e)){s=e;break}for(let e of[`solid`,`vue`,`svelte`,`preact`,`react`,`lit`]){let t=r(c,`packages`,`integrations`,e,`node_modules`,o.pkg,o.esmEntry);if(i(t)){s=t;break}}if(s)break;c=r(c,`..`)}if(!s)throw Error(`Cannot find package '${o.pkg}'`);let l=await import(a(s).href);switch(e){case`solid`:n.push((l.default??l)({ssr:!1,hot:!1}));break;case`vue`:n.push((l.default??l)());break;case`svelte`:n.push((l.svelte??l.default)());break}}catch(t){console.warn(` ⚠ Could not load ${e} plugin: ${t instanceof Error?t.message:t}`)}return n}async function l(e){let{createRequire:t}=await import(`node:module`),{existsSync:n}=await import(`node:fs`),r=t(`${e}/package.json`),i=e=>{try{let t=r.resolve(e);return t.endsWith(`.js`)&&n(t.replace(/\.js$/,`.mjs`))?t.replace(/\.js$/,`.mjs`):t}catch{return null}},a={preact:i(`preact`),"preact/hooks":i(`preact/hooks`),"preact/compat":i(`preact/compat`),"preact/compat/client":i(`preact/compat/client`),"preact/compat/server":i(`preact/compat/server`),"preact/jsx-runtime":i(`preact/jsx-runtime`),react:i(`preact/compat`),"react/jsx-runtime":i(`preact/jsx-runtime`),"react/jsx-dev-runtime":i(`preact/jsx-runtime`),"react-dom":i(`preact/compat`),"react-dom/client":i(`preact/compat/client`),"react-dom/server":i(`preact/compat/server`)};return{name:`avalon:isolated-preact-compat`,enforce:`pre`,resolveId(e){return a[e]??null}}}export async function buildIsolatedIslands(a,u,d,f,p,m){if(d.size===0)return[];let{build:h}=await import(`vite`);console.log(`🏝️ Building ${d.size} islands in isolation...`);let g=performance.now(),_=m?.treeshake?mergeTreeshakeConfig(DEFAULT_TREESHAKE_CONFIG,m.treeshake):DEFAULT_TREESHAKE_CONFIG,v=[];for(let[,r]of d){let{filePath:i,bundleKey:d,framework:m}=r,g=`islands/${d}.js`;if(m===`qwik`||m===`lit`){v.push({island:g,success:!0});continue}let y=generateWrapperCode(i,m),b=`\0isolated-island-entry`,x=`\0virtual:avalon/integration-loader`;try{let r=await c(m,a),i=await l(a),o=performance.now();await h({configFile:!1,root:a,logLevel:`silent`,plugins:[{name:`avalon:isolated-island-virtual`,resolveId(e){return e===b?e:e===`virtual:avalon/integration-loader`||e===x?x:null},load(e){return e===b?y:e===x?generateIntegrationLoaderForFramework(m):null}},i,...r],build:{write:!0,outDir:n(a,u),emptyOutDir:!1,minify:`oxc`,target:`es2020`,rollupOptions:{input:b,output:{format:`es`,entryFileNames:g},preserveEntrySignatures:`exports-only`,treeshake:_}},resolve:{alias:f},define:{...p,__DEV__:`false`,__PROD__:`true`,"process.env.NODE_ENV":`"production"`}});let S=performance.now()-o,C=n(a,u,g),w=e(C)?t(C).size:0;v.push({island:g,success:!0,size:w,elapsedMs:S}),console.log(` ✅ ${d} (${m}): ${(w/1024).toFixed(1)} KiB`),S>2e3&&console.warn(` ⚠ ${d} (${m}): build took ${S.toFixed(0)}ms (>2s)`)}catch(e){let t=e instanceof Error?e.message:String(e);console.error(` ❌ ${d} (${m}): ${t}`),v.push({island:g,success:!1,error:t})}}let y=((performance.now()-g)/1e3).toFixed(1),b=v.filter(e=>e.success).length,x=v.filter(e=>!e.success).length;return console.log(`🏝️ Done in ${y}s: ${b} built${x?`, ${x} failed`:``}`),v}
|
|
@@ -8,7 +8,7 @@ export default { loadPage, routes: [] };
|
|
|
8
8
|
export default islandManifest;
|
|
9
9
|
`}function z(e,t){let n={avalon:{streaming:t.streaming??!0,pagesDir:e.pagesDir,layoutsDir:e.layoutsDir,isDev:e.isDev},...t.runtimeConfig};return`export const runtimeConfig = ${JSON.stringify(n,null,2)};\nexport function useRuntimeConfig() { return runtimeConfig; }\nexport default runtimeConfig;\n`}export function generateConfigModule(e,t){let n={streaming:t.streaming??!0,pagesDir:e.pagesDir,layoutsDir:e.layoutsDir,isDev:e.isDev,...t.runtimeConfig};return`const config = ${JSON.stringify(n,null,2)};\nexport function useAvalonConfig() { return config; }\nexport default config;\n`}async function B(e,t,n){let{getAllLayoutDirs:r}=await import(`./module-discovery.js`),{relative:i,resolve:o}=await import(`node:path`),{stat:s}=await import(`node:fs/promises`),c=process.cwd(),l=await r(e.layoutsDir,e.modules,c),u=[],d=0,f=o(c,e.layoutsDir);for(let{dir:t,prefix:n}of l){let r=a(t,`_layout.tsx`);try{if(!(await s(r)).isFile())continue}catch{continue}let o=i(c,r).replaceAll(`\\`,`/`),l=o.startsWith(`/`)?o:`/`+o,p=t.startsWith(f),m=p&&!e.modules?`RootLayout`:`Layout_${d}`;u.push({prefix:n,importPath:l,varName:m,isShared:p}),d++}let p=u.filter(e=>e.isShared),m=u.filter(e=>!e.isShared),h=u.map(e=>`import ${e.varName} from '${e.importPath}';`),g=m.toSorted((e,t)=>t.prefix.length-e.prefix.length).map(e=>{let t=e.prefix===`/`;return` { prefix: ${JSON.stringify(e.prefix)}, Layout: ${e.varName}, skipRoot: ${t} }`}),_=p.length>0?p[0].varName:`null`,v=JSON.stringify(n);return[`// Auto-generated by Avalon — do not edit`,`import { h } from 'preact';`,`import preactRenderToString from 'preact-render-to-string';`,`import { getUniversalCSSForHead } from '@useavalon/avalon/islands/universal-css-collector';`,`import { getUniversalHeadForInjection, injectSolidHydrationScriptIfNeeded } from '@useavalon/avalon/islands/universal-head-collector';`,...h,``,`const RootLayoutComponent = ${_};`,`const _cssLinks = ${v};`,``,`const moduleLayouts = [`,g.join(`,
|
|
10
10
|
`),`];`,``,`function getLayoutsForPath(pathname) {`,` for (const entry of moduleLayouts) {`,` if (entry.prefix === '/' ? pathname === '/' : pathname.startsWith(entry.prefix)) {`,` return entry;`,` }`,` }`,` return null;`,`}`,``,`function injectUniversalAssets(html) {`,` // In dev, inject <link> tags for all discovered CSS files.`,` // The ?direct suffix makes Vite return raw CSS (text/css) instead`,` // of a JS module wrapper, so <link rel="stylesheet"> works.`,` if (process.env.NODE_ENV !== 'production' && _cssLinks.length > 0) {`,` var links = _cssLinks.map(function(href) {`,` return '<link rel="stylesheet" href="' + href + '?direct">';`,` }).join('\\n');`,` if (html.includes('</head>')) {`,` html = html.replace('</head>', links + '\\n</head>');`,` }`,` }`,` const universalCSS = getUniversalCSSForHead(true);`,` if (universalCSS && html.includes('</head>')) {`,` html = html.replace('</head>', universalCSS + '\\n</head>');`,` }`,` const universalHead = getUniversalHeadForInjection(true);`,` if (universalHead && html.includes('</head>')) {`,` html = html.replace('</head>', universalHead + '\\n</head>');`,` }`,` html = injectSolidHydrationScriptIfNeeded(html);`,` return html;`,`}`,``,`export async function wrapWithLayouts(pageHtml, pageModule, context, injectAssets) {`,` const pathname = context.url.pathname;`,` const frontmatter = {`,` ...(pageModule.frontmatter || {}),`,` ...(pageModule.metadata || {}),`,` currentPath: pathname,`,` };`,` const pageLayoutConfig = pageModule.layoutConfig;`,` const skipAll = pageLayoutConfig?.skipLayouts?.includes('_layout');`,``,` const layoutEntry = getLayoutsForPath(pathname);`,` const routeInfo = { path: pathname, params: context.params, query: context.url.searchParams };`,` let html;`,``,` if (!layoutEntry || skipAll) {`,` if (RootLayoutComponent && !skipAll) {`,` const rootProps = {`,` children: h('div', { id: 'app', dangerouslySetInnerHTML: { __html: pageHtml } }),`,` frontmatter,`,` data: {},`,` route: routeInfo,`,` };`,` const rootResult = RootLayoutComponent(rootProps);`,` const resolvedRoot = rootResult instanceof Promise ? await rootResult : rootResult;`,` html = '<!DOCTYPE html>\\n' + preactRenderToString(resolvedRoot);`,` } else {`,` const title = String(frontmatter.title || 'Avalon');`,` html = [`,` '<!DOCTYPE html>',`,` '<html lang="en">',`,` '<head>',`,` '<meta charset="utf-8">',`,` '<meta name="viewport" content="width=device-width, initial-scale=1">',`,` '<title>' + title + '</title>',`,` '</head>',`,` '<body>',`,` '<div id="app">' + pageHtml + '</div>',`,` '</body>',`,` '</html>',`,` ].join('\\n');`,` }`,` } else {`,` const layoutProps = {`,` children: h('div', { dangerouslySetInnerHTML: { __html: pageHtml } }),`,` frontmatter,`,` data: {},`,` route: routeInfo,`,` };`,` const layoutResult = layoutEntry.Layout(layoutProps);`,` const resolvedLayout = layoutResult instanceof Promise ? await layoutResult : layoutResult;`,` let wrappedHtml = preactRenderToString(resolvedLayout);`,``,` if (!layoutEntry.skipRoot && RootLayoutComponent) {`,` const rootProps = {`,` children: h('div', { dangerouslySetInnerHTML: { __html: wrappedHtml } }),`,` frontmatter,`,` data: {},`,` route: routeInfo,`,` };`,` const rootResult = RootLayoutComponent(rootProps);`,` const resolvedRoot = rootResult instanceof Promise ? await rootResult : rootResult;`,` wrappedHtml = preactRenderToString(resolvedRoot);`,` }`,``,` html = '<!DOCTYPE html>\\n' + wrappedHtml;`,` }`,``,` if (injectAssets) {`,` html = injectAssets(html);`,` }`,` return injectUniversalAssets(html);`,`}`,``,`export default { wrapWithLayouts };`,``].join(`
|
|
11
|
-
`)}function V(e){let t=e.clientEntry??`app/entry-client`;return[`// Auto-generated by Avalon — do not edit`,`// @ts-ignore — virtual import resolved by Nitro's Vite assets plugin at build time`,`import clientAssets from '${t.startsWith(`/`)?t:`/`+t}?assets=client';`,``,`function buildAssetTags() {`,` const cssLinks = (clientAssets?.css ?? [])`,` .map(attr => '<link rel="stylesheet" href="' + attr.href + '">')`,` .join('\\n');`,` const jsPreloads = (clientAssets?.js ?? [])`,` .map(attr => '<link rel="modulepreload" href="' + attr.href + '">')`,` .join('\\n');`,` const entryScript = clientAssets?.entry`,` ? '<script type="module" src="' + clientAssets.entry + '"><\/script>'`,` : '';`,` return { cssLinks, jsPreloads, entryScript };`,`}`,``,`export function injectAssets(html) {`,` const { cssLinks, jsPreloads, entryScript } = buildAssetTags();`,` if (html.includes('</head>')) {`,` html = html.replace('</head>', cssLinks + '\\n' + jsPreloads + '\\n</head>');`,` }`,` if (html.includes('</body>')) {`,` html = html.replace('</body>', entryScript + '\\n</body>');`,` }`,` return html;`,`}`,``,`export { clientAssets };`,`export default { injectAssets, clientAssets };`,``].join(`
|
|
11
|
+
`)}function V(e){let t=e.clientEntry??`app/entry-client`;return[`// Auto-generated by Avalon — do not edit`,`// @ts-ignore — virtual import resolved by Nitro's Vite assets plugin at build time`,`import clientAssets from '${t.startsWith(`/`)?t:`/`+t}?assets=client';`,``,`function buildAssetTags() {`,` const cssLinks = (clientAssets?.css ?? [])`,` .filter(attr => {`,` const href = attr.href || '';`,` // Only include global CSS — entry-client and index (layout/global styles)`,` // Island-specific CSS (Counter-*, DocsSidebar-*, _isolated-island-entry-*, etc.)`,` // is loaded on-demand when the island's JS chunk imports it.`,` if (href.includes('entry-client')) return true;`,` if (href.includes('ssr-index')) return true;`,` // The main index CSS contains all CSS module styles — needed globally`,` if (/\\/index-[^/]+\\.css$/.test(href)) return true;`,` return false;`,` })`,` .map(attr => '<link rel="stylesheet" href="' + attr.href + '">')`,` .join('\\n');`,` const jsPreloads = (clientAssets?.js ?? [])`,` .map(attr => '<link rel="modulepreload" href="' + attr.href + '">')`,` .join('\\n');`,` const entryScript = clientAssets?.entry`,` ? '<script type="module" src="' + clientAssets.entry + '"><\/script>'`,` : '';`,` return { cssLinks, jsPreloads, entryScript };`,`}`,``,`export function injectAssets(html) {`,` const { cssLinks, jsPreloads, entryScript } = buildAssetTags();`,` if (html.includes('</head>')) {`,` html = html.replace('</head>', cssLinks + '\\n' + jsPreloads + '\\n</head>');`,` }`,` if (html.includes('</body>')) {`,` html = html.replace('</body>', entryScript + '\\n</body>');`,` }`,` return html;`,`}`,``,`export { clientAssets };`,`export default { injectAssets, clientAssets };`,``].join(`
|
|
12
12
|
`)}function H(e){let t=Array.isArray(e.integrations)?e.integrations:[],n=[],r=[];for(let e of t){let t=`${e}Integration`;n.push(`import { ${t} } from '@useavalon/${e}';`),r.push(`registry.register(${t});`)}return[`// Auto-generated by Avalon — do not edit`,`import { createNitroRenderer } from '@useavalon/avalon/nitro/renderer';`,`import { registerBuiltinDirectives } from '@useavalon/avalon';`,`import { registry } from '@useavalon/avalon/islands/integration-registry';`,`import avalonConfig from 'virtual:avalon/config';`,`import { loadPage } from 'virtual:avalon/page-loader';`,`import { wrapWithLayouts } from 'virtual:avalon/layouts';`,`import { injectAssets } from 'virtual:avalon/assets';`,...n,``,`// Pre-register framework integrations for SSR`,...r,``,`// Register built-in custom hydration directives (on:delay, on:scroll, etc.)`,`registerBuiltinDirectives();`,``,`export default createNitroRenderer({`,` avalonConfig,`,` isDev: avalonConfig.isDev,`,` resolvePageRoute: async (pathname) => {`,` const mod = loadPage(pathname);`,` if (!mod || !('default' in mod)) return null;`,` return { filePath: '[virtual:' + pathname + ']', pattern: pathname, params: {} };`,` },`,` loadPageModule: async (filePath) => {`,` const match = filePath.match(/^\\[virtual:(.+)\\]$/);`,` const pathname = match ? match[1] : filePath;`,` const mod = loadPage(pathname);`,` if (mod) return mod;`,` return { default: () => null, metadata: { title: 'Avalon' } };`,` },`,` wrapWithLayouts: (pageHtml, pageModule, context) =>`,` wrapWithLayouts(pageHtml, pageModule, context, injectAssets),`,`});`,``].join(`
|
|
13
13
|
`)}async function U(e,t){let{getAllLayoutDirs:n}=await import(`./module-discovery.js`),{readdir:r}=await import(`node:fs/promises`),{relative:i,join:a}=await import(`node:path`),o=process.cwd(),s=await n(e.layoutsDir,e.modules,o),c=[];for(let{dir:e}of s)try{let t=await r(e,{withFileTypes:!0});for(let n of t){if(!n.isFile()||!n.name.endsWith(`.css`))continue;let t=i(o,a(e,n.name)).replaceAll(`\\`,`/`),r=t.startsWith(`/`)?t:`/`+t;c.push(r)}}catch{}let l=globalThis.__avalonConfig?.isDev??e.isDev?`@useavalon/avalon/client/main`:`@useavalon/avalon/client/main-slim`,u=[`// Auto-generated by Avalon — do not edit`,`// Island hydration runtime`];(globalThis.__avalonHydrationMode??`entry-client`)===`entry-client`?u.push(`import '${l}';`):u.push(`// Per-island hydration mode — no shared runtime needed`),u.push(``);let d=t.globalCSS??[];for(let e of d){let t=e.startsWith(`/`)?e:`/`+e;u.push(`// Global CSS`),u.push(`import '${t}';`)}if(d.length>0&&u.push(``),c.length>0){u.push(`// Layout CSS (auto-discovered)`);let e=0;for(let t of c)t.includes(`.module.`)?(u.push(`import _lcss${e} from '${t}';`),e++):u.push(`import '${t}';`)}return u.push(``),u.join(`
|
|
14
14
|
`)}export function generateIntegrationLoaderModule(e){let t=(e.integrations??[]).map(e=>typeof e==`string`?e:e.name),n={preact:`@useavalon/preact/client`,react:`@useavalon/preact/client`,vue:`@useavalon/vue/client`,svelte:`@useavalon/svelte/client`,solid:`@useavalon/solid/client`,lit:`@useavalon/lit/client`,qwik:`@useavalon/qwik/client`},r={preact:`@useavalon/preact/client/hmr`,react:`@useavalon/react/client/hmr`,vue:`@useavalon/vue/client/hmr`,svelte:`@useavalon/svelte/client/hmr`,solid:`@useavalon/solid/client/hmr`,lit:`@useavalon/lit/client/hmr`,qwik:`@useavalon/qwik/client/hmr`},i=t.includes(`lit`),a=t.includes(`solid`),o=(globalThis.__avalonConfig?.isDev??e.isDev)===!0,s=[`// Auto-generated by Avalon — only includes configured integrations`,``];a&&!o&&(s.push(`// --- Inlined Solid adapter (production) ---`),s.push(`// Eliminates a separate chunk + network request for the Solid client adapter.`),s.push(`// Only imports hydrate/createComponent — no render() fallback (saves ~1-2 KiB).`),s.push(`function _ensureHydrationContext() {`),s.push(` if (!globalThis._$HY) {`),s.push(` globalThis._$HY = { events: [], completed: new WeakSet(), r: {}, fe() {} };`),s.push(` }`),s.push(`}`),s.push(``),s.push(`async function _solidHydrate(container, Component, props) {`),s.push(` if (!container) throw new Error("Container element is required for hydration");`),s.push(` if (!Component || typeof Component !== "function") {`),s.push(` throw new Error("Invalid Solid component: expected function, got " + typeof Component);`),s.push(` }`),s.push(` var el = container;`),s.push(` var renderId = el.dataset.solidRenderId || el.dataset.renderId;`),s.push(` var { hydrate: solidHydrate, createComponent } = await import("solid-js/web");`),s.push(` _ensureHydrationContext();`),s.push(` solidHydrate(function() { return createComponent(Component, props || {}); }, el, { renderId: renderId || "" });`),s.push(`}`),s.push(``),s.push(`var _solidModule = { hydrate: _solidHydrate };`),s.push(``)),s.push(`// --- loadIntegrationModule ---`),s.push(`export async function loadIntegrationModule(framework) {`),s.push(` switch (framework) {`);for(let e of t){let t=n[e];t&&(e===`solid`&&!o?(s.push(` case "solid":`),s.push(` return _solidModule;`)):e===`react`?s.push(` case "react":`):e===`preact`?(s.push(` case "preact":`),s.push(` return import("${t}");`)):(s.push(` case "${e}":`),s.push(` return import("${t}");`)))}t.includes(`react`)&&!t.includes(`preact`)&&s.push(` return import("${n.react}");`),s.push(` default:`),s.push(" throw new Error(`Unknown or unconfigured framework: ${framework}`);"),s.push(` }`),s.push(`}`),s.push(``),s.push(`// --- Lit hydration pre-load (only if Lit is configured) ---`),i?(s.push(`export async function preLitHydration() {`),s.push(` await import("@useavalon/lit/client");`),s.push(`}`)):s.push(`export async function preLitHydration() {}`),s.push(``),s.push(`// --- HMR adapter loader ---`),s.push(`export async function loadHMRAdapter(framework) {`),s.push(` switch (framework) {`);for(let e of t){let t=r[e];t&&(s.push(` case "${e}":`),s.push(` return import("${t}").then(m => m.${e}Adapter);`))}return s.push(` default: return null;`),s.push(` }`),s.push(`}`),s.join(`
|