@useavalon/avalon 0.1.13 → 0.1.14
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/mod.js +1 -0
- package/dist/src/build/integration-bundler-plugin.js +1 -0
- package/dist/src/build/integration-config.js +1 -0
- package/dist/src/build/integration-detection-plugin.js +1 -0
- package/dist/src/build/integration-resolver-plugin.js +1 -0
- package/dist/src/build/island-manifest.js +1 -0
- package/dist/src/build/island-types-generator.js +5 -0
- package/dist/src/build/mdx-island-transform.js +2 -0
- package/dist/src/build/mdx-plugin.js +1 -0
- package/dist/src/build/page-island-transform.js +3 -0
- package/dist/src/build/prop-extractors/index.js +1 -0
- package/dist/src/build/prop-extractors/lit.js +1 -0
- package/dist/src/build/prop-extractors/qwik.js +1 -0
- package/dist/src/build/prop-extractors/solid.js +1 -0
- package/dist/src/build/prop-extractors/svelte.js +1 -0
- package/dist/src/build/prop-extractors/vue.js +1 -0
- package/dist/src/build/sidecar-file-manager.js +1 -0
- package/dist/src/build/sidecar-renderer.js +6 -0
- package/dist/src/client/adapters/index.js +1 -0
- package/dist/src/client/components.js +1 -0
- package/dist/src/client/css-hmr-handler.js +1 -0
- package/dist/src/client/framework-adapter.js +13 -0
- package/dist/src/client/hmr-coordinator.js +1 -0
- package/dist/src/client/hmr-error-overlay.js +214 -0
- package/dist/src/client/main.js +39 -0
- package/dist/src/components/Image.js +1 -0
- package/dist/src/components/IslandErrorBoundary.js +1 -0
- package/dist/src/components/LayoutDataErrorBoundary.js +1 -0
- package/dist/src/components/LayoutErrorBoundary.js +1 -0
- package/dist/src/components/PersistentIsland.js +1 -0
- package/dist/src/components/StreamingErrorBoundary.js +1 -0
- package/dist/src/components/StreamingLayout.js +29 -0
- package/dist/src/core/components/component-analyzer.js +1 -0
- package/dist/src/core/components/component-detection.js +5 -0
- package/dist/src/core/components/enhanced-framework-detector.js +1 -0
- package/dist/src/core/components/framework-registry.js +1 -0
- package/dist/src/core/content/mdx-processor.js +1 -0
- package/dist/src/core/integrations/index.js +1 -0
- package/dist/src/core/integrations/loader.js +1 -0
- package/dist/src/core/integrations/registry.js +1 -0
- package/dist/src/core/islands/island-persistence.js +1 -0
- package/dist/src/core/islands/island-state-serializer.js +1 -0
- package/dist/src/core/islands/persistent-island-context.js +1 -0
- package/dist/src/core/islands/use-persistent-state.js +1 -0
- package/dist/src/core/layout/enhanced-layout-resolver.js +1 -0
- package/dist/src/core/layout/layout-cache-manager.js +1 -0
- package/dist/src/core/layout/layout-composer.js +1 -0
- package/dist/src/core/layout/layout-data-loader.js +1 -0
- package/dist/src/core/layout/layout-discovery.js +1 -0
- package/dist/src/core/layout/layout-matcher.js +1 -0
- package/dist/src/core/layout/layout-types.js +1 -0
- package/dist/src/core/modules/framework-module-resolver.js +1 -0
- package/dist/src/islands/component-analysis.js +1 -0
- package/dist/src/islands/css-utils.js +17 -0
- package/dist/src/islands/discovery/index.js +1 -0
- package/dist/src/islands/discovery/registry.js +1 -0
- package/dist/src/islands/discovery/resolver.js +2 -0
- package/dist/src/islands/discovery/scanner.js +1 -0
- package/dist/src/islands/discovery/types.js +1 -0
- package/dist/src/islands/discovery/validator.js +18 -0
- package/dist/src/islands/discovery/watcher.js +1 -0
- package/dist/src/islands/framework-detection.js +1 -0
- package/dist/src/islands/integration-loader.js +1 -0
- package/dist/src/islands/island.js +1 -0
- package/dist/src/islands/render-cache.js +1 -0
- package/dist/src/islands/types.js +1 -0
- package/dist/src/islands/universal-css-collector.js +5 -0
- package/dist/src/islands/universal-head-collector.js +2 -0
- package/dist/src/layout-system.js +1 -0
- package/dist/src/middleware/discovery.js +1 -0
- package/dist/src/middleware/executor.js +1 -0
- package/dist/src/middleware/index.js +1 -0
- package/dist/src/middleware/types.js +1 -0
- package/dist/src/nitro/build-config.js +1 -0
- package/dist/src/nitro/config.js +1 -0
- package/dist/src/nitro/error-handler.js +198 -0
- package/dist/src/nitro/index.js +1 -0
- package/dist/src/nitro/island-manifest.js +2 -0
- package/dist/src/nitro/middleware-adapter.js +1 -0
- package/dist/src/nitro/renderer.js +183 -0
- package/dist/src/nitro/route-discovery.js +1 -0
- package/dist/src/nitro/types.js +1 -0
- package/dist/src/render/collect-css.js +3 -0
- package/dist/src/render/error-pages.js +48 -0
- package/dist/src/render/isolated-ssr-renderer.js +1 -0
- package/dist/src/render/ssr.js +90 -0
- package/dist/src/schemas/api.js +1 -0
- package/dist/src/schemas/core.js +1 -0
- package/dist/src/schemas/index.js +1 -0
- package/dist/src/schemas/layout.js +1 -0
- package/dist/src/schemas/routing/index.js +1 -0
- package/dist/src/schemas/routing.js +1 -0
- package/dist/src/types/as-island.js +1 -0
- package/dist/src/types/layout.js +1 -0
- package/dist/src/types/routing.js +1 -0
- package/dist/src/types/types.js +1 -0
- package/dist/src/utils/dev-logger.js +12 -0
- package/dist/src/utils/fs.js +1 -0
- package/dist/src/vite-plugin/auto-discover.js +1 -0
- package/dist/src/vite-plugin/config.js +1 -0
- package/dist/src/vite-plugin/errors.js +1 -0
- package/dist/src/vite-plugin/image-optimization.js +45 -0
- package/dist/src/vite-plugin/integration-activator.js +1 -0
- package/dist/src/vite-plugin/island-sidecar-plugin.js +1 -0
- package/dist/src/vite-plugin/module-discovery.js +1 -0
- package/dist/src/vite-plugin/nitro-integration.js +42 -0
- package/dist/src/vite-plugin/plugin.js +1 -0
- package/dist/src/vite-plugin/types.js +1 -0
- package/dist/src/vite-plugin/validation.js +2 -0
- package/package.json +14 -20
- package/mod.ts +0 -302
- package/src/build/integration-bundler-plugin.ts +0 -116
- package/src/build/integration-config.ts +0 -168
- package/src/build/integration-detection-plugin.ts +0 -117
- package/src/build/integration-resolver-plugin.ts +0 -90
- package/src/build/island-manifest.ts +0 -269
- package/src/build/island-types-generator.ts +0 -476
- package/src/build/mdx-island-transform.ts +0 -464
- package/src/build/mdx-plugin.ts +0 -98
- package/src/build/page-island-transform.ts +0 -598
- package/src/build/prop-extractors/index.ts +0 -21
- package/src/build/prop-extractors/lit.ts +0 -140
- package/src/build/prop-extractors/qwik.ts +0 -16
- package/src/build/prop-extractors/solid.ts +0 -125
- package/src/build/prop-extractors/svelte.ts +0 -194
- package/src/build/prop-extractors/vue.ts +0 -111
- package/src/build/sidecar-file-manager.ts +0 -104
- package/src/build/sidecar-renderer.ts +0 -30
- package/src/client/adapters/index.ts +0 -21
- package/src/client/components.ts +0 -35
- package/src/client/css-hmr-handler.ts +0 -344
- package/src/client/framework-adapter.ts +0 -462
- package/src/client/hmr-coordinator.ts +0 -396
- package/src/client/hmr-error-overlay.js +0 -533
- package/src/client/main.js +0 -824
- package/src/components/Image.tsx +0 -123
- package/src/components/IslandErrorBoundary.tsx +0 -145
- package/src/components/LayoutDataErrorBoundary.tsx +0 -141
- package/src/components/LayoutErrorBoundary.tsx +0 -127
- package/src/components/PersistentIsland.tsx +0 -52
- package/src/components/StreamingErrorBoundary.tsx +0 -233
- package/src/components/StreamingLayout.tsx +0 -538
- package/src/core/components/component-analyzer.ts +0 -192
- package/src/core/components/component-detection.ts +0 -508
- package/src/core/components/enhanced-framework-detector.ts +0 -500
- package/src/core/components/framework-registry.ts +0 -563
- package/src/core/content/mdx-processor.ts +0 -46
- package/src/core/integrations/index.ts +0 -19
- package/src/core/integrations/loader.ts +0 -125
- package/src/core/integrations/registry.ts +0 -175
- package/src/core/islands/island-persistence.ts +0 -325
- package/src/core/islands/island-state-serializer.ts +0 -258
- package/src/core/islands/persistent-island-context.tsx +0 -80
- package/src/core/islands/use-persistent-state.ts +0 -68
- package/src/core/layout/enhanced-layout-resolver.ts +0 -322
- package/src/core/layout/layout-cache-manager.ts +0 -485
- package/src/core/layout/layout-composer.ts +0 -357
- package/src/core/layout/layout-data-loader.ts +0 -516
- package/src/core/layout/layout-discovery.ts +0 -243
- package/src/core/layout/layout-matcher.ts +0 -299
- package/src/core/layout/layout-types.ts +0 -110
- package/src/core/modules/framework-module-resolver.ts +0 -273
- package/src/islands/component-analysis.ts +0 -213
- package/src/islands/css-utils.ts +0 -565
- package/src/islands/discovery/index.ts +0 -80
- package/src/islands/discovery/registry.ts +0 -340
- package/src/islands/discovery/resolver.ts +0 -477
- package/src/islands/discovery/scanner.ts +0 -386
- package/src/islands/discovery/types.ts +0 -117
- package/src/islands/discovery/validator.ts +0 -544
- package/src/islands/discovery/watcher.ts +0 -368
- package/src/islands/framework-detection.ts +0 -428
- package/src/islands/integration-loader.ts +0 -490
- package/src/islands/island.tsx +0 -565
- package/src/islands/render-cache.ts +0 -550
- package/src/islands/types.ts +0 -80
- package/src/islands/universal-css-collector.ts +0 -157
- package/src/islands/universal-head-collector.ts +0 -137
- package/src/layout-system.ts +0 -218
- package/src/middleware/discovery.ts +0 -268
- package/src/middleware/executor.ts +0 -315
- package/src/middleware/index.ts +0 -76
- package/src/middleware/types.ts +0 -99
- package/src/nitro/build-config.ts +0 -576
- package/src/nitro/config.ts +0 -483
- package/src/nitro/error-handler.ts +0 -636
- package/src/nitro/index.ts +0 -173
- package/src/nitro/island-manifest.ts +0 -584
- package/src/nitro/middleware-adapter.ts +0 -260
- package/src/nitro/renderer.ts +0 -1471
- package/src/nitro/route-discovery.ts +0 -439
- package/src/nitro/types.ts +0 -321
- package/src/render/collect-css.ts +0 -198
- package/src/render/error-pages.ts +0 -79
- package/src/render/isolated-ssr-renderer.ts +0 -654
- package/src/render/ssr.ts +0 -1030
- package/src/schemas/api.ts +0 -30
- package/src/schemas/core.ts +0 -64
- package/src/schemas/index.ts +0 -212
- package/src/schemas/layout.ts +0 -279
- package/src/schemas/routing/index.ts +0 -38
- package/src/schemas/routing.ts +0 -376
- package/src/types/as-island.ts +0 -20
- package/src/types/layout.ts +0 -285
- package/src/types/routing.ts +0 -555
- package/src/types/types.ts +0 -5
- package/src/utils/dev-logger.ts +0 -299
- package/src/utils/fs.ts +0 -151
- package/src/vite-plugin/auto-discover.ts +0 -551
- package/src/vite-plugin/config.ts +0 -266
- package/src/vite-plugin/errors.ts +0 -127
- package/src/vite-plugin/image-optimization.ts +0 -156
- package/src/vite-plugin/integration-activator.ts +0 -126
- package/src/vite-plugin/island-sidecar-plugin.ts +0 -176
- package/src/vite-plugin/module-discovery.ts +0 -189
- package/src/vite-plugin/nitro-integration.ts +0 -1354
- package/src/vite-plugin/plugin.ts +0 -403
- package/src/vite-plugin/types.ts +0 -327
- package/src/vite-plugin/validation.ts +0 -228
- /package/{src → dist/src}/client/types/framework-runtime.d.ts +0 -0
- /package/{src → dist/src}/client/types/vite-hmr.d.ts +0 -0
- /package/{src → dist/src}/client/types/vite-virtual-modules.d.ts +0 -0
- /package/{src → dist/src}/layout-system.d.ts +0 -0
- /package/{src → dist/src}/types/image.d.ts +0 -0
- /package/{src → dist/src}/types/index.d.ts +0 -0
- /package/{src → dist/src}/types/island-jsx.d.ts +0 -0
- /package/{src → dist/src}/types/island-prop.d.ts +0 -0
- /package/{src → dist/src}/types/mdx.d.ts +0 -0
- /package/{src → dist/src}/types/urlpattern.d.ts +0 -0
- /package/{src → dist/src}/types/vite-env.d.ts +0 -0
|
@@ -1,654 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Isolated SSR Renderer
|
|
3
|
-
*
|
|
4
|
-
* This module provides framework-specific SSR contexts to prevent cross-contamination
|
|
5
|
-
* between different frameworks during server-side rendering. Each framework gets its
|
|
6
|
-
* own isolated import context and rendering pipeline.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import type { JSX } from 'preact';
|
|
10
|
-
import { render as preactRenderToString } from 'preact-render-to-string';
|
|
11
|
-
import { readFile } from 'node:fs/promises';
|
|
12
|
-
import { EnhancedFrameworkDetector } from '../core/components/enhanced-framework-detector.ts';
|
|
13
|
-
import { toImportSpecifier } from '../middleware/executor.ts';
|
|
14
|
-
|
|
15
|
-
export interface FrameworkSSRContext {
|
|
16
|
-
framework: string;
|
|
17
|
-
imports: Map<string, unknown>;
|
|
18
|
-
renderFunction: (component: unknown, props: unknown) => Promise<string>;
|
|
19
|
-
cleanup: () => void;
|
|
20
|
-
isActive: boolean;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export interface SSRIsolationConfig {
|
|
24
|
-
enableStrictIsolation: boolean;
|
|
25
|
-
allowedCrossFrameworkImports: string[];
|
|
26
|
-
errorHandling: 'strict' | 'fallback' | 'ignore';
|
|
27
|
-
debugLogging: boolean;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export interface IsolatedRenderRequest {
|
|
31
|
-
componentPath: string;
|
|
32
|
-
component: () => JSX.Element | Promise<JSX.Element>;
|
|
33
|
-
framework?: string;
|
|
34
|
-
props?: Record<string, unknown>;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export interface IsolatedRenderResult {
|
|
38
|
-
html: string;
|
|
39
|
-
framework: string;
|
|
40
|
-
success: boolean;
|
|
41
|
-
errors: string[];
|
|
42
|
-
warnings: string[];
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Isolated SSR Renderer with framework-specific contexts
|
|
47
|
-
*/
|
|
48
|
-
export class IsolatedSSRRenderer {
|
|
49
|
-
private readonly contexts: Map<string, FrameworkSSRContext>;
|
|
50
|
-
private readonly detector: EnhancedFrameworkDetector;
|
|
51
|
-
private config: SSRIsolationConfig;
|
|
52
|
-
private activeContext: string | null = null;
|
|
53
|
-
|
|
54
|
-
constructor(config: Partial<SSRIsolationConfig> = {}) {
|
|
55
|
-
this.contexts = new Map();
|
|
56
|
-
this.detector = new EnhancedFrameworkDetector();
|
|
57
|
-
this.config = {
|
|
58
|
-
enableStrictIsolation: true,
|
|
59
|
-
allowedCrossFrameworkImports: ['preact', 'preact-render-to-string'],
|
|
60
|
-
errorHandling: 'fallback',
|
|
61
|
-
debugLogging: false,
|
|
62
|
-
...config,
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
this.initializeFrameworkContexts();
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Renders a component with framework isolation
|
|
70
|
-
*/
|
|
71
|
-
async renderWithIsolation(request: IsolatedRenderRequest): Promise<IsolatedRenderResult> {
|
|
72
|
-
const errors: string[] = [];
|
|
73
|
-
const warnings: string[] = [];
|
|
74
|
-
|
|
75
|
-
try {
|
|
76
|
-
const framework = await this.resolveFramework(request, warnings);
|
|
77
|
-
return await this.renderInContext(request, framework, errors, warnings);
|
|
78
|
-
} catch (error) {
|
|
79
|
-
errors.push(`SSR rendering failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
80
|
-
return await this.tryFallbackRender(request, errors, warnings);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
private async resolveFramework(request: IsolatedRenderRequest, warnings: string[]): Promise<string> {
|
|
85
|
-
if (request.framework) return request.framework;
|
|
86
|
-
|
|
87
|
-
try {
|
|
88
|
-
const content = await this.getComponentContent(request.componentPath);
|
|
89
|
-
const detection = this.detector.detectFramework(request.componentPath, content);
|
|
90
|
-
|
|
91
|
-
if (detection.confidence === 'low') {
|
|
92
|
-
warnings.push(`Low confidence framework detection for ${request.componentPath}: ${detection.framework}`);
|
|
93
|
-
}
|
|
94
|
-
if (this.config.debugLogging) {
|
|
95
|
-
console.log(`[SSR Isolation] Detected framework: ${detection.framework} for ${request.componentPath}`);
|
|
96
|
-
console.log(`[SSR Isolation] Evidence: ${detection.evidence.join(', ')}`);
|
|
97
|
-
}
|
|
98
|
-
return detection.framework;
|
|
99
|
-
} catch {
|
|
100
|
-
// Component path is a virtual/route path — can't read file, default to preact
|
|
101
|
-
warnings.push(
|
|
102
|
-
`Could not read component file for framework detection: ${request.componentPath}, defaulting to preact`,
|
|
103
|
-
);
|
|
104
|
-
return 'preact';
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
private async renderInContext(
|
|
109
|
-
request: IsolatedRenderRequest,
|
|
110
|
-
framework: string,
|
|
111
|
-
errors: string[],
|
|
112
|
-
warnings: string[],
|
|
113
|
-
): Promise<IsolatedRenderResult> {
|
|
114
|
-
const context = this.getFrameworkContext(framework);
|
|
115
|
-
if (!context) throw new Error(`No SSR context available for framework: ${framework}`);
|
|
116
|
-
|
|
117
|
-
await this.switchToContext(framework);
|
|
118
|
-
try {
|
|
119
|
-
const componentResult = request.component();
|
|
120
|
-
const resolvedComponent = componentResult instanceof Promise ? await componentResult : componentResult;
|
|
121
|
-
const html = await context.renderFunction(resolvedComponent, request.props || {});
|
|
122
|
-
return { html, framework, success: true, errors, warnings };
|
|
123
|
-
} finally {
|
|
124
|
-
this.cleanupContext(framework);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
private async tryFallbackRender(
|
|
129
|
-
request: IsolatedRenderRequest,
|
|
130
|
-
errors: string[],
|
|
131
|
-
warnings: string[],
|
|
132
|
-
): Promise<IsolatedRenderResult> {
|
|
133
|
-
if (this.config.errorHandling !== 'fallback') {
|
|
134
|
-
return { html: '', framework: request.framework || 'unknown', success: false, errors, warnings };
|
|
135
|
-
}
|
|
136
|
-
try {
|
|
137
|
-
const resolvedComponent = await request.component();
|
|
138
|
-
const html = preactRenderToString(resolvedComponent);
|
|
139
|
-
warnings.push('Fell back to Preact rendering due to framework-specific error');
|
|
140
|
-
return { html, framework: 'preact', success: true, errors, warnings };
|
|
141
|
-
} catch (fallbackError) {
|
|
142
|
-
errors.push(
|
|
143
|
-
`Fallback rendering also failed: ${fallbackError instanceof Error ? fallbackError.message : String(fallbackError)}`,
|
|
144
|
-
);
|
|
145
|
-
return { html: '', framework: request.framework || 'unknown', success: false, errors, warnings };
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* Initializes framework-specific SSR contexts
|
|
151
|
-
*/
|
|
152
|
-
private initializeFrameworkContexts(): void {
|
|
153
|
-
// Preact context
|
|
154
|
-
this.contexts.set('preact', {
|
|
155
|
-
framework: 'preact',
|
|
156
|
-
imports: new Map(),
|
|
157
|
-
renderFunction: (component: unknown) => {
|
|
158
|
-
return Promise.resolve(preactRenderToString(component as JSX.Element));
|
|
159
|
-
},
|
|
160
|
-
cleanup: () => {
|
|
161
|
-
this.clearFrameworkGlobals('preact');
|
|
162
|
-
},
|
|
163
|
-
isActive: false,
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
this.contexts.set('solid', {
|
|
167
|
-
framework: 'solid',
|
|
168
|
-
imports: new Map(),
|
|
169
|
-
renderFunction: async (component: unknown) => {
|
|
170
|
-
try {
|
|
171
|
-
// Import Solid SSR modules in isolation
|
|
172
|
-
const solidWeb = (await this.importFrameworkModule('solid-js/web', 'solid')) as Record<string, unknown>;
|
|
173
|
-
if (solidWeb && typeof solidWeb.renderToString === 'function') {
|
|
174
|
-
return (solidWeb.renderToString as (fn: () => unknown) => string)(() => component);
|
|
175
|
-
}
|
|
176
|
-
throw new Error('Solid renderToString not available');
|
|
177
|
-
} catch (error) {
|
|
178
|
-
throw new Error(`Solid SSR failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
179
|
-
}
|
|
180
|
-
},
|
|
181
|
-
cleanup: () => {
|
|
182
|
-
this.clearFrameworkGlobals('solid');
|
|
183
|
-
},
|
|
184
|
-
isActive: false,
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
this.contexts.set('vue', {
|
|
188
|
-
framework: 'vue',
|
|
189
|
-
imports: new Map(),
|
|
190
|
-
renderFunction: async (component: unknown) => {
|
|
191
|
-
try {
|
|
192
|
-
// Import Vue SSR modules in isolation
|
|
193
|
-
const vueServerRenderer = (await this.importFrameworkModule('vue/server-renderer', 'vue')) as Record<
|
|
194
|
-
string,
|
|
195
|
-
unknown
|
|
196
|
-
>;
|
|
197
|
-
if (vueServerRenderer && typeof vueServerRenderer.renderToString === 'function') {
|
|
198
|
-
return await (vueServerRenderer.renderToString as (component: unknown) => Promise<string>)(component);
|
|
199
|
-
}
|
|
200
|
-
throw new Error('Vue renderToString not available');
|
|
201
|
-
} catch (error) {
|
|
202
|
-
throw new Error(`Vue SSR failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
203
|
-
}
|
|
204
|
-
},
|
|
205
|
-
cleanup: () => {
|
|
206
|
-
this.clearFrameworkGlobals('vue');
|
|
207
|
-
},
|
|
208
|
-
isActive: false,
|
|
209
|
-
});
|
|
210
|
-
|
|
211
|
-
this.contexts.set('svelte', {
|
|
212
|
-
framework: 'svelte',
|
|
213
|
-
imports: new Map(),
|
|
214
|
-
renderFunction: (component: unknown) => {
|
|
215
|
-
try {
|
|
216
|
-
// Svelte components have a render method
|
|
217
|
-
if (component && typeof component === 'object' && 'render' in component) {
|
|
218
|
-
const renderResult = (component as { render: () => { html?: string } }).render();
|
|
219
|
-
return Promise.resolve(renderResult.html || '');
|
|
220
|
-
}
|
|
221
|
-
throw new Error('Svelte component does not have render method');
|
|
222
|
-
} catch (error) {
|
|
223
|
-
throw new Error(`Svelte SSR failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
224
|
-
}
|
|
225
|
-
},
|
|
226
|
-
cleanup: () => {
|
|
227
|
-
this.clearFrameworkGlobals('svelte');
|
|
228
|
-
},
|
|
229
|
-
isActive: false,
|
|
230
|
-
});
|
|
231
|
-
|
|
232
|
-
this.contexts.set('unknown', {
|
|
233
|
-
framework: 'unknown',
|
|
234
|
-
imports: new Map(),
|
|
235
|
-
renderFunction: (component: unknown) => {
|
|
236
|
-
// Fallback to Preact rendering
|
|
237
|
-
return Promise.resolve(preactRenderToString(component as JSX.Element));
|
|
238
|
-
},
|
|
239
|
-
cleanup: () => {
|
|
240
|
-
// No specific cleanup needed
|
|
241
|
-
},
|
|
242
|
-
isActive: false,
|
|
243
|
-
});
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
/**
|
|
247
|
-
* Gets or creates a framework context
|
|
248
|
-
*/
|
|
249
|
-
private getFrameworkContext(framework: string): FrameworkSSRContext | null {
|
|
250
|
-
const context = this.contexts.get(framework);
|
|
251
|
-
if (context) {
|
|
252
|
-
return context;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
// If framework not found, use unknown/fallback context
|
|
256
|
-
return this.contexts.get('unknown') || null;
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
/**
|
|
260
|
-
* Switches to a specific framework context with isolation
|
|
261
|
-
*/
|
|
262
|
-
private async switchToContext(framework: string): Promise<void> {
|
|
263
|
-
// Cleanup previous context if active
|
|
264
|
-
if (this.activeContext && this.activeContext !== framework) {
|
|
265
|
-
this.cleanupContext(this.activeContext);
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
const context = this.contexts.get(framework);
|
|
269
|
-
if (!context) {
|
|
270
|
-
throw new Error(`Framework context not found: ${framework}`);
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
// Activate the context
|
|
274
|
-
context.isActive = true;
|
|
275
|
-
this.activeContext = framework;
|
|
276
|
-
|
|
277
|
-
// Set up framework-specific environment
|
|
278
|
-
await this.setupFrameworkEnvironment(framework);
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
/**
|
|
282
|
-
* Cleans up a framework context
|
|
283
|
-
*/
|
|
284
|
-
private cleanupContext(framework: string): void {
|
|
285
|
-
const context = this.contexts.get(framework);
|
|
286
|
-
if (!context) {
|
|
287
|
-
return;
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
// Run framework-specific cleanup
|
|
291
|
-
context.cleanup();
|
|
292
|
-
context.isActive = false;
|
|
293
|
-
|
|
294
|
-
// Clear framework-specific imports
|
|
295
|
-
context.imports.clear();
|
|
296
|
-
|
|
297
|
-
if (this.activeContext === framework) {
|
|
298
|
-
this.activeContext = null;
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
/**
|
|
303
|
-
* Sets up framework-specific environment
|
|
304
|
-
*/
|
|
305
|
-
private async setupFrameworkEnvironment(framework: string): Promise<void> {
|
|
306
|
-
// Framework-specific setup logic
|
|
307
|
-
switch (framework) {
|
|
308
|
-
case 'solid':
|
|
309
|
-
// Ensure Solid-specific globals are available
|
|
310
|
-
await this.ensureSolidEnvironment();
|
|
311
|
-
break;
|
|
312
|
-
case 'vue':
|
|
313
|
-
// Ensure Vue-specific globals are available
|
|
314
|
-
await this.ensureVueEnvironment();
|
|
315
|
-
break;
|
|
316
|
-
case 'svelte':
|
|
317
|
-
// Ensure Svelte-specific globals are available
|
|
318
|
-
this.ensureSvelteEnvironment();
|
|
319
|
-
break;
|
|
320
|
-
case 'preact':
|
|
321
|
-
default:
|
|
322
|
-
// Preact is the default, no special setup needed
|
|
323
|
-
break;
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
/**
|
|
328
|
-
* Imports a framework module with isolation
|
|
329
|
-
*/
|
|
330
|
-
private async importFrameworkModule(modulePath: string, framework: string): Promise<unknown> {
|
|
331
|
-
const context = this.contexts.get(framework);
|
|
332
|
-
if (!context) {
|
|
333
|
-
throw new Error(`No context for framework: ${framework}`);
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
// Check if module is already imported in this context
|
|
337
|
-
if (context.imports.has(modulePath)) {
|
|
338
|
-
return context.imports.get(modulePath);
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
// Validate import is allowed for this framework
|
|
342
|
-
if (this.config.enableStrictIsolation && !this.isImportAllowed(modulePath, framework)) {
|
|
343
|
-
throw new Error(`Import not allowed in ${framework} context: ${modulePath}`);
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
try {
|
|
347
|
-
// Import the module
|
|
348
|
-
const module = await import(/* @vite-ignore */ toImportSpecifier(modulePath));
|
|
349
|
-
|
|
350
|
-
// Store in context-specific imports
|
|
351
|
-
context.imports.set(modulePath, module);
|
|
352
|
-
|
|
353
|
-
if (this.config.debugLogging) {
|
|
354
|
-
console.log(`[SSR Isolation] Imported ${modulePath} in ${framework} context`);
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
return module;
|
|
358
|
-
} catch (error) {
|
|
359
|
-
throw new Error(
|
|
360
|
-
`Failed to import ${modulePath} in ${framework} context: ${
|
|
361
|
-
error instanceof Error ? error.message : String(error)
|
|
362
|
-
}`,
|
|
363
|
-
);
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
/**
|
|
368
|
-
* Checks if an import is allowed for a specific framework
|
|
369
|
-
*/
|
|
370
|
-
private isImportAllowed(modulePath: string, framework: string): boolean {
|
|
371
|
-
// Always allow framework-specific modules
|
|
372
|
-
const frameworkConfig = this.detector.getFrameworkConfigs().get(framework);
|
|
373
|
-
if (frameworkConfig) {
|
|
374
|
-
const allowedModules = [...frameworkConfig.ssrModules, ...frameworkConfig.hydrationModules];
|
|
375
|
-
if (allowedModules.some(allowed => modulePath.startsWith(allowed))) {
|
|
376
|
-
return true;
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
// Check globally allowed cross-framework imports
|
|
381
|
-
return this.config.allowedCrossFrameworkImports.some(allowed => modulePath.startsWith(allowed));
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
/**
|
|
385
|
-
* Clears framework-specific globals
|
|
386
|
-
*/
|
|
387
|
-
private clearFrameworkGlobals(framework: string): void {
|
|
388
|
-
// Clear framework-specific globals to prevent contamination
|
|
389
|
-
const globals = globalThis as Record<string, unknown>;
|
|
390
|
-
switch (framework) {
|
|
391
|
-
case 'solid':
|
|
392
|
-
// Clear Solid-specific globals if they exist
|
|
393
|
-
if (typeof globalThis !== 'undefined') {
|
|
394
|
-
delete globals._$HY;
|
|
395
|
-
delete globals.Solid;
|
|
396
|
-
}
|
|
397
|
-
break;
|
|
398
|
-
case 'vue':
|
|
399
|
-
// Clear Vue-specific globals if they exist
|
|
400
|
-
if (typeof globalThis !== 'undefined') {
|
|
401
|
-
delete globals.__VUE__;
|
|
402
|
-
delete globals.Vue;
|
|
403
|
-
}
|
|
404
|
-
break;
|
|
405
|
-
case 'svelte':
|
|
406
|
-
// Clear Svelte-specific globals if they exist
|
|
407
|
-
if (typeof globalThis !== 'undefined') {
|
|
408
|
-
delete globals.__SVELTE__;
|
|
409
|
-
}
|
|
410
|
-
break;
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
/**
|
|
415
|
-
* Ensures Solid environment is properly set up
|
|
416
|
-
*/
|
|
417
|
-
private async ensureSolidEnvironment(): Promise<void> {
|
|
418
|
-
try {
|
|
419
|
-
// Import Solid modules needed for SSR
|
|
420
|
-
await this.importFrameworkModule('solid-js/web', 'solid');
|
|
421
|
-
} catch (error) {
|
|
422
|
-
if (this.config.debugLogging) {
|
|
423
|
-
console.warn('[SSR Isolation] Failed to set up Solid environment:', error);
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
/**
|
|
429
|
-
* Ensures Vue environment is properly set up
|
|
430
|
-
*/
|
|
431
|
-
private async ensureVueEnvironment(): Promise<void> {
|
|
432
|
-
try {
|
|
433
|
-
// Import Vue modules needed for SSR
|
|
434
|
-
await this.importFrameworkModule('vue/server-renderer', 'vue');
|
|
435
|
-
} catch (error) {
|
|
436
|
-
if (this.config.debugLogging) {
|
|
437
|
-
console.warn('[SSR Isolation] Failed to set up Vue environment:', error);
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
/**
|
|
443
|
-
* Ensures Svelte environment is properly set up
|
|
444
|
-
*/
|
|
445
|
-
private ensureSvelteEnvironment(): void {
|
|
446
|
-
try {
|
|
447
|
-
// Svelte components are typically pre-compiled, no special setup needed
|
|
448
|
-
if (this.config.debugLogging) {
|
|
449
|
-
console.log('[SSR Isolation] Svelte environment ready');
|
|
450
|
-
}
|
|
451
|
-
} catch (error) {
|
|
452
|
-
if (this.config.debugLogging) {
|
|
453
|
-
console.warn('[SSR Isolation] Failed to set up Svelte environment:', error);
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
/**
|
|
459
|
-
* Gets component content for framework detection
|
|
460
|
-
*/
|
|
461
|
-
private async getComponentContent(componentPath: string): Promise<string> {
|
|
462
|
-
try {
|
|
463
|
-
// Try to read the component file
|
|
464
|
-
let resolvedPath = componentPath;
|
|
465
|
-
|
|
466
|
-
// Handle different path formats
|
|
467
|
-
if (componentPath.startsWith('/')) {
|
|
468
|
-
resolvedPath = componentPath.substring(1);
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
// Try multiple path variations
|
|
472
|
-
const pathVariations = [
|
|
473
|
-
resolvedPath,
|
|
474
|
-
`src/islands/${resolvedPath.split('/').pop()}`,
|
|
475
|
-
`islands/${resolvedPath.split('/').pop()}`,
|
|
476
|
-
`examples/${resolvedPath.split('/').pop()}`,
|
|
477
|
-
];
|
|
478
|
-
|
|
479
|
-
for (const pathVariation of pathVariations) {
|
|
480
|
-
try {
|
|
481
|
-
return await readFile(pathVariation, 'utf-8');
|
|
482
|
-
} catch {
|
|
483
|
-
// Continue to next path variation
|
|
484
|
-
continue;
|
|
485
|
-
}
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
throw new Error(`Component file not found: ${componentPath}`);
|
|
489
|
-
} catch (error) {
|
|
490
|
-
throw new Error(`Failed to read component content: ${error instanceof Error ? error.message : String(error)}`);
|
|
491
|
-
}
|
|
492
|
-
}
|
|
493
|
-
|
|
494
|
-
/**
|
|
495
|
-
* Gets current active context
|
|
496
|
-
*/
|
|
497
|
-
getActiveContext(): string | null {
|
|
498
|
-
return this.activeContext;
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
/**
|
|
502
|
-
* Gets all framework contexts
|
|
503
|
-
*/
|
|
504
|
-
getContexts(): Map<string, FrameworkSSRContext> {
|
|
505
|
-
return new Map(this.contexts);
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
/**
|
|
509
|
-
* Updates configuration
|
|
510
|
-
*/
|
|
511
|
-
updateConfig(config: Partial<SSRIsolationConfig>): void {
|
|
512
|
-
this.config = { ...this.config, ...config };
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
/**
|
|
516
|
-
* Resets all contexts
|
|
517
|
-
*/
|
|
518
|
-
resetAllContexts(): void {
|
|
519
|
-
for (const [framework] of this.contexts) {
|
|
520
|
-
this.cleanupContext(framework);
|
|
521
|
-
}
|
|
522
|
-
this.activeContext = null;
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
/**
|
|
526
|
-
* Creates fallback rendering when framework modules are unavailable
|
|
527
|
-
*/
|
|
528
|
-
async renderWithFallback(
|
|
529
|
-
component: () => JSX.Element | Promise<JSX.Element>,
|
|
530
|
-
preferredFramework: string,
|
|
531
|
-
): Promise<IsolatedRenderResult> {
|
|
532
|
-
const errors: string[] = [];
|
|
533
|
-
const warnings: string[] = [];
|
|
534
|
-
|
|
535
|
-
// Try preferred framework first
|
|
536
|
-
try {
|
|
537
|
-
const request: IsolatedRenderRequest = {
|
|
538
|
-
componentPath: 'fallback-component',
|
|
539
|
-
component,
|
|
540
|
-
framework: preferredFramework,
|
|
541
|
-
};
|
|
542
|
-
|
|
543
|
-
const result = await this.renderWithIsolation(request);
|
|
544
|
-
if (result.success) {
|
|
545
|
-
return result;
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
errors.push(...result.errors);
|
|
549
|
-
warnings.push(...result.warnings);
|
|
550
|
-
} catch (error) {
|
|
551
|
-
errors.push(
|
|
552
|
-
`Preferred framework (${preferredFramework}) failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
553
|
-
);
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
// Try fallback frameworks in order of preference
|
|
557
|
-
const fallbackOrder = ['preact', 'unknown'];
|
|
558
|
-
|
|
559
|
-
for (const fallbackFramework of fallbackOrder) {
|
|
560
|
-
if (fallbackFramework === preferredFramework) {
|
|
561
|
-
continue; // Already tried
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
try {
|
|
565
|
-
const request: IsolatedRenderRequest = {
|
|
566
|
-
componentPath: 'fallback-component',
|
|
567
|
-
component,
|
|
568
|
-
framework: fallbackFramework,
|
|
569
|
-
};
|
|
570
|
-
|
|
571
|
-
const result = await this.renderWithIsolation(request);
|
|
572
|
-
if (result.success) {
|
|
573
|
-
warnings.push(`Fell back to ${fallbackFramework} rendering from ${preferredFramework}`);
|
|
574
|
-
return {
|
|
575
|
-
...result,
|
|
576
|
-
warnings: [...warnings, ...result.warnings],
|
|
577
|
-
};
|
|
578
|
-
}
|
|
579
|
-
|
|
580
|
-
errors.push(...result.errors);
|
|
581
|
-
} catch (error) {
|
|
582
|
-
errors.push(
|
|
583
|
-
`Fallback framework (${fallbackFramework}) failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
584
|
-
);
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
// All frameworks failed, return error result
|
|
589
|
-
return {
|
|
590
|
-
html: '',
|
|
591
|
-
framework: preferredFramework,
|
|
592
|
-
success: false,
|
|
593
|
-
errors,
|
|
594
|
-
warnings,
|
|
595
|
-
};
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
/**
|
|
599
|
-
* Validates that a framework context is properly set up
|
|
600
|
-
*/
|
|
601
|
-
async validateFrameworkContext(framework: string): Promise<boolean> {
|
|
602
|
-
const context = this.contexts.get(framework);
|
|
603
|
-
if (!context) {
|
|
604
|
-
return false;
|
|
605
|
-
}
|
|
606
|
-
|
|
607
|
-
try {
|
|
608
|
-
// Try to set up the framework environment
|
|
609
|
-
await this.setupFrameworkEnvironment(framework);
|
|
610
|
-
return true;
|
|
611
|
-
} catch (error) {
|
|
612
|
-
if (this.config.debugLogging) {
|
|
613
|
-
console.warn(`[SSR Isolation] Framework context validation failed for ${framework}:`, error);
|
|
614
|
-
}
|
|
615
|
-
return false;
|
|
616
|
-
}
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
/**
|
|
620
|
-
* Gets framework-specific error recovery strategies
|
|
621
|
-
*/
|
|
622
|
-
getErrorRecoveryStrategies(framework: string): string[] {
|
|
623
|
-
const strategies: Record<string, string[]> = {
|
|
624
|
-
solid: [
|
|
625
|
-
'Ensure solid-js and solid-js/web are installed',
|
|
626
|
-
'Check that Solid components use proper JSX import source: /** @jsxImportSource solid-js */',
|
|
627
|
-
'Verify Solid components export default function',
|
|
628
|
-
],
|
|
629
|
-
vue: [
|
|
630
|
-
'Ensure vue and vue/server-renderer are installed',
|
|
631
|
-
'Check that Vue components have proper <template>, <script>, and <style> sections',
|
|
632
|
-
'Verify Vue components are properly compiled for SSR',
|
|
633
|
-
],
|
|
634
|
-
svelte: [
|
|
635
|
-
'Ensure svelte is installed and components are compiled',
|
|
636
|
-
'Check that Svelte components export default class or function',
|
|
637
|
-
'Verify Svelte components have proper script and style sections',
|
|
638
|
-
],
|
|
639
|
-
preact: [
|
|
640
|
-
'Ensure preact and preact-render-to-string are installed',
|
|
641
|
-
'Check that Preact components use proper JSX import source: /** @jsxImportSource preact */',
|
|
642
|
-
'Verify Preact components export default function',
|
|
643
|
-
],
|
|
644
|
-
};
|
|
645
|
-
|
|
646
|
-
return (
|
|
647
|
-
strategies[framework] || [
|
|
648
|
-
'Check that the framework is properly installed',
|
|
649
|
-
'Verify component syntax is correct for the detected framework',
|
|
650
|
-
'Consider adding explicit framework detection hints',
|
|
651
|
-
]
|
|
652
|
-
);
|
|
653
|
-
}
|
|
654
|
-
}
|