@useavalon/avalon 0.1.13 → 0.1.15

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 (230) hide show
  1. package/dist/mod.js +1 -0
  2. package/dist/src/build/integration-bundler-plugin.js +1 -0
  3. package/dist/src/build/integration-config.js +1 -0
  4. package/dist/src/build/integration-detection-plugin.js +1 -0
  5. package/dist/src/build/integration-resolver-plugin.js +1 -0
  6. package/dist/src/build/island-manifest.js +1 -0
  7. package/dist/src/build/island-types-generator.js +5 -0
  8. package/dist/src/build/mdx-island-transform.js +2 -0
  9. package/dist/src/build/mdx-plugin.js +1 -0
  10. package/dist/src/build/page-island-transform.js +3 -0
  11. package/dist/src/build/prop-extractors/index.js +1 -0
  12. package/dist/src/build/prop-extractors/lit.js +1 -0
  13. package/dist/src/build/prop-extractors/qwik.js +1 -0
  14. package/dist/src/build/prop-extractors/solid.js +1 -0
  15. package/dist/src/build/prop-extractors/svelte.js +1 -0
  16. package/dist/src/build/prop-extractors/vue.js +1 -0
  17. package/dist/src/build/sidecar-file-manager.js +1 -0
  18. package/dist/src/build/sidecar-renderer.js +6 -0
  19. package/dist/src/client/adapters/index.js +1 -0
  20. package/dist/src/client/components.js +1 -0
  21. package/dist/src/client/css-hmr-handler.js +1 -0
  22. package/dist/src/client/framework-adapter.js +13 -0
  23. package/dist/src/client/hmr-coordinator.js +1 -0
  24. package/dist/src/client/hmr-error-overlay.js +214 -0
  25. package/dist/src/client/main.js +39 -0
  26. package/dist/src/components/Image.js +1 -0
  27. package/dist/src/components/IslandErrorBoundary.js +1 -0
  28. package/dist/src/components/LayoutDataErrorBoundary.js +1 -0
  29. package/dist/src/components/LayoutErrorBoundary.js +1 -0
  30. package/dist/src/components/PersistentIsland.js +1 -0
  31. package/dist/src/components/StreamingErrorBoundary.js +1 -0
  32. package/dist/src/components/StreamingLayout.js +29 -0
  33. package/dist/src/core/components/component-analyzer.js +1 -0
  34. package/dist/src/core/components/component-detection.js +5 -0
  35. package/dist/src/core/components/enhanced-framework-detector.js +1 -0
  36. package/dist/src/core/components/framework-registry.js +1 -0
  37. package/dist/src/core/content/mdx-processor.js +1 -0
  38. package/dist/src/core/integrations/index.js +1 -0
  39. package/dist/src/core/integrations/loader.js +1 -0
  40. package/dist/src/core/integrations/registry.js +1 -0
  41. package/dist/src/core/islands/island-persistence.js +1 -0
  42. package/dist/src/core/islands/island-state-serializer.js +1 -0
  43. package/dist/src/core/islands/persistent-island-context.js +1 -0
  44. package/dist/src/core/islands/use-persistent-state.js +1 -0
  45. package/dist/src/core/layout/enhanced-layout-resolver.js +1 -0
  46. package/dist/src/core/layout/layout-cache-manager.js +1 -0
  47. package/dist/src/core/layout/layout-composer.js +1 -0
  48. package/dist/src/core/layout/layout-data-loader.js +1 -0
  49. package/dist/src/core/layout/layout-discovery.js +1 -0
  50. package/dist/src/core/layout/layout-matcher.js +1 -0
  51. package/dist/src/core/layout/layout-types.js +1 -0
  52. package/dist/src/core/modules/framework-module-resolver.js +1 -0
  53. package/dist/src/islands/component-analysis.js +1 -0
  54. package/dist/src/islands/css-utils.js +17 -0
  55. package/dist/src/islands/discovery/index.js +1 -0
  56. package/dist/src/islands/discovery/registry.js +1 -0
  57. package/dist/src/islands/discovery/resolver.js +2 -0
  58. package/dist/src/islands/discovery/scanner.js +1 -0
  59. package/dist/src/islands/discovery/types.js +1 -0
  60. package/dist/src/islands/discovery/validator.js +18 -0
  61. package/dist/src/islands/discovery/watcher.js +1 -0
  62. package/dist/src/islands/framework-detection.js +1 -0
  63. package/dist/src/islands/integration-loader.js +1 -0
  64. package/dist/src/islands/island.js +1 -0
  65. package/dist/src/islands/render-cache.js +1 -0
  66. package/dist/src/islands/types.js +1 -0
  67. package/dist/src/islands/universal-css-collector.js +5 -0
  68. package/dist/src/islands/universal-head-collector.js +2 -0
  69. package/dist/src/layout-system.js +1 -0
  70. package/dist/src/middleware/discovery.js +1 -0
  71. package/dist/src/middleware/executor.js +1 -0
  72. package/dist/src/middleware/index.js +1 -0
  73. package/dist/src/middleware/types.js +1 -0
  74. package/dist/src/nitro/build-config.js +1 -0
  75. package/dist/src/nitro/config.js +1 -0
  76. package/dist/src/nitro/error-handler.js +198 -0
  77. package/dist/src/nitro/index.js +1 -0
  78. package/dist/src/nitro/island-manifest.js +2 -0
  79. package/dist/src/nitro/middleware-adapter.js +1 -0
  80. package/dist/src/nitro/renderer.js +183 -0
  81. package/dist/src/nitro/route-discovery.js +1 -0
  82. package/dist/src/nitro/types.js +1 -0
  83. package/dist/src/render/collect-css.js +3 -0
  84. package/dist/src/render/error-pages.js +48 -0
  85. package/dist/src/render/isolated-ssr-renderer.js +1 -0
  86. package/dist/src/render/ssr.js +90 -0
  87. package/dist/src/schemas/api.js +1 -0
  88. package/dist/src/schemas/core.js +1 -0
  89. package/dist/src/schemas/index.js +1 -0
  90. package/dist/src/schemas/layout.js +1 -0
  91. package/dist/src/schemas/routing/index.js +1 -0
  92. package/dist/src/schemas/routing.js +1 -0
  93. package/dist/src/types/as-island.js +1 -0
  94. package/dist/src/types/layout.js +1 -0
  95. package/dist/src/types/routing.js +1 -0
  96. package/dist/src/types/types.js +1 -0
  97. package/dist/src/utils/dev-logger.js +12 -0
  98. package/dist/src/utils/fs.js +1 -0
  99. package/dist/src/vite-plugin/auto-discover.js +1 -0
  100. package/dist/src/vite-plugin/config.js +1 -0
  101. package/dist/src/vite-plugin/errors.js +1 -0
  102. package/dist/src/vite-plugin/image-optimization.js +45 -0
  103. package/dist/src/vite-plugin/integration-activator.js +1 -0
  104. package/dist/src/vite-plugin/island-sidecar-plugin.js +1 -0
  105. package/dist/src/vite-plugin/module-discovery.js +1 -0
  106. package/dist/src/vite-plugin/nitro-integration.js +42 -0
  107. package/dist/src/vite-plugin/plugin.js +1 -0
  108. package/dist/src/vite-plugin/types.js +1 -0
  109. package/dist/src/vite-plugin/validation.js +2 -0
  110. package/package.json +14 -20
  111. package/mod.ts +0 -302
  112. package/src/build/integration-bundler-plugin.ts +0 -116
  113. package/src/build/integration-config.ts +0 -168
  114. package/src/build/integration-detection-plugin.ts +0 -117
  115. package/src/build/integration-resolver-plugin.ts +0 -90
  116. package/src/build/island-manifest.ts +0 -269
  117. package/src/build/island-types-generator.ts +0 -476
  118. package/src/build/mdx-island-transform.ts +0 -464
  119. package/src/build/mdx-plugin.ts +0 -98
  120. package/src/build/page-island-transform.ts +0 -598
  121. package/src/build/prop-extractors/index.ts +0 -21
  122. package/src/build/prop-extractors/lit.ts +0 -140
  123. package/src/build/prop-extractors/qwik.ts +0 -16
  124. package/src/build/prop-extractors/solid.ts +0 -125
  125. package/src/build/prop-extractors/svelte.ts +0 -194
  126. package/src/build/prop-extractors/vue.ts +0 -111
  127. package/src/build/sidecar-file-manager.ts +0 -104
  128. package/src/build/sidecar-renderer.ts +0 -30
  129. package/src/client/adapters/index.ts +0 -21
  130. package/src/client/components.ts +0 -35
  131. package/src/client/css-hmr-handler.ts +0 -344
  132. package/src/client/framework-adapter.ts +0 -462
  133. package/src/client/hmr-coordinator.ts +0 -396
  134. package/src/client/hmr-error-overlay.js +0 -533
  135. package/src/client/main.js +0 -824
  136. package/src/components/Image.tsx +0 -123
  137. package/src/components/IslandErrorBoundary.tsx +0 -145
  138. package/src/components/LayoutDataErrorBoundary.tsx +0 -141
  139. package/src/components/LayoutErrorBoundary.tsx +0 -127
  140. package/src/components/PersistentIsland.tsx +0 -52
  141. package/src/components/StreamingErrorBoundary.tsx +0 -233
  142. package/src/components/StreamingLayout.tsx +0 -538
  143. package/src/core/components/component-analyzer.ts +0 -192
  144. package/src/core/components/component-detection.ts +0 -508
  145. package/src/core/components/enhanced-framework-detector.ts +0 -500
  146. package/src/core/components/framework-registry.ts +0 -563
  147. package/src/core/content/mdx-processor.ts +0 -46
  148. package/src/core/integrations/index.ts +0 -19
  149. package/src/core/integrations/loader.ts +0 -125
  150. package/src/core/integrations/registry.ts +0 -175
  151. package/src/core/islands/island-persistence.ts +0 -325
  152. package/src/core/islands/island-state-serializer.ts +0 -258
  153. package/src/core/islands/persistent-island-context.tsx +0 -80
  154. package/src/core/islands/use-persistent-state.ts +0 -68
  155. package/src/core/layout/enhanced-layout-resolver.ts +0 -322
  156. package/src/core/layout/layout-cache-manager.ts +0 -485
  157. package/src/core/layout/layout-composer.ts +0 -357
  158. package/src/core/layout/layout-data-loader.ts +0 -516
  159. package/src/core/layout/layout-discovery.ts +0 -243
  160. package/src/core/layout/layout-matcher.ts +0 -299
  161. package/src/core/layout/layout-types.ts +0 -110
  162. package/src/core/modules/framework-module-resolver.ts +0 -273
  163. package/src/islands/component-analysis.ts +0 -213
  164. package/src/islands/css-utils.ts +0 -565
  165. package/src/islands/discovery/index.ts +0 -80
  166. package/src/islands/discovery/registry.ts +0 -340
  167. package/src/islands/discovery/resolver.ts +0 -477
  168. package/src/islands/discovery/scanner.ts +0 -386
  169. package/src/islands/discovery/types.ts +0 -117
  170. package/src/islands/discovery/validator.ts +0 -544
  171. package/src/islands/discovery/watcher.ts +0 -368
  172. package/src/islands/framework-detection.ts +0 -428
  173. package/src/islands/integration-loader.ts +0 -490
  174. package/src/islands/island.tsx +0 -565
  175. package/src/islands/render-cache.ts +0 -550
  176. package/src/islands/types.ts +0 -80
  177. package/src/islands/universal-css-collector.ts +0 -157
  178. package/src/islands/universal-head-collector.ts +0 -137
  179. package/src/layout-system.ts +0 -218
  180. package/src/middleware/discovery.ts +0 -268
  181. package/src/middleware/executor.ts +0 -315
  182. package/src/middleware/index.ts +0 -76
  183. package/src/middleware/types.ts +0 -99
  184. package/src/nitro/build-config.ts +0 -576
  185. package/src/nitro/config.ts +0 -483
  186. package/src/nitro/error-handler.ts +0 -636
  187. package/src/nitro/index.ts +0 -173
  188. package/src/nitro/island-manifest.ts +0 -584
  189. package/src/nitro/middleware-adapter.ts +0 -260
  190. package/src/nitro/renderer.ts +0 -1471
  191. package/src/nitro/route-discovery.ts +0 -439
  192. package/src/nitro/types.ts +0 -321
  193. package/src/render/collect-css.ts +0 -198
  194. package/src/render/error-pages.ts +0 -79
  195. package/src/render/isolated-ssr-renderer.ts +0 -654
  196. package/src/render/ssr.ts +0 -1030
  197. package/src/schemas/api.ts +0 -30
  198. package/src/schemas/core.ts +0 -64
  199. package/src/schemas/index.ts +0 -212
  200. package/src/schemas/layout.ts +0 -279
  201. package/src/schemas/routing/index.ts +0 -38
  202. package/src/schemas/routing.ts +0 -376
  203. package/src/types/as-island.ts +0 -20
  204. package/src/types/layout.ts +0 -285
  205. package/src/types/routing.ts +0 -555
  206. package/src/types/types.ts +0 -5
  207. package/src/utils/dev-logger.ts +0 -299
  208. package/src/utils/fs.ts +0 -151
  209. package/src/vite-plugin/auto-discover.ts +0 -551
  210. package/src/vite-plugin/config.ts +0 -266
  211. package/src/vite-plugin/errors.ts +0 -127
  212. package/src/vite-plugin/image-optimization.ts +0 -156
  213. package/src/vite-plugin/integration-activator.ts +0 -126
  214. package/src/vite-plugin/island-sidecar-plugin.ts +0 -176
  215. package/src/vite-plugin/module-discovery.ts +0 -189
  216. package/src/vite-plugin/nitro-integration.ts +0 -1354
  217. package/src/vite-plugin/plugin.ts +0 -403
  218. package/src/vite-plugin/types.ts +0 -327
  219. package/src/vite-plugin/validation.ts +0 -228
  220. /package/{src → dist/src}/client/types/framework-runtime.d.ts +0 -0
  221. /package/{src → dist/src}/client/types/vite-hmr.d.ts +0 -0
  222. /package/{src → dist/src}/client/types/vite-virtual-modules.d.ts +0 -0
  223. /package/{src → dist/src}/layout-system.d.ts +0 -0
  224. /package/{src → dist/src}/types/image.d.ts +0 -0
  225. /package/{src → dist/src}/types/index.d.ts +0 -0
  226. /package/{src → dist/src}/types/island-jsx.d.ts +0 -0
  227. /package/{src → dist/src}/types/island-prop.d.ts +0 -0
  228. /package/{src → dist/src}/types/mdx.d.ts +0 -0
  229. /package/{src → dist/src}/types/urlpattern.d.ts +0 -0
  230. /package/{src → dist/src}/types/vite-env.d.ts +0 -0
@@ -1,824 +0,0 @@
1
- // Main client entry point for Vite
2
- // Integration-based island hydration system
3
- //
4
- // NOTE: This file contains imports to Vite virtual modules (/@useavalon/*/client)
5
- // that will show as errors in the IDE. These are resolved by Vite at runtime
6
- // and work correctly in the browser. The errors can be safely ignored.
7
-
8
- if (document.readyState === 'loading') {
9
- document.addEventListener('DOMContentLoaded', initializeHydration);
10
- } else {
11
- initializeHydration();
12
- }
13
-
14
- /**
15
- * Initialize hydration for all islands on the page
16
- * Discovers islands by data-framework attribute and routes to appropriate integration
17
- */
18
- function initializeHydration() {
19
- const islands = document.querySelectorAll('[data-framework]');
20
-
21
- if (islands.length === 0) {
22
- return;
23
- }
24
-
25
- islands.forEach(island => {
26
- try {
27
- const framework = island.dataset.framework;
28
- const condition = island.dataset.condition || 'on:client';
29
- const renderStrategy = island.dataset.renderStrategy;
30
-
31
- if (renderStrategy === 'ssr-only') {
32
- return;
33
- }
34
-
35
- if (!shouldHydrate(island, condition)) {
36
- return;
37
- }
38
-
39
- if (condition === 'on:client') {
40
- hydrateIsland(island, framework);
41
- } else if (condition === 'on:visible') {
42
- setupIntersectionObserver(island, framework);
43
- } else if (condition === 'on:interaction') {
44
- setupInteractionObserver(island, framework);
45
- } else if (condition === 'on:idle') {
46
- setupIdleCallback(island, framework);
47
- } else if (condition.startsWith('media:')) {
48
- const mediaQuery = condition.slice(6);
49
- setupMediaQuery(island, framework, mediaQuery);
50
- } else {
51
- hydrateIsland(island, framework);
52
- }
53
- } catch (error) {
54
- console.error('Error processing island:', error);
55
- handleHydrationError(island, island.dataset.framework || 'unknown', island.dataset.src || 'unknown', error);
56
- }
57
- });
58
- }
59
-
60
- /**
61
- * Determine if an island should hydrate based on its condition
62
- *
63
- * @param {HTMLElement} island - The island element
64
- * @param {string} condition - The hydration condition
65
- * @returns {boolean} Whether the island should hydrate
66
- */
67
- function shouldHydrate(island, condition) {
68
- if (!condition || condition === 'on:client') {
69
- return true;
70
- }
71
-
72
- if (condition.startsWith('media:')) {
73
- const mediaQuery = condition.slice(6);
74
- try {
75
- return globalThis.matchMedia(mediaQuery).matches;
76
- } catch (error) {
77
- console.error('Invalid media query:', mediaQuery, error);
78
- return true;
79
- }
80
- }
81
-
82
- if (condition === 'on:visible' || condition === 'on:interaction' || condition === 'on:idle') {
83
- return true;
84
- }
85
-
86
- console.warn('Unknown hydration condition:', condition);
87
- return true;
88
- }
89
-
90
- /**
91
- * Setup Intersection Observer for "on:visible" hydration
92
- *
93
- * @param {HTMLElement} island - The island element
94
- * @param {string} framework - The framework name
95
- */
96
- function setupIntersectionObserver(island, framework) {
97
- try {
98
- const observer = new IntersectionObserver(
99
- entries => {
100
- const entry = entries[0];
101
- if (entry.isIntersecting) {
102
- hydrateIsland(island, framework);
103
- observer.disconnect();
104
- }
105
- },
106
- {
107
- rootMargin: '50px',
108
- threshold: 0,
109
- },
110
- );
111
-
112
- observer.observe(island);
113
- } catch (error) {
114
- console.error('Failed to setup intersection observer:', error);
115
- hydrateIsland(island, framework);
116
- }
117
- }
118
-
119
- /**
120
- * Setup interaction observer for "on:interaction" hydration
121
- *
122
- * @param {HTMLElement} island - The island element
123
- * @param {string} framework - The framework name
124
- */
125
- function setupInteractionObserver(island, framework) {
126
- const events = ['click', 'touchstart', 'mouseenter', 'focusin'];
127
- let hydrated = false;
128
-
129
- const handleInteraction = () => {
130
- if (hydrated) return;
131
- hydrated = true;
132
-
133
- events.forEach(eventType => {
134
- island.removeEventListener(eventType, handleInteraction);
135
- });
136
-
137
- hydrateIsland(island, framework);
138
- };
139
-
140
- try {
141
- events.forEach(eventType => {
142
- island.addEventListener(eventType, handleInteraction, { once: true, passive: true });
143
- });
144
- } catch (error) {
145
- console.error('Failed to setup interaction observer:', error);
146
- hydrateIsland(island, framework);
147
- }
148
- }
149
-
150
- /**
151
- * Setup idle callback for "on:idle" hydration
152
- *
153
- * @param {HTMLElement} island - The island element
154
- * @param {string} framework - The framework name
155
- */
156
- function setupIdleCallback(island, framework) {
157
- try {
158
- if ('requestIdleCallback' in globalThis) {
159
- globalThis.requestIdleCallback(
160
- () => {
161
- hydrateIsland(island, framework);
162
- },
163
- { timeout: 5000 },
164
- );
165
- } else if (document.readyState === 'complete') {
166
- setTimeout(() => {
167
- hydrateIsland(island, framework);
168
- }, 200);
169
- } else {
170
- globalThis.addEventListener(
171
- 'load',
172
- () => {
173
- setTimeout(() => {
174
- hydrateIsland(island, framework);
175
- }, 200);
176
- },
177
- { once: true },
178
- );
179
- }
180
- } catch (error) {
181
- console.error('Failed to setup idle callback:', error);
182
- hydrateIsland(island, framework);
183
- }
184
- }
185
-
186
- /**
187
- * Setup media query listener for "media:" hydration
188
- *
189
- * @param {HTMLElement} island - The island element
190
- * @param {string} framework - The framework name
191
- * @param {string} mediaQuery - The media query string
192
- */
193
- function setupMediaQuery(island, framework, mediaQuery) {
194
- try {
195
- const mql = globalThis.matchMedia(mediaQuery);
196
-
197
- if (mql.matches) {
198
- hydrateIsland(island, framework);
199
- return;
200
- }
201
-
202
- const handleChange = event => {
203
- if (event.matches) {
204
- hydrateIsland(island, framework);
205
- mql.removeEventListener('change', handleChange);
206
- }
207
- };
208
-
209
- mql.addEventListener('change', handleChange);
210
- } catch (error) {
211
- console.error('Failed to setup media query:', mediaQuery, error);
212
- hydrateIsland(island, framework);
213
- }
214
- }
215
-
216
- /**
217
- * Load the integration module for a given framework
218
- *
219
- * @param {string} framework - The framework name
220
- * @returns {Promise<object>} The integration module
221
- */
222
- async function loadIntegrationModule(framework) {
223
- switch (framework) {
224
- case 'preact':
225
- // @ts-ignore - Vite resolves this at runtime
226
- return import('/@useavalon/preact/client');
227
- case 'react':
228
- // @ts-ignore - Vite resolves this at runtime
229
- return import('/@useavalon/react/client');
230
- case 'vue':
231
- // @ts-ignore - Vite resolves this at runtime
232
- return import('/@useavalon/vue/client');
233
- case 'svelte':
234
- // @ts-ignore - Vite resolves this at runtime
235
- return import('/@useavalon/svelte/client');
236
- case 'solid':
237
- // @ts-ignore - Vite resolves this at runtime
238
- return import('/@useavalon/solid/client');
239
- case 'lit':
240
- // @ts-ignore - Vite resolves this at runtime
241
- return import('/@useavalon/lit/client');
242
- case 'qwik':
243
- // @ts-ignore - Vite resolves this at runtime
244
- return import('/@useavalon/qwik/client');
245
- default:
246
- throw new Error(`Unknown framework: ${framework}`);
247
- }
248
- }
249
-
250
- /**
251
- * Resolve the component from a module, trying default export then named exports
252
- *
253
- * @param {object} componentModule - The imported module
254
- * @param {string} src - The component source path (for error messages)
255
- * @returns {object} The resolved component
256
- */
257
- function resolveComponent(componentModule, src) {
258
- let Component = componentModule.default;
259
-
260
- if (!Component) {
261
- const exports = Object.keys(componentModule).filter(key => key !== 'default');
262
- for (const exportName of exports) {
263
- const exportValue = componentModule[exportName];
264
- if (typeof exportValue === 'function' && exportValue.prototype) {
265
- Component = exportValue;
266
- break;
267
- }
268
- }
269
-
270
- if (!Component) {
271
- Component = componentModule;
272
- }
273
- }
274
-
275
- if (!Component) {
276
- throw new Error(`Component ${src} has no default export`);
277
- }
278
-
279
- return Component;
280
- }
281
-
282
- /**
283
- * Hydrate an island using the integration system
284
- *
285
- * @param {HTMLElement} island - The island element
286
- * @param {string} framework - The framework name
287
- */
288
- async function hydrateIsland(island, framework) {
289
- if (island.dataset.hydrated) {
290
- return;
291
- }
292
-
293
- const src = island.dataset.src;
294
- const propsAttr = island.dataset.props;
295
-
296
- if (!src) {
297
- console.warn('Island missing data-src attribute');
298
- return;
299
- }
300
-
301
- try {
302
- const props = propsAttr ? JSON.parse(propsAttr) : {};
303
-
304
- // CRITICAL: For Lit components, load hydration support BEFORE importing the component
305
- // This ensures our patch is applied before @customElement decorator runs
306
- if (framework === 'lit') {
307
- // @ts-ignore - Vite resolves this virtual module at runtime
308
- await import('/@useavalon/lit/client');
309
- }
310
-
311
- const componentModule = await import(/* @vite-ignore */ src);
312
- const Component = resolveComponent(componentModule, src);
313
-
314
- try {
315
- const integrationModule = await loadIntegrationModule(framework);
316
-
317
- if (!integrationModule.hydrate || typeof integrationModule.hydrate !== 'function') {
318
- throw new Error(`Integration ${framework} does not export a hydrate function`);
319
- }
320
-
321
- integrationModule.hydrate(island, Component, props);
322
- island.dataset.hydrated = 'true';
323
- } catch (integrationError) {
324
- if (import.meta.env?.DEV) {
325
- console.error(`Integration hydration failed for ${framework}: ${src}`, integrationError);
326
- }
327
-
328
- island.dataset.hydrationStatus = 'failed';
329
- island.dataset.hydrationError = integrationError.message;
330
-
331
- island.dispatchEvent(
332
- new CustomEvent('hydration-error', {
333
- detail: {
334
- framework,
335
- src,
336
- error: integrationError.message,
337
- timestamp: Date.now(),
338
- hydrationType: 'integration-level',
339
- },
340
- bubbles: true,
341
- }),
342
- );
343
- }
344
- } catch (error) {
345
- console.error(`❌ Critical error hydrating ${framework} island ${src}:`, error);
346
- handleHydrationError(island, framework, src, error);
347
- }
348
- }
349
-
350
- /**
351
- * Handle hydration errors with graceful degradation
352
- *
353
- * @param {HTMLElement} island - The island element
354
- * @param {string} framework - The framework name
355
- * @param {string} src - The component source path
356
- * @param {Error} error - The error that occurred
357
- */
358
- function handleHydrationError(island, framework, src, error) {
359
- console.error(`Hydration error for ${framework} island:`, {
360
- src,
361
- error: error.message,
362
- stack: error.stack,
363
- });
364
-
365
- island.dataset.hydrationStatus = 'failed';
366
- island.dataset.renderStrategy = 'ssr-only';
367
- island.classList.add('hydration-failed');
368
-
369
- island.dispatchEvent(
370
- new CustomEvent('hydration-error', {
371
- detail: {
372
- framework,
373
- src,
374
- error: error.message,
375
- timestamp: Date.now(),
376
- },
377
- bubbles: true,
378
- }),
379
- );
380
-
381
- if (isDevelopment()) {
382
- addErrorIndicator(island, framework, src, error);
383
- }
384
- }
385
-
386
- /**
387
- * Add visual error indicator in development mode
388
- *
389
- * @param {HTMLElement} island - The island element
390
- * @param {string} framework - The framework name
391
- * @param {string} src - The component source path
392
- * @param {Error} error - The error that occurred
393
- */
394
- function addErrorIndicator(island, framework, src, error) {
395
- const indicator = document.createElement('div');
396
- indicator.className = 'hydration-error-indicator';
397
- indicator.style.cssText = `
398
- position: absolute;
399
- top: 0;
400
- right: 0;
401
- background: #ff4444;
402
- color: white;
403
- padding: 4px 8px;
404
- font-size: 11px;
405
- font-family: monospace;
406
- border-radius: 0 0 0 4px;
407
- z-index: 9999;
408
- cursor: pointer;
409
- box-shadow: 0 2px 4px rgba(0,0,0,0.2);
410
- `;
411
- indicator.textContent = `❌ ${framework}`;
412
- indicator.title = `Hydration failed: ${src}\n${error.message}\nClick for details`;
413
-
414
- indicator.addEventListener('click', () => {
415
- alert(
416
- `Hydration Error\n\nFramework: ${framework}\nComponent: ${src}\n\nError: ${error.message}\n\nStack:\n${error.stack}`,
417
- );
418
- });
419
-
420
- const computedStyle = globalThis.getComputedStyle(island);
421
- if (computedStyle.position === 'static') {
422
- island.style.position = 'relative';
423
- }
424
-
425
- island.appendChild(indicator);
426
- }
427
-
428
- /**
429
- * Check if running in development mode
430
- *
431
- * @returns {boolean} True if in development
432
- */
433
- function isDevelopment() {
434
- return (
435
- import.meta.env?.DEV ||
436
- import.meta.env?.MODE === 'development' ||
437
- globalThis.location?.hostname === 'localhost' ||
438
- globalThis.location?.hostname === '127.0.0.1'
439
- );
440
- }
441
-
442
- /**
443
- * Store island state before HMR update
444
- * @param {HTMLElement} island - The island element
445
- * @returns {object|null} The preserved state
446
- */
447
- function preserveIslandState(island) {
448
- const framework = island.dataset.framework;
449
- const src = island.dataset.src;
450
-
451
- if (!src) return null;
452
-
453
- const state = {
454
- framework,
455
- src,
456
- props: island.dataset.props,
457
- scrollPosition: {
458
- x: globalThis.scrollX,
459
- y: globalThis.scrollY,
460
- },
461
- focusedElement: document.activeElement?.id || null,
462
- };
463
-
464
- try {
465
- if (framework === 'vue' && island.__vue__) {
466
- state.vueData = structuredClone(island.__vue__.$data || {});
467
- } else if (framework === 'svelte' && island.__svelte__) {
468
- state.svelteState = island.__svelte__;
469
- } else if (framework === 'lit' && island.tagName?.includes('-')) {
470
- const litElement = island.querySelector('[data-lit-element]') || island;
471
- if (litElement._$litElement$) {
472
- state.litProperties = {};
473
- }
474
- }
475
- } catch (error) {
476
- console.warn('Failed to preserve island state:', error);
477
- }
478
-
479
- return state;
480
- }
481
-
482
- /**
483
- * Restore island state after HMR update
484
- * @param {HTMLElement} island - The island element
485
- * @param {object} state - The preserved state
486
- */
487
- function restoreIslandState(island, state) {
488
- if (!state) return;
489
-
490
- try {
491
- if (state.scrollPosition) {
492
- globalThis.scrollTo(state.scrollPosition.x, state.scrollPosition.y);
493
- }
494
-
495
- if (state.focusedElement) {
496
- const element = document.getElementById(state.focusedElement);
497
- if (element) {
498
- element.focus();
499
- }
500
- }
501
-
502
- if (island.dataset.framework === 'vue' && state.vueData && island.__vue__) {
503
- Object.assign(island.__vue__.$data, state.vueData);
504
- }
505
- } catch (error) {
506
- console.warn('Failed to restore island state:', error);
507
- }
508
- }
509
-
510
- /**
511
- * Hydrate an island with a fresh module (cache-busted)
512
- * @param {HTMLElement} island - The island element
513
- * @param {string} framework - The framework name
514
- * @param {string} freshSrc - The cache-busted source path
515
- * @param {string} originalSrc - The original source path
516
- */
517
- async function hydrateIslandWithFreshModule(island, framework, freshSrc, originalSrc) {
518
- const propsAttr = island.dataset.props;
519
- const props = propsAttr ? JSON.parse(propsAttr) : {};
520
-
521
- if (framework === 'lit') {
522
- // @ts-ignore - Vite resolves this at runtime
523
- await import('/@useavalon/lit/client');
524
- }
525
-
526
- const componentModule = await import(/* @vite-ignore */ freshSrc);
527
- const Component = resolveComponent(componentModule, originalSrc);
528
-
529
- const integrationModule = await loadIntegrationModule(framework);
530
-
531
- if (!integrationModule.hydrate || typeof integrationModule.hydrate !== 'function') {
532
- throw new Error(`Integration ${framework} does not export a hydrate function`);
533
- }
534
-
535
- integrationModule.hydrate(island, Component, props);
536
- island.dataset.hydrated = 'true';
537
- }
538
-
539
- /**
540
- * Show inline HMR error indicator
541
- * @param {HTMLElement} island - The island element
542
- * @param {string} framework - The framework name
543
- * @param {string} src - The component source path
544
- * @param {Error} error - The error that occurred
545
- */
546
- function showInlineHMRError(island, framework, src, error) {
547
- const existing = island.querySelector('.hmr-error-indicator');
548
- if (existing) {
549
- existing.remove();
550
- }
551
-
552
- const indicator = document.createElement('div');
553
- indicator.className = 'hmr-error-indicator';
554
- indicator.style.cssText = `
555
- position: absolute;
556
- top: 0;
557
- left: 0;
558
- right: 0;
559
- background: linear-gradient(135deg, #ff6b6b, #ee5a5a);
560
- color: white;
561
- padding: 8px 12px;
562
- font-size: 12px;
563
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, monospace;
564
- z-index: 10000;
565
- box-shadow: 0 2px 8px rgba(0,0,0,0.3);
566
- display: flex;
567
- align-items: center;
568
- gap: 8px;
569
- `;
570
-
571
- const icon = document.createElement('span');
572
- icon.textContent = '⚠️';
573
- icon.style.fontSize = '14px';
574
-
575
- const message = document.createElement('span');
576
- message.style.flex = '1';
577
- message.innerHTML = `<strong>HMR Failed:</strong> ${error.message.slice(0, 100)}${error.message.length > 100 ? '...' : ''}`;
578
-
579
- const dismissBtn = document.createElement('button');
580
- dismissBtn.textContent = '×';
581
- dismissBtn.style.cssText = `
582
- background: rgba(255,255,255,0.2);
583
- border: none;
584
- color: white;
585
- width: 20px;
586
- height: 20px;
587
- border-radius: 50%;
588
- cursor: pointer;
589
- font-size: 14px;
590
- line-height: 1;
591
- `;
592
- dismissBtn.onclick = () => indicator.remove();
593
-
594
- indicator.appendChild(icon);
595
- indicator.appendChild(message);
596
- indicator.appendChild(dismissBtn);
597
-
598
- const computedStyle = globalThis.getComputedStyle(island);
599
- if (computedStyle.position === 'static') {
600
- island.style.position = 'relative';
601
- }
602
-
603
- island.insertBefore(indicator, island.firstChild);
604
- }
605
-
606
- // HMR support for development
607
- if (import.meta.hot) {
608
- import.meta.hot.accept();
609
-
610
- // Lazy HMR adapter registration - only load adapters for frameworks used on the page
611
- import('./hmr-coordinator.js')
612
- .then(async ({ initializeHMR, getHMRCoordinator }) => {
613
- initializeHMR();
614
-
615
- const coordinator = getHMRCoordinator();
616
-
617
- // Discover which frameworks are actually used on this page
618
- const usedFrameworks = new Set();
619
- document.querySelectorAll('[data-framework]').forEach(island => {
620
- const framework = island.dataset.framework;
621
- if (framework) usedFrameworks.add(framework);
622
- });
623
-
624
- // Only register adapters for frameworks that are used
625
- // Adapters are loaded from their respective integration packages
626
- const adapterLoaders = {
627
- // @ts-ignore - Vite resolves these virtual modules at runtime
628
- react: () => import('/@useavalon/react/client/hmr').then(m => m.reactAdapter),
629
- // @ts-ignore - Vite resolves these virtual modules at runtime
630
- preact: () => import('/@useavalon/preact/client/hmr').then(m => m.preactAdapter),
631
- // @ts-ignore - Vite resolves these virtual modules at runtime
632
- vue: () => import('/@useavalon/vue/client/hmr').then(m => m.vueAdapter),
633
- // @ts-ignore - Vite resolves these virtual modules at runtime
634
- svelte: () => import('/@useavalon/svelte/client/hmr').then(m => m.svelteAdapter),
635
- // @ts-ignore - Vite resolves these virtual modules at runtime
636
- solid: () => import('/@useavalon/solid/client/hmr').then(m => m.solidAdapter),
637
- // @ts-ignore - Vite resolves these virtual modules at runtime
638
- lit: () => import('/@useavalon/lit/client/hmr').then(m => m.litAdapter),
639
- // @ts-ignore - Vite resolves these virtual modules at runtime
640
- qwik: () => import('/@useavalon/qwik/client/hmr').then(m => m.qwikAdapter),
641
- };
642
-
643
- for (const framework of usedFrameworks) {
644
- const loader = adapterLoaders[framework];
645
- if (loader) {
646
- try {
647
- const adapter = await loader();
648
- coordinator.registerAdapter(framework, adapter);
649
- } catch (error) {
650
- console.warn(`[HMR] Failed to load adapter for ${framework}:`, error);
651
- }
652
- }
653
- }
654
- })
655
- .catch(error => {
656
- console.error('[HMR] Failed to initialize:', error);
657
- });
658
-
659
- // Enhanced HMR support for nested islands
660
- setupNestedIslandHMR();
661
- }
662
-
663
- /**
664
- * Show HMR error feedback on the island
665
- * @param {HTMLElement} island - The island element
666
- * @param {string} hmrFramework - The framework name
667
- * @param {string} hmrSrc - The component source path
668
- * @param {Error} error - The error that occurred
669
- */
670
- async function showHMRError(island, hmrFramework, hmrSrc, error) {
671
- try {
672
- const { showHMRErrorOverlay } = await import('./hmr-error-overlay.js');
673
- showHMRErrorOverlay({
674
- framework: hmrFramework,
675
- src: hmrSrc,
676
- error,
677
- filePath: hmrSrc,
678
- });
679
- } catch {
680
- showInlineHMRError(island, hmrFramework, hmrSrc, error);
681
- }
682
- }
683
-
684
- /**
685
- * Setup HMR support for nested island directories.
686
- * Handles hot module replacement for islands in any discovered directory,
687
- * including nested paths like /src/modules/[module]/islands/.
688
- */
689
- function setupNestedIslandHMR() {
690
- if (!import.meta.hot) return;
691
-
692
- const hydratedIslands = new Map();
693
-
694
- async function handleIslandHMR(modulePath) {
695
- const normalizedPath = modulePath.replaceAll('\\', '/');
696
-
697
- const islands = document.querySelectorAll(`[data-src*="${normalizedPath}"], [data-src$="${normalizedPath}"]`);
698
-
699
- if (islands.length === 0) {
700
- const allIslands = document.querySelectorAll('[data-src]');
701
- for (const island of allIslands) {
702
- const src = island.dataset.src;
703
- if (src && (src.includes(normalizedPath) || normalizedPath.includes(src.replace(/^\//, '')))) {
704
- await rehydrateIsland(island);
705
- }
706
- }
707
- return;
708
- }
709
-
710
- for (const island of islands) {
711
- await rehydrateIsland(island);
712
- }
713
- }
714
-
715
- async function rehydrateIsland(island) {
716
- const framework = island.dataset.framework;
717
- const src = island.dataset.src;
718
-
719
- if (!src || !framework) return;
720
-
721
- try {
722
- const state = preserveIslandState(island);
723
- hydratedIslands.set(src, state);
724
-
725
- delete island.dataset.hydrated;
726
- delete island.dataset.hydrationStatus;
727
-
728
- const errorIndicator = island.querySelector('.hydration-error-indicator');
729
- if (errorIndicator) {
730
- errorIndicator.remove();
731
- }
732
-
733
- const timestamp = Date.now();
734
- const freshSrc = src.includes('?') ? `${src}&t=${timestamp}` : `${src}?t=${timestamp}`;
735
-
736
- await hydrateIslandWithFreshModule(island, framework, freshSrc, src);
737
-
738
- const preservedState = hydratedIslands.get(src);
739
- if (preservedState) {
740
- restoreIslandState(island, preservedState);
741
- hydratedIslands.delete(src);
742
- }
743
-
744
- island.dispatchEvent(
745
- new CustomEvent('hmr-update', {
746
- detail: {
747
- framework,
748
- src,
749
- timestamp: Date.now(),
750
- success: true,
751
- },
752
- bubbles: true,
753
- }),
754
- );
755
- } catch (error) {
756
- console.error(`[HMR] Failed for ${framework} island ${src}:`, error);
757
-
758
- island.dispatchEvent(
759
- new CustomEvent('hmr-error', {
760
- detail: {
761
- framework,
762
- src,
763
- error: error.message,
764
- timestamp: Date.now(),
765
- },
766
- bubbles: true,
767
- }),
768
- );
769
-
770
- if (isDevelopment()) {
771
- showHMRError(island, framework, src, error);
772
- }
773
- }
774
- }
775
-
776
- // Listen for Vite HMR events
777
- import.meta.hot.on('vite:beforeUpdate', payload => {
778
- for (const update of payload.updates || []) {
779
- const path = update.path || update.acceptedPath;
780
- if (path && (path.includes('/islands/') || path.includes('\\islands\\'))) {
781
- handleIslandHMR(path);
782
- }
783
- }
784
- });
785
-
786
- // Handle full page reloads for islands
787
- import.meta.hot.on('vite:beforeFullReload', () => {
788
- const islands = document.querySelectorAll('[data-hydrated="true"]');
789
- const states = {};
790
-
791
- for (const island of islands) {
792
- const src = island.dataset.src;
793
- if (src) {
794
- states[src] = preserveIslandState(island);
795
- }
796
- }
797
-
798
- try {
799
- sessionStorage.setItem('__avalon_hmr_states__', JSON.stringify(states));
800
- } catch {
801
- // sessionStorage might not be available
802
- }
803
- });
804
-
805
- // Restore states after page load (for full reloads)
806
- try {
807
- const savedStates = sessionStorage.getItem('__avalon_hmr_states__');
808
- if (savedStates) {
809
- const states = JSON.parse(savedStates);
810
- sessionStorage.removeItem('__avalon_hmr_states__');
811
-
812
- setTimeout(() => {
813
- for (const [src, state] of Object.entries(states)) {
814
- const island = document.querySelector(`[data-src="${src}"]`);
815
- if (island && state) {
816
- restoreIslandState(island, state);
817
- }
818
- }
819
- }, 100);
820
- }
821
- } catch {
822
- // Ignore errors - state restoration is best-effort
823
- }
824
- }