@useavalon/avalon 0.1.0

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.
Files changed (159) hide show
  1. package/README.md +54 -0
  2. package/mod.ts +301 -0
  3. package/package.json +85 -0
  4. package/src/build/README.md +310 -0
  5. package/src/build/integration-bundler-plugin.ts +116 -0
  6. package/src/build/integration-config.ts +168 -0
  7. package/src/build/integration-detection-plugin.ts +117 -0
  8. package/src/build/integration-resolver-plugin.ts +90 -0
  9. package/src/build/island-manifest.ts +269 -0
  10. package/src/build/island-types-generator.ts +476 -0
  11. package/src/build/mdx-island-transform.ts +464 -0
  12. package/src/build/mdx-plugin.ts +98 -0
  13. package/src/build/page-island-transform.ts +598 -0
  14. package/src/build/prop-extractors/index.ts +21 -0
  15. package/src/build/prop-extractors/lit.ts +140 -0
  16. package/src/build/prop-extractors/qwik.ts +16 -0
  17. package/src/build/prop-extractors/solid.ts +125 -0
  18. package/src/build/prop-extractors/svelte.ts +194 -0
  19. package/src/build/prop-extractors/vue.ts +111 -0
  20. package/src/build/sidecar-file-manager.ts +104 -0
  21. package/src/build/sidecar-renderer.ts +30 -0
  22. package/src/client/adapters/index.ts +13 -0
  23. package/src/client/adapters/lit-adapter.ts +654 -0
  24. package/src/client/adapters/preact-adapter.ts +331 -0
  25. package/src/client/adapters/qwik-adapter.ts +345 -0
  26. package/src/client/adapters/react-adapter.ts +353 -0
  27. package/src/client/adapters/solid-adapter.ts +451 -0
  28. package/src/client/adapters/svelte-adapter.ts +524 -0
  29. package/src/client/adapters/vue-adapter.ts +467 -0
  30. package/src/client/components.ts +35 -0
  31. package/src/client/css-hmr-handler.ts +344 -0
  32. package/src/client/framework-adapter.ts +462 -0
  33. package/src/client/hmr-coordinator.ts +396 -0
  34. package/src/client/hmr-error-overlay.js +533 -0
  35. package/src/client/main.js +816 -0
  36. package/src/client/tests/css-hmr-handler.test.ts +360 -0
  37. package/src/client/tests/framework-adapter.test.ts +519 -0
  38. package/src/client/tests/hmr-coordinator.test.ts +176 -0
  39. package/src/client/tests/hydration-option-parsing.test.ts +107 -0
  40. package/src/client/tests/lit-adapter.test.ts +427 -0
  41. package/src/client/tests/preact-adapter.test.ts +353 -0
  42. package/src/client/tests/qwik-adapter.test.ts +343 -0
  43. package/src/client/tests/react-adapter.test.ts +317 -0
  44. package/src/client/tests/solid-adapter.test.ts +396 -0
  45. package/src/client/tests/svelte-adapter.test.ts +387 -0
  46. package/src/client/tests/vue-adapter.test.ts +407 -0
  47. package/src/client/types/framework-runtime.d.ts +68 -0
  48. package/src/client/types/vite-hmr.d.ts +46 -0
  49. package/src/client/types/vite-virtual-modules.d.ts +60 -0
  50. package/src/components/Image.tsx +123 -0
  51. package/src/components/IslandErrorBoundary.tsx +145 -0
  52. package/src/components/LayoutDataErrorBoundary.tsx +141 -0
  53. package/src/components/LayoutErrorBoundary.tsx +127 -0
  54. package/src/components/PersistentIsland.tsx +52 -0
  55. package/src/components/StreamingErrorBoundary.tsx +233 -0
  56. package/src/components/StreamingLayout.tsx +538 -0
  57. package/src/components/tests/component-analyzer.test.ts +96 -0
  58. package/src/components/tests/component-detection.test.ts +347 -0
  59. package/src/components/tests/persistent-islands.test.ts +398 -0
  60. package/src/core/components/component-analyzer.ts +192 -0
  61. package/src/core/components/component-detection.ts +508 -0
  62. package/src/core/components/enhanced-framework-detector.ts +500 -0
  63. package/src/core/components/framework-registry.ts +563 -0
  64. package/src/core/components/tests/enhanced-framework-detector.test.ts +577 -0
  65. package/src/core/components/tests/framework-registry.test.ts +465 -0
  66. package/src/core/content/mdx-processor.ts +46 -0
  67. package/src/core/integrations/README.md +282 -0
  68. package/src/core/integrations/index.ts +19 -0
  69. package/src/core/integrations/loader.ts +125 -0
  70. package/src/core/integrations/registry.ts +195 -0
  71. package/src/core/islands/island-persistence.ts +325 -0
  72. package/src/core/islands/island-state-serializer.ts +258 -0
  73. package/src/core/islands/persistent-island-context.tsx +80 -0
  74. package/src/core/islands/use-persistent-state.ts +68 -0
  75. package/src/core/layout/enhanced-layout-resolver.ts +322 -0
  76. package/src/core/layout/layout-cache-manager.ts +485 -0
  77. package/src/core/layout/layout-composer.ts +357 -0
  78. package/src/core/layout/layout-data-loader.ts +516 -0
  79. package/src/core/layout/layout-discovery.ts +243 -0
  80. package/src/core/layout/layout-matcher.ts +299 -0
  81. package/src/core/layout/layout-types.ts +110 -0
  82. package/src/core/layout/tests/enhanced-layout-resolver.test.ts +477 -0
  83. package/src/core/layout/tests/layout-cache-optimization.test.ts +149 -0
  84. package/src/core/layout/tests/layout-composer.test.ts +486 -0
  85. package/src/core/layout/tests/layout-data-loader.test.ts +443 -0
  86. package/src/core/layout/tests/layout-discovery.test.ts +253 -0
  87. package/src/core/layout/tests/layout-matcher.test.ts +480 -0
  88. package/src/core/modules/framework-module-resolver.ts +273 -0
  89. package/src/core/modules/tests/framework-module-resolver.test.ts +263 -0
  90. package/src/core/modules/tests/module-resolution-integration.test.ts +117 -0
  91. package/src/islands/component-analysis.ts +213 -0
  92. package/src/islands/css-utils.ts +565 -0
  93. package/src/islands/discovery/index.ts +80 -0
  94. package/src/islands/discovery/registry.ts +340 -0
  95. package/src/islands/discovery/resolver.ts +477 -0
  96. package/src/islands/discovery/scanner.ts +386 -0
  97. package/src/islands/discovery/tests/island-discovery.test.ts +881 -0
  98. package/src/islands/discovery/types.ts +117 -0
  99. package/src/islands/discovery/validator.ts +544 -0
  100. package/src/islands/discovery/watcher.ts +368 -0
  101. package/src/islands/framework-detection.ts +428 -0
  102. package/src/islands/integration-loader.ts +490 -0
  103. package/src/islands/island.tsx +565 -0
  104. package/src/islands/render-cache.ts +550 -0
  105. package/src/islands/types.ts +80 -0
  106. package/src/islands/universal-css-collector.ts +157 -0
  107. package/src/islands/universal-head-collector.ts +137 -0
  108. package/src/layout-system.d.ts +592 -0
  109. package/src/layout-system.ts +218 -0
  110. package/src/middleware/__tests__/discovery.test.ts +107 -0
  111. package/src/middleware/discovery.ts +268 -0
  112. package/src/middleware/executor.ts +315 -0
  113. package/src/middleware/index.ts +76 -0
  114. package/src/middleware/types.ts +99 -0
  115. package/src/nitro/build-config.ts +576 -0
  116. package/src/nitro/config.ts +483 -0
  117. package/src/nitro/error-handler.ts +636 -0
  118. package/src/nitro/index.ts +173 -0
  119. package/src/nitro/island-manifest.ts +584 -0
  120. package/src/nitro/middleware-adapter.ts +260 -0
  121. package/src/nitro/renderer.ts +1458 -0
  122. package/src/nitro/route-discovery.ts +439 -0
  123. package/src/nitro/types.ts +321 -0
  124. package/src/render/collect-css.ts +198 -0
  125. package/src/render/error-pages.ts +79 -0
  126. package/src/render/isolated-ssr-renderer.ts +654 -0
  127. package/src/render/ssr.ts +1030 -0
  128. package/src/schemas/api.ts +30 -0
  129. package/src/schemas/core.ts +64 -0
  130. package/src/schemas/index.ts +212 -0
  131. package/src/schemas/layout.ts +279 -0
  132. package/src/schemas/routing/index.ts +38 -0
  133. package/src/schemas/routing.ts +376 -0
  134. package/src/types/as-island.ts +20 -0
  135. package/src/types/image.d.ts +106 -0
  136. package/src/types/index.d.ts +22 -0
  137. package/src/types/island-jsx.d.ts +33 -0
  138. package/src/types/island-prop.d.ts +20 -0
  139. package/src/types/layout.ts +285 -0
  140. package/src/types/mdx.d.ts +6 -0
  141. package/src/types/routing.ts +555 -0
  142. package/src/types/tests/layout-types.test.ts +197 -0
  143. package/src/types/types.ts +5 -0
  144. package/src/types/urlpattern.d.ts +49 -0
  145. package/src/types/vite-env.d.ts +11 -0
  146. package/src/utils/dev-logger.ts +299 -0
  147. package/src/utils/fs.ts +151 -0
  148. package/src/vite-plugin/auto-discover.ts +551 -0
  149. package/src/vite-plugin/config.ts +266 -0
  150. package/src/vite-plugin/errors.ts +127 -0
  151. package/src/vite-plugin/image-optimization.ts +151 -0
  152. package/src/vite-plugin/integration-activator.ts +126 -0
  153. package/src/vite-plugin/island-sidecar-plugin.ts +176 -0
  154. package/src/vite-plugin/module-discovery.ts +189 -0
  155. package/src/vite-plugin/nitro-integration.ts +1334 -0
  156. package/src/vite-plugin/plugin.ts +329 -0
  157. package/src/vite-plugin/tests/image-optimization.test.ts +54 -0
  158. package/src/vite-plugin/types.ts +327 -0
  159. package/src/vite-plugin/validation.ts +228 -0
@@ -0,0 +1,344 @@
1
+ /**
2
+ * CSS HMR Handler
3
+ *
4
+ * Handles Hot Module Replacement for CSS files including:
5
+ * - Global CSS files
6
+ * - CSS modules
7
+ * - Component-scoped styles (Svelte, Vue)
8
+ */
9
+
10
+ /// <reference lib="dom" />
11
+ /// <reference lib="dom.iterable" />
12
+
13
+ import type { Update } from './hmr-coordinator.ts';
14
+
15
+ /**
16
+ * CSS update types
17
+ */
18
+ export type CSSUpdateType = 'global' | 'module' | 'scoped';
19
+
20
+ /**
21
+ * CSS update information
22
+ */
23
+ export interface CSSUpdateInfo {
24
+ type: CSSUpdateType;
25
+ path: string;
26
+ timestamp: number;
27
+ affectedComponents?: string[];
28
+ }
29
+
30
+ /**
31
+ * CSS HMR Handler class
32
+ * Manages CSS hot updates without page reload
33
+ */
34
+ export class CSSHMRHandler {
35
+ private cssModuleMap: Map<string, Set<HTMLElement>> = new Map();
36
+ private styleElementMap: Map<string, HTMLStyleElement> = new Map();
37
+
38
+ /**
39
+ * Handle CSS update from Vite HMR
40
+ */
41
+ handleCSSUpdate(update: Update): void {
42
+ const updateInfo = this.classifyCSSUpdate(update);
43
+
44
+ switch (updateInfo.type) {
45
+ case 'global':
46
+ this.handleGlobalCSSUpdate(updateInfo);
47
+ break;
48
+ case 'module':
49
+ this.handleCSSModuleUpdate(updateInfo);
50
+ break;
51
+ case 'scoped':
52
+ this.handleScopedCSSUpdate(updateInfo);
53
+ break;
54
+ }
55
+ }
56
+
57
+ /**
58
+ * Classify the type of CSS update
59
+ */
60
+ private classifyCSSUpdate(update: Update): CSSUpdateInfo {
61
+ const path = update.path || update.acceptedPath;
62
+
63
+ // Check if it's a CSS module
64
+ if (path.includes('.module.css') || path.includes('.module.scss')) {
65
+ return {
66
+ type: 'module',
67
+ path,
68
+ timestamp: update.timestamp,
69
+ };
70
+ }
71
+
72
+ // Check if it's a scoped style (Svelte or Vue)
73
+ if (path.includes('.svelte') || path.includes('.vue')) {
74
+ return {
75
+ type: 'scoped',
76
+ path,
77
+ timestamp: update.timestamp,
78
+ };
79
+ }
80
+
81
+ // Default to global CSS
82
+ return {
83
+ type: 'global',
84
+ path,
85
+ timestamp: update.timestamp,
86
+ };
87
+ }
88
+
89
+ /**
90
+ * Handle global CSS file update
91
+ * Injects updated styles without page reload
92
+ */
93
+ private handleGlobalCSSUpdate(info: CSSUpdateInfo): void {
94
+ try {
95
+ // Find existing style element for this CSS file
96
+ const existingStyle = this.styleElementMap.get(info.path);
97
+
98
+ if (existingStyle) {
99
+ // Remove old style element
100
+ existingStyle.remove();
101
+ this.styleElementMap.delete(info.path);
102
+ }
103
+
104
+ // Vite automatically injects the updated CSS via its HMR mechanism
105
+ // We just need to ensure old styles are removed
106
+ // The new styles will be injected by Vite's CSS handling
107
+
108
+ // Find the newly injected style element
109
+ // Vite adds a data-vite-dev-id attribute to style elements
110
+ const newStyle = document.querySelector<HTMLStyleElement>(
111
+ `style[data-vite-dev-id*="${this.getFileId(info.path)}"]`,
112
+ );
113
+
114
+ if (newStyle) {
115
+ this.styleElementMap.set(info.path, newStyle);
116
+ }
117
+
118
+ // Dispatch event for feedback
119
+ this.dispatchCSSUpdateEvent(info, true);
120
+ } catch (error) {
121
+ console.error(`Failed to update global CSS: ${info.path}`, error);
122
+ this.dispatchCSSUpdateEvent(info, false, error as Error);
123
+ throw error;
124
+ }
125
+ }
126
+
127
+ /**
128
+ * Handle CSS module update
129
+ * Re-renders components using the updated CSS module
130
+ */
131
+ private handleCSSModuleUpdate(info: CSSUpdateInfo): void {
132
+ try {
133
+ const affectedIslands = this.findIslandsUsingCSSModule(info.path);
134
+
135
+ if (affectedIslands.length === 0) {
136
+ return;
137
+ }
138
+
139
+ for (const island of affectedIslands) {
140
+ this.triggerIslandRerender(island, info);
141
+ }
142
+
143
+ this.dispatchCSSUpdateEvent(info, true);
144
+ } catch (error) {
145
+ console.error(`[HMR] Failed to update CSS module: ${info.path}`, error);
146
+ this.dispatchCSSUpdateEvent(info, false, error as Error);
147
+ throw error;
148
+ }
149
+ }
150
+
151
+ /**
152
+ * Handle scoped CSS update (Svelte/Vue)
153
+ * Updates only the affected component's styles
154
+ */
155
+ private handleScopedCSSUpdate(info: CSSUpdateInfo): void {
156
+ try {
157
+ const affectedIslands = this.findIslandsUsingComponent(info.path);
158
+
159
+ if (affectedIslands.length === 0) {
160
+ return;
161
+ }
162
+
163
+ this.dispatchCSSUpdateEvent(info, true);
164
+ } catch (error) {
165
+ console.error(`[HMR] Failed to update scoped CSS: ${info.path}`, error);
166
+ this.dispatchCSSUpdateEvent(info, false, error as Error);
167
+ throw error;
168
+ }
169
+ }
170
+
171
+ /**
172
+ * Find islands that use a specific CSS module
173
+ */
174
+ private findIslandsUsingCSSModule(cssPath: string): HTMLElement[] {
175
+ const islands: HTMLElement[] = [];
176
+ const normalizedPath = this.normalizePath(cssPath);
177
+
178
+ // Check cached mapping first
179
+ const cached = this.cssModuleMap.get(normalizedPath);
180
+ if (cached) {
181
+ return Array.from(cached);
182
+ }
183
+
184
+ // Find all islands
185
+ const allIslands = document.querySelectorAll<HTMLElement>('[data-src]');
186
+
187
+ for (const island of allIslands) {
188
+ const src = island.getAttribute('data-src');
189
+ if (!src) continue;
190
+
191
+ // Check if the island's component likely imports this CSS module
192
+ // This is a heuristic - we look for islands in the same directory
193
+ const componentDir = this.getDirectory(src);
194
+ const cssDir = this.getDirectory(cssPath);
195
+
196
+ if (componentDir === cssDir) {
197
+ islands.push(island);
198
+ }
199
+ }
200
+
201
+ // Cache the mapping
202
+ if (islands.length > 0) {
203
+ this.cssModuleMap.set(normalizedPath, new Set(islands));
204
+ }
205
+
206
+ return islands;
207
+ }
208
+
209
+ /**
210
+ * Find islands using a specific component file
211
+ */
212
+ private findIslandsUsingComponent(componentPath: string): HTMLElement[] {
213
+ const islands: HTMLElement[] = [];
214
+ const normalizedPath = this.normalizePath(componentPath);
215
+
216
+ const allIslands = document.querySelectorAll<HTMLElement>('[data-src]');
217
+
218
+ for (const island of allIslands) {
219
+ const src = island.getAttribute('data-src');
220
+ if (!src) continue;
221
+
222
+ const normalizedSrc = this.normalizePath(src);
223
+
224
+ if (normalizedSrc === normalizedPath || normalizedSrc.includes(normalizedPath)) {
225
+ islands.push(island);
226
+ }
227
+ }
228
+
229
+ return islands;
230
+ }
231
+
232
+ /**
233
+ * Trigger re-render of an island to apply new CSS module classes
234
+ */
235
+ private triggerIslandRerender(island: HTMLElement, info: CSSUpdateInfo): void {
236
+ // Dispatch event to trigger island re-render
237
+ // The HMR coordinator will handle the actual re-render
238
+ island.dispatchEvent(
239
+ new CustomEvent('css-module-update', {
240
+ detail: {
241
+ cssPath: info.path,
242
+ timestamp: info.timestamp,
243
+ },
244
+ bubbles: true,
245
+ }),
246
+ );
247
+
248
+ // Also trigger a standard HMR update event
249
+ // This will be picked up by the HMR coordinator
250
+ const src = island.getAttribute('data-src');
251
+ if (src) {
252
+ island.dispatchEvent(
253
+ new CustomEvent('hmr-update-required', {
254
+ detail: {
255
+ src,
256
+ reason: 'css-module-update',
257
+ cssPath: info.path,
258
+ },
259
+ bubbles: true,
260
+ }),
261
+ );
262
+ }
263
+ }
264
+
265
+ /**
266
+ * Dispatch CSS update event for feedback
267
+ */
268
+ private dispatchCSSUpdateEvent(info: CSSUpdateInfo, success: boolean, error?: Error): void {
269
+ const event = new CustomEvent('css-hmr-update', {
270
+ detail: {
271
+ type: info.type,
272
+ path: info.path,
273
+ timestamp: info.timestamp,
274
+ success,
275
+ error: error?.message,
276
+ },
277
+ bubbles: true,
278
+ });
279
+
280
+ document.dispatchEvent(event);
281
+ }
282
+
283
+ /**
284
+ * Normalize a file path for comparison
285
+ */
286
+ private normalizePath(path: string): string {
287
+ return path.replace(/\\/g, '/').replace(/^\//, '').replace(/\?.*$/, '').replace(/#.*$/, '');
288
+ }
289
+
290
+ /**
291
+ * Get directory from a file path
292
+ */
293
+ private getDirectory(path: string): string {
294
+ const normalized = this.normalizePath(path);
295
+ const lastSlash = normalized.lastIndexOf('/');
296
+ return lastSlash >= 0 ? normalized.substring(0, lastSlash) : '';
297
+ }
298
+
299
+ /**
300
+ * Get file ID from path (for Vite's data-vite-dev-id)
301
+ */
302
+ private getFileId(path: string): string {
303
+ const normalized = this.normalizePath(path);
304
+ // Vite uses the file path as the ID
305
+ return normalized;
306
+ }
307
+
308
+ /**
309
+ * Clear cached mappings
310
+ */
311
+ clearCache(): void {
312
+ this.cssModuleMap.clear();
313
+ this.styleElementMap.clear();
314
+ }
315
+
316
+ /**
317
+ * Register an island as using a CSS module
318
+ * Useful for explicit tracking
319
+ */
320
+ registerCSSModuleUsage(cssPath: string, island: HTMLElement): void {
321
+ const normalized = this.normalizePath(cssPath);
322
+
323
+ if (!this.cssModuleMap.has(normalized)) {
324
+ this.cssModuleMap.set(normalized, new Set());
325
+ }
326
+
327
+ this.cssModuleMap.get(normalized)!.add(island);
328
+ }
329
+ }
330
+
331
+ /**
332
+ * Global CSS HMR handler instance
333
+ */
334
+ let cssHandlerInstance: CSSHMRHandler | null = null;
335
+
336
+ /**
337
+ * Get or create the global CSS HMR handler instance
338
+ */
339
+ export function getCSSHMRHandler(): CSSHMRHandler {
340
+ if (!cssHandlerInstance) {
341
+ cssHandlerInstance = new CSSHMRHandler();
342
+ }
343
+ return cssHandlerInstance;
344
+ }