@useavalon/avalon 0.1.12 → 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/mod.ts +302 -0
- package/package.json +9 -17
- package/src/build/integration-bundler-plugin.ts +116 -0
- package/src/build/integration-config.ts +168 -0
- package/src/build/integration-detection-plugin.ts +117 -0
- package/src/build/integration-resolver-plugin.ts +90 -0
- package/src/build/island-manifest.ts +269 -0
- package/src/build/island-types-generator.ts +476 -0
- package/src/build/mdx-island-transform.ts +464 -0
- package/src/build/mdx-plugin.ts +98 -0
- package/src/build/page-island-transform.ts +598 -0
- package/src/build/prop-extractors/index.ts +21 -0
- package/src/build/prop-extractors/lit.ts +140 -0
- package/src/build/prop-extractors/qwik.ts +16 -0
- package/src/build/prop-extractors/solid.ts +125 -0
- package/src/build/prop-extractors/svelte.ts +194 -0
- package/src/build/prop-extractors/vue.ts +111 -0
- package/src/build/sidecar-file-manager.ts +104 -0
- package/src/build/sidecar-renderer.ts +30 -0
- package/src/client/adapters/index.ts +21 -0
- package/src/client/components.ts +35 -0
- package/src/client/css-hmr-handler.ts +344 -0
- package/src/client/framework-adapter.ts +462 -0
- package/src/client/hmr-coordinator.ts +396 -0
- package/src/client/hmr-error-overlay.js +533 -0
- package/src/client/main.js +824 -0
- package/src/components/Image.tsx +123 -0
- package/src/components/IslandErrorBoundary.tsx +145 -0
- package/src/components/LayoutDataErrorBoundary.tsx +141 -0
- package/src/components/LayoutErrorBoundary.tsx +127 -0
- package/src/components/PersistentIsland.tsx +52 -0
- package/src/components/StreamingErrorBoundary.tsx +233 -0
- package/src/components/StreamingLayout.tsx +538 -0
- package/src/core/components/component-analyzer.ts +192 -0
- package/src/core/components/component-detection.ts +508 -0
- package/src/core/components/enhanced-framework-detector.ts +500 -0
- package/src/core/components/framework-registry.ts +563 -0
- package/src/core/content/mdx-processor.ts +46 -0
- package/src/core/integrations/index.ts +19 -0
- package/src/core/integrations/loader.ts +125 -0
- package/src/core/integrations/registry.ts +175 -0
- package/src/core/islands/island-persistence.ts +325 -0
- package/src/core/islands/island-state-serializer.ts +258 -0
- package/src/core/islands/persistent-island-context.tsx +80 -0
- package/src/core/islands/use-persistent-state.ts +68 -0
- package/src/core/layout/enhanced-layout-resolver.ts +322 -0
- package/src/core/layout/layout-cache-manager.ts +485 -0
- package/src/core/layout/layout-composer.ts +357 -0
- package/src/core/layout/layout-data-loader.ts +516 -0
- package/src/core/layout/layout-discovery.ts +243 -0
- package/src/core/layout/layout-matcher.ts +299 -0
- package/src/core/layout/layout-types.ts +110 -0
- package/src/core/modules/framework-module-resolver.ts +273 -0
- package/src/islands/component-analysis.ts +213 -0
- package/src/islands/css-utils.ts +565 -0
- package/src/islands/discovery/index.ts +80 -0
- package/src/islands/discovery/registry.ts +340 -0
- package/src/islands/discovery/resolver.ts +477 -0
- package/src/islands/discovery/scanner.ts +386 -0
- package/src/islands/discovery/types.ts +117 -0
- package/src/islands/discovery/validator.ts +544 -0
- package/src/islands/discovery/watcher.ts +368 -0
- package/src/islands/framework-detection.ts +428 -0
- package/src/islands/integration-loader.ts +490 -0
- package/src/islands/island.tsx +565 -0
- package/src/islands/render-cache.ts +550 -0
- package/src/islands/types.ts +80 -0
- package/src/islands/universal-css-collector.ts +157 -0
- package/src/islands/universal-head-collector.ts +137 -0
- package/src/layout-system.ts +218 -0
- package/src/middleware/discovery.ts +268 -0
- package/src/middleware/executor.ts +315 -0
- package/src/middleware/index.ts +76 -0
- package/src/middleware/types.ts +99 -0
- package/src/nitro/build-config.ts +576 -0
- package/src/nitro/config.ts +483 -0
- package/src/nitro/error-handler.ts +636 -0
- package/src/nitro/index.ts +173 -0
- package/src/nitro/island-manifest.ts +584 -0
- package/src/nitro/middleware-adapter.ts +260 -0
- package/src/nitro/renderer.ts +1471 -0
- package/src/nitro/route-discovery.ts +439 -0
- package/src/nitro/types.ts +321 -0
- package/src/render/collect-css.ts +198 -0
- package/src/render/error-pages.ts +79 -0
- package/src/render/isolated-ssr-renderer.ts +654 -0
- package/src/render/ssr.ts +1030 -0
- package/src/schemas/api.ts +30 -0
- package/src/schemas/core.ts +64 -0
- package/src/schemas/index.ts +212 -0
- package/src/schemas/layout.ts +279 -0
- package/src/schemas/routing/index.ts +38 -0
- package/src/schemas/routing.ts +376 -0
- package/src/types/as-island.ts +20 -0
- package/src/types/layout.ts +285 -0
- package/src/types/routing.ts +555 -0
- package/src/types/types.ts +5 -0
- package/src/utils/dev-logger.ts +299 -0
- package/src/utils/fs.ts +151 -0
- package/src/vite-plugin/auto-discover.ts +551 -0
- package/src/vite-plugin/config.ts +266 -0
- package/src/vite-plugin/errors.ts +127 -0
- package/src/vite-plugin/image-optimization.ts +156 -0
- package/src/vite-plugin/integration-activator.ts +126 -0
- package/src/vite-plugin/island-sidecar-plugin.ts +176 -0
- package/src/vite-plugin/module-discovery.ts +189 -0
- package/src/vite-plugin/nitro-integration.ts +1354 -0
- package/src/vite-plugin/plugin.ts +403 -0
- package/src/vite-plugin/types.ts +327 -0
- package/src/vite-plugin/validation.ts +228 -0
- package/dist/mod.js +0 -1
- package/dist/src/build/integration-bundler-plugin.js +0 -1
- package/dist/src/build/integration-config.js +0 -1
- package/dist/src/build/integration-detection-plugin.js +0 -1
- package/dist/src/build/integration-resolver-plugin.js +0 -1
- package/dist/src/build/island-manifest.js +0 -1
- package/dist/src/build/island-types-generator.js +0 -5
- package/dist/src/build/mdx-island-transform.js +0 -2
- package/dist/src/build/mdx-plugin.js +0 -1
- package/dist/src/build/page-island-transform.js +0 -3
- package/dist/src/build/prop-extractors/index.js +0 -1
- package/dist/src/build/prop-extractors/lit.js +0 -1
- package/dist/src/build/prop-extractors/qwik.js +0 -1
- package/dist/src/build/prop-extractors/solid.js +0 -1
- package/dist/src/build/prop-extractors/svelte.js +0 -1
- package/dist/src/build/prop-extractors/vue.js +0 -1
- package/dist/src/build/sidecar-file-manager.js +0 -1
- package/dist/src/build/sidecar-renderer.js +0 -6
- package/dist/src/client/adapters/index.js +0 -1
- package/dist/src/client/components.js +0 -1
- package/dist/src/client/css-hmr-handler.js +0 -1
- package/dist/src/client/framework-adapter.js +0 -13
- package/dist/src/client/hmr-coordinator.js +0 -1
- package/dist/src/client/hmr-error-overlay.js +0 -214
- package/dist/src/client/main.js +0 -39
- package/dist/src/components/Image.js +0 -1
- package/dist/src/components/IslandErrorBoundary.js +0 -1
- package/dist/src/components/LayoutDataErrorBoundary.js +0 -1
- package/dist/src/components/LayoutErrorBoundary.js +0 -1
- package/dist/src/components/PersistentIsland.js +0 -1
- package/dist/src/components/StreamingErrorBoundary.js +0 -1
- package/dist/src/components/StreamingLayout.js +0 -29
- package/dist/src/core/components/component-analyzer.js +0 -1
- package/dist/src/core/components/component-detection.js +0 -5
- package/dist/src/core/components/enhanced-framework-detector.js +0 -1
- package/dist/src/core/components/framework-registry.js +0 -1
- package/dist/src/core/content/mdx-processor.js +0 -1
- package/dist/src/core/integrations/index.js +0 -1
- package/dist/src/core/integrations/loader.js +0 -1
- package/dist/src/core/integrations/registry.js +0 -1
- package/dist/src/core/islands/island-persistence.js +0 -1
- package/dist/src/core/islands/island-state-serializer.js +0 -1
- package/dist/src/core/islands/persistent-island-context.js +0 -1
- package/dist/src/core/islands/use-persistent-state.js +0 -1
- package/dist/src/core/layout/enhanced-layout-resolver.js +0 -1
- package/dist/src/core/layout/layout-cache-manager.js +0 -1
- package/dist/src/core/layout/layout-composer.js +0 -1
- package/dist/src/core/layout/layout-data-loader.js +0 -1
- package/dist/src/core/layout/layout-discovery.js +0 -1
- package/dist/src/core/layout/layout-matcher.js +0 -1
- package/dist/src/core/layout/layout-types.js +0 -1
- package/dist/src/core/modules/framework-module-resolver.js +0 -1
- package/dist/src/islands/component-analysis.js +0 -1
- package/dist/src/islands/css-utils.js +0 -17
- package/dist/src/islands/discovery/index.js +0 -1
- package/dist/src/islands/discovery/registry.js +0 -1
- package/dist/src/islands/discovery/resolver.js +0 -2
- package/dist/src/islands/discovery/scanner.js +0 -1
- package/dist/src/islands/discovery/types.js +0 -1
- package/dist/src/islands/discovery/validator.js +0 -18
- package/dist/src/islands/discovery/watcher.js +0 -1
- package/dist/src/islands/framework-detection.js +0 -1
- package/dist/src/islands/integration-loader.js +0 -1
- package/dist/src/islands/island.js +0 -1
- package/dist/src/islands/render-cache.js +0 -1
- package/dist/src/islands/types.js +0 -1
- package/dist/src/islands/universal-css-collector.js +0 -5
- package/dist/src/islands/universal-head-collector.js +0 -2
- package/dist/src/layout-system.js +0 -1
- package/dist/src/middleware/discovery.js +0 -1
- package/dist/src/middleware/executor.js +0 -1
- package/dist/src/middleware/index.js +0 -1
- package/dist/src/middleware/types.js +0 -1
- package/dist/src/nitro/build-config.js +0 -1
- package/dist/src/nitro/config.js +0 -1
- package/dist/src/nitro/error-handler.js +0 -198
- package/dist/src/nitro/index.js +0 -1
- package/dist/src/nitro/island-manifest.js +0 -2
- package/dist/src/nitro/middleware-adapter.js +0 -1
- package/dist/src/nitro/renderer.js +0 -183
- package/dist/src/nitro/route-discovery.js +0 -1
- package/dist/src/nitro/types.js +0 -1
- package/dist/src/render/collect-css.js +0 -3
- package/dist/src/render/error-pages.js +0 -48
- package/dist/src/render/isolated-ssr-renderer.js +0 -1
- package/dist/src/render/ssr.js +0 -90
- package/dist/src/schemas/api.js +0 -1
- package/dist/src/schemas/core.js +0 -1
- package/dist/src/schemas/index.js +0 -1
- package/dist/src/schemas/layout.js +0 -1
- package/dist/src/schemas/routing/index.js +0 -1
- package/dist/src/schemas/routing.js +0 -1
- package/dist/src/types/as-island.js +0 -1
- package/dist/src/types/layout.js +0 -1
- package/dist/src/types/routing.js +0 -1
- package/dist/src/types/types.js +0 -1
- package/dist/src/utils/dev-logger.js +0 -12
- package/dist/src/utils/fs.js +0 -1
- package/dist/src/vite-plugin/auto-discover.js +0 -1
- package/dist/src/vite-plugin/config.js +0 -1
- package/dist/src/vite-plugin/errors.js +0 -1
- package/dist/src/vite-plugin/image-optimization.js +0 -45
- package/dist/src/vite-plugin/integration-activator.js +0 -1
- package/dist/src/vite-plugin/island-sidecar-plugin.js +0 -1
- package/dist/src/vite-plugin/module-discovery.js +0 -1
- package/dist/src/vite-plugin/nitro-integration.js +0 -42
- package/dist/src/vite-plugin/plugin.js +0 -1
- package/dist/src/vite-plugin/types.js +0 -1
- package/dist/src/vite-plugin/validation.js +0 -2
- /package/{dist/src → src}/client/types/framework-runtime.d.ts +0 -0
- /package/{dist/src → src}/client/types/vite-hmr.d.ts +0 -0
- /package/{dist/src → src}/client/types/vite-virtual-modules.d.ts +0 -0
- /package/{dist/src → src}/layout-system.d.ts +0 -0
- /package/{dist/src → src}/types/image.d.ts +0 -0
- /package/{dist/src → src}/types/index.d.ts +0 -0
- /package/{dist/src → src}/types/island-jsx.d.ts +0 -0
- /package/{dist/src → src}/types/island-prop.d.ts +0 -0
- /package/{dist/src → src}/types/mdx.d.ts +0 -0
- /package/{dist/src → src}/types/urlpattern.d.ts +0 -0
- /package/{dist/src → src}/types/vite-env.d.ts +0 -0
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Framework-aware module resolver for handling framework-specific path transformations
|
|
3
|
+
* and MIME type resolution during hydration and module serving.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export interface ModuleResolutionConfig {
|
|
7
|
+
framework: string;
|
|
8
|
+
baseUrl: string;
|
|
9
|
+
extensions: string[];
|
|
10
|
+
transformPath: (path: string) => string;
|
|
11
|
+
mimeType: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface ResolvedModule {
|
|
15
|
+
originalPath: string;
|
|
16
|
+
resolvedPath: string;
|
|
17
|
+
framework: string;
|
|
18
|
+
shouldTransform: boolean;
|
|
19
|
+
mimeType: string;
|
|
20
|
+
url: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface FrameworkModuleConfig {
|
|
24
|
+
extensions: string[];
|
|
25
|
+
hydrationExtension: string;
|
|
26
|
+
mimeType: string;
|
|
27
|
+
transformPath: (path: string, mode: 'development' | 'production') => string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Framework-specific module configurations
|
|
32
|
+
*/
|
|
33
|
+
const FRAMEWORK_MODULE_CONFIGS: Record<string, FrameworkModuleConfig> = {
|
|
34
|
+
solid: {
|
|
35
|
+
extensions: ['.tsx', '.jsx'],
|
|
36
|
+
hydrationExtension: '.js',
|
|
37
|
+
mimeType: 'application/javascript',
|
|
38
|
+
transformPath: (path: string, mode: 'development' | 'production') => {
|
|
39
|
+
// For Solid, transform .tsx to .js for hydration
|
|
40
|
+
if (path.endsWith('.tsx')) {
|
|
41
|
+
return path.replace(/\.tsx$/, '.js');
|
|
42
|
+
}
|
|
43
|
+
if (path.endsWith('.jsx')) {
|
|
44
|
+
return path.replace(/\.jsx$/, '.js');
|
|
45
|
+
}
|
|
46
|
+
return path;
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
preact: {
|
|
50
|
+
extensions: ['.tsx', '.jsx'],
|
|
51
|
+
hydrationExtension: '.js',
|
|
52
|
+
mimeType: 'application/javascript',
|
|
53
|
+
transformPath: (path: string, mode: 'development' | 'production') => {
|
|
54
|
+
// For Preact, transform .tsx/.jsx to .js for hydration
|
|
55
|
+
if (path.endsWith('.tsx')) {
|
|
56
|
+
return path.replace(/\.tsx$/, '.js');
|
|
57
|
+
}
|
|
58
|
+
if (path.endsWith('.jsx')) {
|
|
59
|
+
return path.replace(/\.jsx$/, '.js');
|
|
60
|
+
}
|
|
61
|
+
return path;
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
vue: {
|
|
65
|
+
extensions: ['.vue'],
|
|
66
|
+
hydrationExtension: '.js',
|
|
67
|
+
mimeType: 'application/javascript',
|
|
68
|
+
transformPath: (path: string, mode: 'development' | 'production') => {
|
|
69
|
+
// Vue components are typically compiled to .js
|
|
70
|
+
if (path.endsWith('.vue')) {
|
|
71
|
+
return path.replace(/\.vue$/, '.js');
|
|
72
|
+
}
|
|
73
|
+
return path;
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
svelte: {
|
|
77
|
+
extensions: ['.svelte'],
|
|
78
|
+
hydrationExtension: '.js',
|
|
79
|
+
mimeType: 'application/javascript',
|
|
80
|
+
transformPath: (path: string, mode: 'development' | 'production') => {
|
|
81
|
+
// Svelte components are compiled to .js
|
|
82
|
+
if (path.endsWith('.svelte')) {
|
|
83
|
+
return path.replace(/\.svelte$/, '.js');
|
|
84
|
+
}
|
|
85
|
+
return path;
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
qwik: {
|
|
89
|
+
extensions: ['.tsx', '.jsx'],
|
|
90
|
+
hydrationExtension: '.js',
|
|
91
|
+
mimeType: 'application/javascript',
|
|
92
|
+
transformPath: (path: string, mode: 'development' | 'production') => {
|
|
93
|
+
// Qwik components are compiled to .js via the Qwik optimizer
|
|
94
|
+
if (path.endsWith('.tsx')) {
|
|
95
|
+
return path.replace(/\.tsx$/, '.js');
|
|
96
|
+
}
|
|
97
|
+
if (path.endsWith('.jsx')) {
|
|
98
|
+
return path.replace(/\.jsx$/, '.js');
|
|
99
|
+
}
|
|
100
|
+
return path;
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
export class FrameworkModuleResolver {
|
|
106
|
+
private mode: 'development' | 'production';
|
|
107
|
+
private baseUrl: string;
|
|
108
|
+
|
|
109
|
+
constructor(mode: 'development' | 'production' = 'development', baseUrl = '') {
|
|
110
|
+
this.mode = mode;
|
|
111
|
+
this.baseUrl = baseUrl;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Resolve a module path for a specific framework
|
|
116
|
+
*/
|
|
117
|
+
resolveModule(
|
|
118
|
+
originalPath: string,
|
|
119
|
+
framework: string,
|
|
120
|
+
options: {
|
|
121
|
+
forHydration?: boolean;
|
|
122
|
+
baseUrl?: string;
|
|
123
|
+
} = {}
|
|
124
|
+
): ResolvedModule {
|
|
125
|
+
const config = FRAMEWORK_MODULE_CONFIGS[framework];
|
|
126
|
+
if (!config) {
|
|
127
|
+
throw new Error(`Unknown framework: ${framework}`);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const { forHydration = false, baseUrl = this.baseUrl } = options;
|
|
131
|
+
|
|
132
|
+
let resolvedPath = originalPath;
|
|
133
|
+
let shouldTransform = false;
|
|
134
|
+
let mimeType = this.getMimeType(originalPath);
|
|
135
|
+
|
|
136
|
+
// Apply framework-specific path transformation for hydration
|
|
137
|
+
if (forHydration) {
|
|
138
|
+
const transformedPath = config.transformPath(originalPath, this.mode);
|
|
139
|
+
if (transformedPath !== originalPath) {
|
|
140
|
+
resolvedPath = transformedPath;
|
|
141
|
+
shouldTransform = true;
|
|
142
|
+
mimeType = config.mimeType;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Generate the full URL
|
|
147
|
+
const url = this.generateModuleUrl(resolvedPath, baseUrl);
|
|
148
|
+
|
|
149
|
+
return {
|
|
150
|
+
originalPath,
|
|
151
|
+
resolvedPath,
|
|
152
|
+
framework,
|
|
153
|
+
shouldTransform,
|
|
154
|
+
mimeType,
|
|
155
|
+
url,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Check if a path needs transformation for the given framework
|
|
161
|
+
*/
|
|
162
|
+
needsTransformation(path: string, framework: string): boolean {
|
|
163
|
+
const config = FRAMEWORK_MODULE_CONFIGS[framework];
|
|
164
|
+
if (!config) {
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const transformedPath = config.transformPath(path, this.mode);
|
|
169
|
+
return transformedPath !== path;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Get the appropriate MIME type for a file path
|
|
174
|
+
*/
|
|
175
|
+
getMimeType(path: string): string {
|
|
176
|
+
const ext = this.getFileExtension(path);
|
|
177
|
+
|
|
178
|
+
switch (ext) {
|
|
179
|
+
case '.js':
|
|
180
|
+
case '.mjs':
|
|
181
|
+
return 'application/javascript';
|
|
182
|
+
case '.ts':
|
|
183
|
+
case '.tsx':
|
|
184
|
+
case '.jsx':
|
|
185
|
+
return 'application/javascript'; // These are typically compiled to JS
|
|
186
|
+
case '.css':
|
|
187
|
+
return 'text/css';
|
|
188
|
+
case '.json':
|
|
189
|
+
return 'application/json';
|
|
190
|
+
case '.vue':
|
|
191
|
+
case '.svelte':
|
|
192
|
+
return 'application/javascript'; // Compiled components
|
|
193
|
+
default:
|
|
194
|
+
return 'text/plain';
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Generate a module URL for the given path
|
|
200
|
+
*/
|
|
201
|
+
generateModuleUrl(path: string, baseUrl = this.baseUrl): string {
|
|
202
|
+
// Ensure path starts with /
|
|
203
|
+
const normalizedPath = path.startsWith('/') ? path : `/${path}`;
|
|
204
|
+
|
|
205
|
+
if (baseUrl) {
|
|
206
|
+
return `${baseUrl.replace(/\/$/, '')}${normalizedPath}`;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
return normalizedPath;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Get supported frameworks
|
|
214
|
+
*/
|
|
215
|
+
getSupportedFrameworks(): string[] {
|
|
216
|
+
return Object.keys(FRAMEWORK_MODULE_CONFIGS);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Get framework configuration
|
|
221
|
+
*/
|
|
222
|
+
getFrameworkConfig(framework: string): FrameworkModuleConfig | undefined {
|
|
223
|
+
return FRAMEWORK_MODULE_CONFIGS[framework];
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Check if a framework is supported
|
|
228
|
+
*/
|
|
229
|
+
isFrameworkSupported(framework: string): boolean {
|
|
230
|
+
return framework in FRAMEWORK_MODULE_CONFIGS;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Get file extension from path
|
|
235
|
+
*/
|
|
236
|
+
private getFileExtension(path: string): string {
|
|
237
|
+
const lastDot = path.lastIndexOf('.');
|
|
238
|
+
return lastDot === -1 ? '' : path.substring(lastDot);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Set the resolver mode (development/production)
|
|
243
|
+
*/
|
|
244
|
+
setMode(mode: 'development' | 'production'): void {
|
|
245
|
+
this.mode = mode;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Get current mode
|
|
250
|
+
*/
|
|
251
|
+
getMode(): 'development' | 'production' {
|
|
252
|
+
return this.mode;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Set base URL for module resolution
|
|
257
|
+
*/
|
|
258
|
+
setBaseUrl(baseUrl: string): void {
|
|
259
|
+
this.baseUrl = baseUrl;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Get current base URL
|
|
264
|
+
*/
|
|
265
|
+
getBaseUrl(): string {
|
|
266
|
+
return this.baseUrl;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Default instance for common usage
|
|
272
|
+
*/
|
|
273
|
+
export const frameworkModuleResolver = new FrameworkModuleResolver();
|
|
@@ -0,0 +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
|
+
}
|