@useavalon/avalon 0.1.11 → 0.1.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +54 -54
- package/mod.ts +302 -302
- package/package.json +49 -26
- package/src/build/integration-bundler-plugin.ts +116 -116
- package/src/build/integration-config.ts +168 -168
- package/src/build/integration-detection-plugin.ts +117 -117
- package/src/build/integration-resolver-plugin.ts +90 -90
- package/src/build/island-manifest.ts +269 -269
- package/src/build/island-types-generator.ts +476 -476
- package/src/build/mdx-island-transform.ts +464 -464
- package/src/build/mdx-plugin.ts +98 -98
- package/src/build/page-island-transform.ts +598 -598
- package/src/build/prop-extractors/index.ts +21 -21
- package/src/build/prop-extractors/lit.ts +140 -140
- package/src/build/prop-extractors/qwik.ts +16 -16
- package/src/build/prop-extractors/solid.ts +125 -125
- package/src/build/prop-extractors/svelte.ts +194 -194
- package/src/build/prop-extractors/vue.ts +111 -111
- package/src/build/sidecar-file-manager.ts +104 -104
- package/src/build/sidecar-renderer.ts +30 -30
- package/src/client/adapters/index.ts +21 -13
- package/src/client/components.ts +35 -35
- package/src/client/css-hmr-handler.ts +344 -344
- package/src/client/framework-adapter.ts +462 -462
- package/src/client/hmr-coordinator.ts +396 -396
- package/src/client/hmr-error-overlay.js +533 -533
- package/src/client/main.js +824 -816
- package/src/client/types/framework-runtime.d.ts +68 -68
- package/src/client/types/vite-hmr.d.ts +46 -46
- package/src/client/types/vite-virtual-modules.d.ts +70 -60
- package/src/components/Image.tsx +123 -123
- package/src/components/IslandErrorBoundary.tsx +145 -145
- package/src/components/LayoutDataErrorBoundary.tsx +141 -141
- package/src/components/LayoutErrorBoundary.tsx +127 -127
- package/src/components/PersistentIsland.tsx +52 -52
- package/src/components/StreamingErrorBoundary.tsx +233 -233
- package/src/components/StreamingLayout.tsx +538 -538
- package/src/core/components/component-analyzer.ts +192 -192
- package/src/core/components/component-detection.ts +508 -508
- package/src/core/components/enhanced-framework-detector.ts +500 -500
- package/src/core/components/framework-registry.ts +563 -563
- package/src/core/content/mdx-processor.ts +46 -46
- package/src/core/integrations/index.ts +19 -19
- package/src/core/integrations/loader.ts +125 -125
- package/src/core/integrations/registry.ts +175 -175
- package/src/core/islands/island-persistence.ts +325 -325
- package/src/core/islands/island-state-serializer.ts +258 -258
- package/src/core/islands/persistent-island-context.tsx +80 -80
- package/src/core/islands/use-persistent-state.ts +68 -68
- package/src/core/layout/enhanced-layout-resolver.ts +322 -322
- package/src/core/layout/layout-cache-manager.ts +485 -485
- package/src/core/layout/layout-composer.ts +357 -357
- package/src/core/layout/layout-data-loader.ts +516 -516
- package/src/core/layout/layout-discovery.ts +243 -243
- package/src/core/layout/layout-matcher.ts +299 -299
- package/src/core/layout/layout-types.ts +110 -110
- package/src/core/modules/framework-module-resolver.ts +273 -273
- package/src/islands/component-analysis.ts +213 -213
- package/src/islands/css-utils.ts +565 -565
- package/src/islands/discovery/index.ts +80 -80
- package/src/islands/discovery/registry.ts +340 -340
- package/src/islands/discovery/resolver.ts +477 -477
- package/src/islands/discovery/scanner.ts +386 -386
- package/src/islands/discovery/types.ts +117 -117
- package/src/islands/discovery/validator.ts +544 -544
- package/src/islands/discovery/watcher.ts +368 -368
- package/src/islands/framework-detection.ts +428 -428
- package/src/islands/integration-loader.ts +490 -490
- package/src/islands/island.tsx +565 -565
- package/src/islands/render-cache.ts +550 -550
- package/src/islands/types.ts +80 -80
- package/src/islands/universal-css-collector.ts +157 -157
- package/src/islands/universal-head-collector.ts +137 -137
- package/src/layout-system.d.ts +592 -592
- package/src/layout-system.ts +218 -218
- package/src/middleware/discovery.ts +268 -268
- package/src/middleware/executor.ts +315 -315
- package/src/middleware/index.ts +76 -76
- package/src/middleware/types.ts +99 -99
- package/src/nitro/build-config.ts +575 -575
- package/src/nitro/config.ts +483 -483
- package/src/nitro/error-handler.ts +636 -636
- package/src/nitro/index.ts +173 -173
- package/src/nitro/island-manifest.ts +584 -584
- package/src/nitro/middleware-adapter.ts +260 -260
- package/src/nitro/renderer.ts +1471 -1471
- package/src/nitro/route-discovery.ts +439 -439
- package/src/nitro/types.ts +321 -321
- package/src/render/collect-css.ts +198 -198
- package/src/render/error-pages.ts +79 -79
- package/src/render/isolated-ssr-renderer.ts +654 -654
- package/src/render/ssr.ts +1030 -1030
- package/src/schemas/api.ts +30 -30
- package/src/schemas/core.ts +64 -64
- package/src/schemas/index.ts +212 -212
- package/src/schemas/layout.ts +279 -279
- package/src/schemas/routing/index.ts +38 -38
- package/src/schemas/routing.ts +376 -376
- package/src/types/as-island.ts +20 -20
- package/src/types/image.d.ts +106 -106
- package/src/types/index.d.ts +22 -22
- package/src/types/island-jsx.d.ts +33 -33
- package/src/types/island-prop.d.ts +20 -20
- package/src/types/layout.ts +285 -285
- package/src/types/mdx.d.ts +6 -6
- package/src/types/routing.ts +555 -555
- package/src/types/types.ts +5 -5
- package/src/types/urlpattern.d.ts +49 -49
- package/src/types/vite-env.d.ts +11 -11
- package/src/utils/dev-logger.ts +299 -299
- package/src/utils/fs.ts +151 -151
- package/src/vite-plugin/auto-discover.ts +551 -551
- package/src/vite-plugin/config.ts +266 -266
- package/src/vite-plugin/errors.ts +127 -127
- package/src/vite-plugin/image-optimization.ts +156 -156
- package/src/vite-plugin/integration-activator.ts +126 -126
- package/src/vite-plugin/island-sidecar-plugin.ts +176 -176
- package/src/vite-plugin/module-discovery.ts +189 -189
- package/src/vite-plugin/nitro-integration.ts +1354 -1354
- package/src/vite-plugin/plugin.ts +403 -409
- package/src/vite-plugin/types.ts +327 -327
- package/src/vite-plugin/validation.ts +228 -228
- package/src/client/adapters/index.js +0 -12
- package/src/client/adapters/lit-adapter.js +0 -467
- package/src/client/adapters/lit-adapter.ts +0 -654
- package/src/client/adapters/preact-adapter.js +0 -223
- package/src/client/adapters/preact-adapter.ts +0 -331
- package/src/client/adapters/qwik-adapter.js +0 -259
- package/src/client/adapters/qwik-adapter.ts +0 -345
- package/src/client/adapters/react-adapter.js +0 -220
- package/src/client/adapters/react-adapter.ts +0 -353
- package/src/client/adapters/solid-adapter.js +0 -295
- package/src/client/adapters/solid-adapter.ts +0 -451
- package/src/client/adapters/svelte-adapter.js +0 -368
- package/src/client/adapters/svelte-adapter.ts +0 -524
- package/src/client/adapters/vue-adapter.js +0 -278
- package/src/client/adapters/vue-adapter.ts +0 -467
- package/src/client/components.js +0 -23
- package/src/client/css-hmr-handler.js +0 -263
- package/src/client/framework-adapter.js +0 -283
- package/src/client/hmr-coordinator.js +0 -274
|
@@ -1,213 +1,213 @@
|
|
|
1
|
-
import type { JSX } from 'preact';
|
|
2
|
-
import {
|
|
3
|
-
analyzeComponentContent,
|
|
4
|
-
type AnalyzerOptions,
|
|
5
|
-
type AnalysisReport,
|
|
6
|
-
} from '../core/components/component-analyzer.ts';
|
|
7
|
-
import { resolveIslandPath } from './framework-detection.ts';
|
|
8
|
-
import type { IslandProps } from './types.ts';
|
|
9
|
-
import { getCachedAnalysis, setCachedAnalysis, getCachedPath, setCachedPath } from './render-cache.ts';
|
|
10
|
-
import { readFile } from 'node:fs/promises';
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Check if we're in development mode
|
|
14
|
-
*/
|
|
15
|
-
function isDev(): boolean {
|
|
16
|
-
try {
|
|
17
|
-
return process.env.NODE_ENV !== 'production';
|
|
18
|
-
} catch {
|
|
19
|
-
return true; // Default to dev mode if we can't check
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Log cache hit/miss in dev mode
|
|
25
|
-
*/
|
|
26
|
-
function logCacheEvent(_type: 'hit' | 'miss', _cacheType: string, _src: string): void {
|
|
27
|
-
// Silenced — set AVALON_VERBOSE=1 to enable
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Get essential path variations for a component
|
|
32
|
-
* Reduced from 22 variations to essential ones for better performance
|
|
33
|
-
*/
|
|
34
|
-
function getEssentialPathVariations(src: string, resolvedSrc: string): string[] {
|
|
35
|
-
const baseName =
|
|
36
|
-
src
|
|
37
|
-
.split('/')
|
|
38
|
-
.pop()
|
|
39
|
-
?.replace(/\.(tsx|jsx|vue|svelte|ts|js)$/, '') || '';
|
|
40
|
-
|
|
41
|
-
// Get the original file extension
|
|
42
|
-
const originalExt = src.split('.').pop() || 'tsx';
|
|
43
|
-
|
|
44
|
-
// Essential path variations - prioritized by likelihood
|
|
45
|
-
return [
|
|
46
|
-
// Direct paths first (most likely to succeed)
|
|
47
|
-
resolvedSrc.startsWith('/') ? resolvedSrc.substring(1) : resolvedSrc,
|
|
48
|
-
src.startsWith('/') ? src.substring(1) : src,
|
|
49
|
-
// Standard island locations
|
|
50
|
-
`src/islands/${baseName}.${originalExt}`,
|
|
51
|
-
`src/islands/${baseName}.tsx`,
|
|
52
|
-
`islands/${baseName}.${originalExt}`,
|
|
53
|
-
`islands/${baseName}.tsx`,
|
|
54
|
-
// Framework-specific extensions (only for common frameworks)
|
|
55
|
-
`src/islands/${baseName}.svelte`,
|
|
56
|
-
`src/islands/${baseName}.vue`,
|
|
57
|
-
`src/islands/${baseName}.solid.tsx`,
|
|
58
|
-
];
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Try to read a file asynchronously, returning null if not found
|
|
63
|
-
*/
|
|
64
|
-
async function tryReadFile(path: string): Promise<string | null> {
|
|
65
|
-
try {
|
|
66
|
-
return await readFile(path, 'utf-8');
|
|
67
|
-
} catch {
|
|
68
|
-
return null;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Analyze component file for rendering strategy
|
|
74
|
-
*
|
|
75
|
-
* Attempts to read the component file from various path variations and
|
|
76
|
-
* analyzes its content to determine the optimal rendering strategy.
|
|
77
|
-
* Uses caching to avoid repeated file I/O and analysis for the same components.
|
|
78
|
-
*
|
|
79
|
-
* @param src - The source path to the component
|
|
80
|
-
* @param options - Analyzer options for customizing the analysis
|
|
81
|
-
* @returns Analysis result with rendering strategy decision
|
|
82
|
-
* @throws Error if component file cannot be found
|
|
83
|
-
*/
|
|
84
|
-
export async function analyzeComponentFile(src: string, options: AnalyzerOptions = {}): Promise<AnalysisReport> {
|
|
85
|
-
// Check analysis cache first
|
|
86
|
-
const cachedAnalysis = getCachedAnalysis(src);
|
|
87
|
-
if (cachedAnalysis) {
|
|
88
|
-
logCacheEvent('hit', 'analysis', src);
|
|
89
|
-
return cachedAnalysis;
|
|
90
|
-
}
|
|
91
|
-
logCacheEvent('miss', 'analysis', src);
|
|
92
|
-
|
|
93
|
-
// Check if we have a cached resolved path
|
|
94
|
-
let resolvedSrc = getCachedPath(src);
|
|
95
|
-
if (resolvedSrc) {
|
|
96
|
-
logCacheEvent('hit', 'path', src);
|
|
97
|
-
} else {
|
|
98
|
-
logCacheEvent('miss', 'path', src);
|
|
99
|
-
resolvedSrc = await resolveIslandPath(src);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// Get essential path variations (reduced from 22 to ~9)
|
|
103
|
-
const pathVariations = getEssentialPathVariations(src, resolvedSrc);
|
|
104
|
-
|
|
105
|
-
// Try each path variation
|
|
106
|
-
for (const pathVariation of pathVariations) {
|
|
107
|
-
const content = await tryReadFile(pathVariation);
|
|
108
|
-
if (content !== null) {
|
|
109
|
-
// Cache the resolved path for future lookups
|
|
110
|
-
setCachedPath(src, pathVariation);
|
|
111
|
-
|
|
112
|
-
// Analyze the component content
|
|
113
|
-
const result = analyzeComponentContent(pathVariation, content, options);
|
|
114
|
-
|
|
115
|
-
// Cache the analysis result
|
|
116
|
-
setCachedAnalysis(src, result);
|
|
117
|
-
|
|
118
|
-
return result;
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
throw new Error(`Component file not found: ${src}`);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Render component with SSR-only strategy (no hydration)
|
|
127
|
-
*
|
|
128
|
-
* Renders a component server-side without adding client-side hydration.
|
|
129
|
-
* This is useful for static components that don't require interactivity.
|
|
130
|
-
*
|
|
131
|
-
* @param params - Rendering parameters
|
|
132
|
-
* @param params.src - Component source path
|
|
133
|
-
* @param params.condition - Island hydration condition
|
|
134
|
-
* @param params.props - Props to pass to the component
|
|
135
|
-
* @param params.framework - Optional explicit framework (if not provided, will be detected)
|
|
136
|
-
* @param params.renderOptions - Additional render options
|
|
137
|
-
* @returns Island component with SSR-only rendering
|
|
138
|
-
* @throws Error if SSR rendering fails
|
|
139
|
-
*/
|
|
140
|
-
export async function renderComponentSSROnly({
|
|
141
|
-
src,
|
|
142
|
-
condition,
|
|
143
|
-
props,
|
|
144
|
-
framework: explicitFramework,
|
|
145
|
-
renderOptions,
|
|
146
|
-
}: {
|
|
147
|
-
src: string;
|
|
148
|
-
condition: IslandProps['condition'];
|
|
149
|
-
props: Record<string, unknown>;
|
|
150
|
-
framework?: string;
|
|
151
|
-
renderOptions: AnalyzerOptions;
|
|
152
|
-
}) {
|
|
153
|
-
try {
|
|
154
|
-
// Import Island component dynamically to avoid circular dependencies
|
|
155
|
-
const { default: Island } = await import('./island.tsx');
|
|
156
|
-
|
|
157
|
-
// Import integration loader to load the appropriate framework integration
|
|
158
|
-
const { loadIntegration } = await import('./integration-loader.ts');
|
|
159
|
-
const { detectFramework } = await import('./framework-detection.ts');
|
|
160
|
-
|
|
161
|
-
// Use explicit framework if provided, otherwise detect it
|
|
162
|
-
let framework: string;
|
|
163
|
-
if (explicitFramework) {
|
|
164
|
-
framework = explicitFramework;
|
|
165
|
-
} else if (src.endsWith('.vue')) {
|
|
166
|
-
framework = 'vue';
|
|
167
|
-
} else if (src.endsWith('.svelte')) {
|
|
168
|
-
framework = 'svelte';
|
|
169
|
-
} else if (src.endsWith('.tsx') || src.endsWith('.jsx') || src.endsWith('.ts') || src.endsWith('.js')) {
|
|
170
|
-
framework = await detectFramework(src);
|
|
171
|
-
} else {
|
|
172
|
-
framework = 'preact'; // Default fallback
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
// Load the appropriate integration
|
|
176
|
-
const integration = await loadIntegration(framework);
|
|
177
|
-
|
|
178
|
-
// Get Vite server reference for dev mode
|
|
179
|
-
const viteServer = globalThis.__viteDevServer;
|
|
180
|
-
const isDev = process.env.NODE_ENV !== 'production';
|
|
181
|
-
|
|
182
|
-
// Render the component using the integration
|
|
183
|
-
const renderResult = await integration.render({
|
|
184
|
-
component: null, // Integration will load the component from src
|
|
185
|
-
props,
|
|
186
|
-
src,
|
|
187
|
-
condition,
|
|
188
|
-
ssrOnly: true,
|
|
189
|
-
viteServer,
|
|
190
|
-
isDev,
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
// Return Island component with the rendered HTML as children
|
|
194
|
-
// This ensures the HTML is properly wrapped in <avalon-island> with ssrOnly attributes
|
|
195
|
-
return Island({
|
|
196
|
-
src,
|
|
197
|
-
condition,
|
|
198
|
-
props,
|
|
199
|
-
children: renderResult.html, // Pass rendered HTML as children
|
|
200
|
-
ssr: true,
|
|
201
|
-
framework: framework as 'solid' | 'vue' | 'preact' | 'react' | 'svelte' | 'lit' | 'qwik',
|
|
202
|
-
ssrOnly: true,
|
|
203
|
-
renderOptions,
|
|
204
|
-
hydrationData: undefined, // No hydration data for SSR-only components
|
|
205
|
-
});
|
|
206
|
-
} catch (error) {
|
|
207
|
-
// Only log errors in development
|
|
208
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
209
|
-
console.error(`SSR-only rendering failed for ${src}:`, error);
|
|
210
|
-
}
|
|
211
|
-
throw error;
|
|
212
|
-
}
|
|
213
|
-
}
|
|
1
|
+
import type { JSX } from 'preact';
|
|
2
|
+
import {
|
|
3
|
+
analyzeComponentContent,
|
|
4
|
+
type AnalyzerOptions,
|
|
5
|
+
type AnalysisReport,
|
|
6
|
+
} from '../core/components/component-analyzer.ts';
|
|
7
|
+
import { resolveIslandPath } from './framework-detection.ts';
|
|
8
|
+
import type { IslandProps } from './types.ts';
|
|
9
|
+
import { getCachedAnalysis, setCachedAnalysis, getCachedPath, setCachedPath } from './render-cache.ts';
|
|
10
|
+
import { readFile } from 'node:fs/promises';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Check if we're in development mode
|
|
14
|
+
*/
|
|
15
|
+
function isDev(): boolean {
|
|
16
|
+
try {
|
|
17
|
+
return process.env.NODE_ENV !== 'production';
|
|
18
|
+
} catch {
|
|
19
|
+
return true; // Default to dev mode if we can't check
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Log cache hit/miss in dev mode
|
|
25
|
+
*/
|
|
26
|
+
function logCacheEvent(_type: 'hit' | 'miss', _cacheType: string, _src: string): void {
|
|
27
|
+
// Silenced — set AVALON_VERBOSE=1 to enable
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Get essential path variations for a component
|
|
32
|
+
* Reduced from 22 variations to essential ones for better performance
|
|
33
|
+
*/
|
|
34
|
+
function getEssentialPathVariations(src: string, resolvedSrc: string): string[] {
|
|
35
|
+
const baseName =
|
|
36
|
+
src
|
|
37
|
+
.split('/')
|
|
38
|
+
.pop()
|
|
39
|
+
?.replace(/\.(tsx|jsx|vue|svelte|ts|js)$/, '') || '';
|
|
40
|
+
|
|
41
|
+
// Get the original file extension
|
|
42
|
+
const originalExt = src.split('.').pop() || 'tsx';
|
|
43
|
+
|
|
44
|
+
// Essential path variations - prioritized by likelihood
|
|
45
|
+
return [
|
|
46
|
+
// Direct paths first (most likely to succeed)
|
|
47
|
+
resolvedSrc.startsWith('/') ? resolvedSrc.substring(1) : resolvedSrc,
|
|
48
|
+
src.startsWith('/') ? src.substring(1) : src,
|
|
49
|
+
// Standard island locations
|
|
50
|
+
`src/islands/${baseName}.${originalExt}`,
|
|
51
|
+
`src/islands/${baseName}.tsx`,
|
|
52
|
+
`islands/${baseName}.${originalExt}`,
|
|
53
|
+
`islands/${baseName}.tsx`,
|
|
54
|
+
// Framework-specific extensions (only for common frameworks)
|
|
55
|
+
`src/islands/${baseName}.svelte`,
|
|
56
|
+
`src/islands/${baseName}.vue`,
|
|
57
|
+
`src/islands/${baseName}.solid.tsx`,
|
|
58
|
+
];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Try to read a file asynchronously, returning null if not found
|
|
63
|
+
*/
|
|
64
|
+
async function tryReadFile(path: string): Promise<string | null> {
|
|
65
|
+
try {
|
|
66
|
+
return await readFile(path, 'utf-8');
|
|
67
|
+
} catch {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Analyze component file for rendering strategy
|
|
74
|
+
*
|
|
75
|
+
* Attempts to read the component file from various path variations and
|
|
76
|
+
* analyzes its content to determine the optimal rendering strategy.
|
|
77
|
+
* Uses caching to avoid repeated file I/O and analysis for the same components.
|
|
78
|
+
*
|
|
79
|
+
* @param src - The source path to the component
|
|
80
|
+
* @param options - Analyzer options for customizing the analysis
|
|
81
|
+
* @returns Analysis result with rendering strategy decision
|
|
82
|
+
* @throws Error if component file cannot be found
|
|
83
|
+
*/
|
|
84
|
+
export async function analyzeComponentFile(src: string, options: AnalyzerOptions = {}): Promise<AnalysisReport> {
|
|
85
|
+
// Check analysis cache first
|
|
86
|
+
const cachedAnalysis = getCachedAnalysis(src);
|
|
87
|
+
if (cachedAnalysis) {
|
|
88
|
+
logCacheEvent('hit', 'analysis', src);
|
|
89
|
+
return cachedAnalysis;
|
|
90
|
+
}
|
|
91
|
+
logCacheEvent('miss', 'analysis', src);
|
|
92
|
+
|
|
93
|
+
// Check if we have a cached resolved path
|
|
94
|
+
let resolvedSrc = getCachedPath(src);
|
|
95
|
+
if (resolvedSrc) {
|
|
96
|
+
logCacheEvent('hit', 'path', src);
|
|
97
|
+
} else {
|
|
98
|
+
logCacheEvent('miss', 'path', src);
|
|
99
|
+
resolvedSrc = await resolveIslandPath(src);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Get essential path variations (reduced from 22 to ~9)
|
|
103
|
+
const pathVariations = getEssentialPathVariations(src, resolvedSrc);
|
|
104
|
+
|
|
105
|
+
// Try each path variation
|
|
106
|
+
for (const pathVariation of pathVariations) {
|
|
107
|
+
const content = await tryReadFile(pathVariation);
|
|
108
|
+
if (content !== null) {
|
|
109
|
+
// Cache the resolved path for future lookups
|
|
110
|
+
setCachedPath(src, pathVariation);
|
|
111
|
+
|
|
112
|
+
// Analyze the component content
|
|
113
|
+
const result = analyzeComponentContent(pathVariation, content, options);
|
|
114
|
+
|
|
115
|
+
// Cache the analysis result
|
|
116
|
+
setCachedAnalysis(src, result);
|
|
117
|
+
|
|
118
|
+
return result;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
throw new Error(`Component file not found: ${src}`);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Render component with SSR-only strategy (no hydration)
|
|
127
|
+
*
|
|
128
|
+
* Renders a component server-side without adding client-side hydration.
|
|
129
|
+
* This is useful for static components that don't require interactivity.
|
|
130
|
+
*
|
|
131
|
+
* @param params - Rendering parameters
|
|
132
|
+
* @param params.src - Component source path
|
|
133
|
+
* @param params.condition - Island hydration condition
|
|
134
|
+
* @param params.props - Props to pass to the component
|
|
135
|
+
* @param params.framework - Optional explicit framework (if not provided, will be detected)
|
|
136
|
+
* @param params.renderOptions - Additional render options
|
|
137
|
+
* @returns Island component with SSR-only rendering
|
|
138
|
+
* @throws Error if SSR rendering fails
|
|
139
|
+
*/
|
|
140
|
+
export async function renderComponentSSROnly({
|
|
141
|
+
src,
|
|
142
|
+
condition,
|
|
143
|
+
props,
|
|
144
|
+
framework: explicitFramework,
|
|
145
|
+
renderOptions,
|
|
146
|
+
}: {
|
|
147
|
+
src: string;
|
|
148
|
+
condition: IslandProps['condition'];
|
|
149
|
+
props: Record<string, unknown>;
|
|
150
|
+
framework?: string;
|
|
151
|
+
renderOptions: AnalyzerOptions;
|
|
152
|
+
}) {
|
|
153
|
+
try {
|
|
154
|
+
// Import Island component dynamically to avoid circular dependencies
|
|
155
|
+
const { default: Island } = await import('./island.tsx');
|
|
156
|
+
|
|
157
|
+
// Import integration loader to load the appropriate framework integration
|
|
158
|
+
const { loadIntegration } = await import('./integration-loader.ts');
|
|
159
|
+
const { detectFramework } = await import('./framework-detection.ts');
|
|
160
|
+
|
|
161
|
+
// Use explicit framework if provided, otherwise detect it
|
|
162
|
+
let framework: string;
|
|
163
|
+
if (explicitFramework) {
|
|
164
|
+
framework = explicitFramework;
|
|
165
|
+
} else if (src.endsWith('.vue')) {
|
|
166
|
+
framework = 'vue';
|
|
167
|
+
} else if (src.endsWith('.svelte')) {
|
|
168
|
+
framework = 'svelte';
|
|
169
|
+
} else if (src.endsWith('.tsx') || src.endsWith('.jsx') || src.endsWith('.ts') || src.endsWith('.js')) {
|
|
170
|
+
framework = await detectFramework(src);
|
|
171
|
+
} else {
|
|
172
|
+
framework = 'preact'; // Default fallback
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Load the appropriate integration
|
|
176
|
+
const integration = await loadIntegration(framework);
|
|
177
|
+
|
|
178
|
+
// Get Vite server reference for dev mode
|
|
179
|
+
const viteServer = globalThis.__viteDevServer;
|
|
180
|
+
const isDev = process.env.NODE_ENV !== 'production';
|
|
181
|
+
|
|
182
|
+
// Render the component using the integration
|
|
183
|
+
const renderResult = await integration.render({
|
|
184
|
+
component: null, // Integration will load the component from src
|
|
185
|
+
props,
|
|
186
|
+
src,
|
|
187
|
+
condition,
|
|
188
|
+
ssrOnly: true,
|
|
189
|
+
viteServer,
|
|
190
|
+
isDev,
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
// Return Island component with the rendered HTML as children
|
|
194
|
+
// This ensures the HTML is properly wrapped in <avalon-island> with ssrOnly attributes
|
|
195
|
+
return Island({
|
|
196
|
+
src,
|
|
197
|
+
condition,
|
|
198
|
+
props,
|
|
199
|
+
children: renderResult.html, // Pass rendered HTML as children
|
|
200
|
+
ssr: true,
|
|
201
|
+
framework: framework as 'solid' | 'vue' | 'preact' | 'react' | 'svelte' | 'lit' | 'qwik',
|
|
202
|
+
ssrOnly: true,
|
|
203
|
+
renderOptions,
|
|
204
|
+
hydrationData: undefined, // No hydration data for SSR-only components
|
|
205
|
+
});
|
|
206
|
+
} catch (error) {
|
|
207
|
+
// Only log errors in development
|
|
208
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
209
|
+
console.error(`SSR-only rendering failed for ${src}:`, error);
|
|
210
|
+
}
|
|
211
|
+
throw error;
|
|
212
|
+
}
|
|
213
|
+
}
|