@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,396 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HMR Coordinator
|
|
3
|
+
*
|
|
4
|
+
* Central orchestrator for all HMR operations in Avalon.
|
|
5
|
+
* Integrates with Vite's HMR API and coordinates island updates across frameworks.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/// <reference lib="dom" />
|
|
9
|
+
/// <reference lib="dom.iterable" />
|
|
10
|
+
|
|
11
|
+
import { type FrameworkHMRAdapter, type StateSnapshot, AdapterRegistry } from './framework-adapter.ts';
|
|
12
|
+
import { getCSSHMRHandler } from './css-hmr-handler.ts';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Vite HMR types (defined locally to avoid import issues)
|
|
16
|
+
*/
|
|
17
|
+
export interface HMRPayload {
|
|
18
|
+
type: string;
|
|
19
|
+
updates?: Update[];
|
|
20
|
+
timestamp?: number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface ErrorPayload {
|
|
24
|
+
type: 'error';
|
|
25
|
+
err: {
|
|
26
|
+
message: string;
|
|
27
|
+
stack: string;
|
|
28
|
+
id?: string;
|
|
29
|
+
frame?: string;
|
|
30
|
+
plugin?: string;
|
|
31
|
+
pluginCode?: string;
|
|
32
|
+
loc?: {
|
|
33
|
+
file?: string;
|
|
34
|
+
line: number;
|
|
35
|
+
column: number;
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface Update {
|
|
41
|
+
type: 'js-update' | 'css-update';
|
|
42
|
+
path: string;
|
|
43
|
+
acceptedPath: string;
|
|
44
|
+
timestamp: number;
|
|
45
|
+
explicitImportRequired?: boolean;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* HMR update payload from Vite
|
|
50
|
+
*/
|
|
51
|
+
export interface HMRUpdatePayload extends HMRPayload {
|
|
52
|
+
type: 'update' | 'full-reload' | 'prune' | 'error';
|
|
53
|
+
updates?: ModuleUpdate[];
|
|
54
|
+
timestamp?: number;
|
|
55
|
+
err?: ErrorPayload;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Individual module update information
|
|
60
|
+
*/
|
|
61
|
+
export interface ModuleUpdate {
|
|
62
|
+
type: 'js-update' | 'css-update';
|
|
63
|
+
path: string;
|
|
64
|
+
acceptedPath: string;
|
|
65
|
+
timestamp: number;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Re-export types for backward compatibility
|
|
69
|
+
export type { FrameworkHMRAdapter, StateSnapshot } from './framework-adapter.ts';
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* HMR Coordinator class
|
|
73
|
+
* Manages HMR lifecycle and coordinates updates across islands
|
|
74
|
+
*/
|
|
75
|
+
export class HMRCoordinator {
|
|
76
|
+
private readonly registry: AdapterRegistry = new AdapterRegistry();
|
|
77
|
+
private readonly stateSnapshots: Map<string, StateSnapshot> = new Map();
|
|
78
|
+
private readonly updateQueue: Set<string> = new Set();
|
|
79
|
+
private isProcessing = false;
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Initialize the HMR coordinator
|
|
83
|
+
* Sets up Vite HMR listeners and accepts updates
|
|
84
|
+
*/
|
|
85
|
+
initialize(): void {
|
|
86
|
+
// @ts-ignore - Vite HMR is available in browser context
|
|
87
|
+
if (!import.meta.hot) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// @ts-ignore - Vite HMR API
|
|
92
|
+
import.meta.hot.accept();
|
|
93
|
+
|
|
94
|
+
// @ts-ignore - Vite HMR event types
|
|
95
|
+
import.meta.hot.on('vite:beforeUpdate', (payload: HMRPayload) => {
|
|
96
|
+
this.handleUpdate(payload as HMRUpdatePayload);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// @ts-ignore - Vite HMR event types
|
|
100
|
+
import.meta.hot.on('vite:beforeFullReload', () => {
|
|
101
|
+
this.handleBeforeFullReload();
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// @ts-ignore - Vite HMR event types
|
|
105
|
+
import.meta.hot.on('vite:error', (payload: ErrorPayload) => {
|
|
106
|
+
console.error('[HMR] error:', payload);
|
|
107
|
+
this.handleError(payload);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
document.addEventListener('hmr-update-required', (event: Event) => {
|
|
111
|
+
const customEvent = event as CustomEvent;
|
|
112
|
+
const { src, reason } = customEvent.detail;
|
|
113
|
+
|
|
114
|
+
if (reason === 'css-module-update') {
|
|
115
|
+
this.updateQueue.add(this.normalizePath(src));
|
|
116
|
+
|
|
117
|
+
if (!this.isProcessing) {
|
|
118
|
+
this.processUpdateQueue().catch(error => {
|
|
119
|
+
console.error('[HMR] Failed to process CSS module update:', error);
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
registerAdapter(framework: string, adapter: FrameworkHMRAdapter): void {
|
|
127
|
+
this.registry.register(framework, adapter);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
getRegistry(): AdapterRegistry {
|
|
131
|
+
return this.registry;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async handleUpdate(payload: HMRUpdatePayload): Promise<void> {
|
|
135
|
+
if (payload.type !== 'update' || !payload.updates) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const cssUpdates: ModuleUpdate[] = [];
|
|
140
|
+
const jsUpdates: ModuleUpdate[] = [];
|
|
141
|
+
|
|
142
|
+
for (const update of payload.updates) {
|
|
143
|
+
if (update.type === 'css-update') {
|
|
144
|
+
cssUpdates.push(update);
|
|
145
|
+
} else {
|
|
146
|
+
jsUpdates.push(update);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
this.processCSSUpdates(cssUpdates);
|
|
151
|
+
this.queueJSUpdates(jsUpdates);
|
|
152
|
+
|
|
153
|
+
if (!this.isProcessing && this.updateQueue.size > 0) {
|
|
154
|
+
await this.processUpdateQueue();
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
private processCSSUpdates(cssUpdates: ModuleUpdate[]): void {
|
|
159
|
+
if (cssUpdates.length === 0) return;
|
|
160
|
+
|
|
161
|
+
const cssHandler = getCSSHMRHandler();
|
|
162
|
+
for (const cssUpdate of cssUpdates) {
|
|
163
|
+
try {
|
|
164
|
+
cssHandler.handleCSSUpdate(cssUpdate);
|
|
165
|
+
} catch (error) {
|
|
166
|
+
console.error('[HMR] CSS update failed:', error);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
private queueJSUpdates(jsUpdates: ModuleUpdate[]): void {
|
|
172
|
+
for (const update of jsUpdates) {
|
|
173
|
+
const normalizedPath = this.normalizePath(update.path || update.acceptedPath);
|
|
174
|
+
if (this.isIslandModule(normalizedPath)) {
|
|
175
|
+
this.updateQueue.add(normalizedPath);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
private async processUpdateQueue(): Promise<void> {
|
|
181
|
+
if (this.updateQueue.size === 0) return;
|
|
182
|
+
|
|
183
|
+
this.isProcessing = true;
|
|
184
|
+
|
|
185
|
+
try {
|
|
186
|
+
const paths = Array.from(this.updateQueue);
|
|
187
|
+
this.updateQueue.clear();
|
|
188
|
+
|
|
189
|
+
for (const path of paths) {
|
|
190
|
+
const islands = this.findAffectedIslands(path);
|
|
191
|
+
for (const island of islands) {
|
|
192
|
+
try {
|
|
193
|
+
await this.updateIsland(island);
|
|
194
|
+
} catch (error) {
|
|
195
|
+
console.error('[HMR] Failed to update island:', error);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
} finally {
|
|
200
|
+
this.isProcessing = false;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
findAffectedIslands(modulePath: string): HTMLElement[] {
|
|
205
|
+
const islands: HTMLElement[] = [];
|
|
206
|
+
const normalizedPath = this.normalizePath(modulePath);
|
|
207
|
+
const allIslands = document.querySelectorAll<HTMLElement>('[data-src]');
|
|
208
|
+
|
|
209
|
+
for (const island of allIslands) {
|
|
210
|
+
const src = island.dataset.src;
|
|
211
|
+
if (!src) continue;
|
|
212
|
+
|
|
213
|
+
const normalizedSrc = this.normalizePath(src);
|
|
214
|
+
const isMatch =
|
|
215
|
+
normalizedSrc === normalizedPath ||
|
|
216
|
+
normalizedSrc.endsWith(normalizedPath) ||
|
|
217
|
+
normalizedPath.endsWith(normalizedSrc) ||
|
|
218
|
+
normalizedSrc.split('/').pop() === normalizedPath.split('/').pop();
|
|
219
|
+
|
|
220
|
+
if (isMatch) {
|
|
221
|
+
islands.push(island);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
return islands;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
async updateIsland(island: HTMLElement): Promise<void> {
|
|
229
|
+
const framework = island.dataset.framework;
|
|
230
|
+
const src = island.dataset.src;
|
|
231
|
+
const propsAttr = island.dataset.props;
|
|
232
|
+
|
|
233
|
+
if (!framework || !src) {
|
|
234
|
+
console.warn('[HMR] Island missing framework or src attribute', island);
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const adapter = this.registry.get(framework.toLowerCase());
|
|
239
|
+
if (!adapter) {
|
|
240
|
+
console.warn(`[HMR] No adapter registered for framework: ${framework}`);
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
try {
|
|
245
|
+
const props = propsAttr ? JSON.parse(propsAttr) : {};
|
|
246
|
+
const state = adapter.preserveState(island);
|
|
247
|
+
|
|
248
|
+
if (state) {
|
|
249
|
+
this.stateSnapshots.set(this.getIslandId(island), state);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
delete island.dataset.hydrated;
|
|
253
|
+
delete island.dataset.hydrationStatus;
|
|
254
|
+
|
|
255
|
+
island.querySelector('.hydration-error-indicator, .hmr-error-indicator')?.remove();
|
|
256
|
+
|
|
257
|
+
const timestamp = Date.now();
|
|
258
|
+
const freshSrc = src.includes('?') ? `${src}&t=${timestamp}` : `${src}?t=${timestamp}`;
|
|
259
|
+
const componentModule = await import(/* @vite-ignore */ freshSrc);
|
|
260
|
+
const Component = this.resolveComponent(componentModule, src);
|
|
261
|
+
|
|
262
|
+
await adapter.update(island, Component, props);
|
|
263
|
+
|
|
264
|
+
if (state) {
|
|
265
|
+
adapter.restoreState(island, state);
|
|
266
|
+
this.stateSnapshots.delete(this.getIslandId(island));
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
island.dataset.hydrated = 'true';
|
|
270
|
+
|
|
271
|
+
island.dispatchEvent(
|
|
272
|
+
new CustomEvent('hmr-update', {
|
|
273
|
+
detail: { framework, src, timestamp: Date.now(), success: true },
|
|
274
|
+
bubbles: true,
|
|
275
|
+
}),
|
|
276
|
+
);
|
|
277
|
+
} catch (error) {
|
|
278
|
+
console.error(`[HMR] Failed to update ${framework} island ${src}:`, error);
|
|
279
|
+
adapter.handleError(island, error as Error);
|
|
280
|
+
|
|
281
|
+
island.dispatchEvent(
|
|
282
|
+
new CustomEvent('hmr-error', {
|
|
283
|
+
detail: { framework, src, error: (error as Error).message, timestamp: Date.now() },
|
|
284
|
+
bubbles: true,
|
|
285
|
+
}),
|
|
286
|
+
);
|
|
287
|
+
|
|
288
|
+
throw error;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
private resolveComponent(componentModule: Record<string, unknown>, src: string): unknown {
|
|
293
|
+
if (componentModule.default) return componentModule.default;
|
|
294
|
+
|
|
295
|
+
for (const key of Object.keys(componentModule)) {
|
|
296
|
+
if (key === 'default') continue;
|
|
297
|
+
const value = componentModule[key];
|
|
298
|
+
if (typeof value === 'function' && value.prototype) {
|
|
299
|
+
return value;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
throw new Error(`Component ${src} has no default export`);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
private handleBeforeFullReload(): void {
|
|
307
|
+
const islands = document.querySelectorAll<HTMLElement>('[data-hydrated="true"]');
|
|
308
|
+
const states: Record<string, StateSnapshot> = {};
|
|
309
|
+
|
|
310
|
+
for (const island of islands) {
|
|
311
|
+
const framework = island.dataset.framework;
|
|
312
|
+
const src = island.dataset.src;
|
|
313
|
+
|
|
314
|
+
if (!framework || !src) continue;
|
|
315
|
+
|
|
316
|
+
const adapter = this.registry.get(framework.toLowerCase());
|
|
317
|
+
if (!adapter) continue;
|
|
318
|
+
|
|
319
|
+
const state = adapter.preserveState(island);
|
|
320
|
+
if (state) {
|
|
321
|
+
states[src] = state;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
try {
|
|
326
|
+
sessionStorage.setItem('__avalon_hmr_states__', JSON.stringify(states));
|
|
327
|
+
} catch (error) {
|
|
328
|
+
console.warn('[HMR] Failed to save states:', error);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
private handleError(payload: ErrorPayload): void {
|
|
333
|
+
const error = new Error(payload.err.message);
|
|
334
|
+
error.stack = payload.err.stack;
|
|
335
|
+
|
|
336
|
+
console.error('[HMR] Error:', error);
|
|
337
|
+
|
|
338
|
+
if (globalThis.window !== undefined) {
|
|
339
|
+
// @ts-ignore - dynamic import of JS file
|
|
340
|
+
import('./hmr-error-overlay.js')
|
|
341
|
+
.then(({ showHMRErrorOverlay }: { showHMRErrorOverlay: (opts: Record<string, unknown>) => void }) => {
|
|
342
|
+
showHMRErrorOverlay({
|
|
343
|
+
framework: 'unknown',
|
|
344
|
+
src: 'unknown',
|
|
345
|
+
error,
|
|
346
|
+
filePath: payload.err.id || payload.err.loc?.file || 'unknown',
|
|
347
|
+
line: payload.err.loc?.line,
|
|
348
|
+
column: payload.err.loc?.column,
|
|
349
|
+
});
|
|
350
|
+
})
|
|
351
|
+
.catch(() => {
|
|
352
|
+
console.error('[HMR] Failed to show error overlay');
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
private normalizePath(path: string): string {
|
|
358
|
+
return path
|
|
359
|
+
.replaceAll('\\', '/')
|
|
360
|
+
.replace(/^\//, '')
|
|
361
|
+
.replace(/\?.*$/, '')
|
|
362
|
+
.replace(/#.*$/, '')
|
|
363
|
+
.replace(/^src\//, '');
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
private isIslandModule(path: string): boolean {
|
|
367
|
+
return path.includes('/islands/') || path.includes('\\islands\\');
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
private getIslandId(island: HTMLElement): string {
|
|
371
|
+
const src = island.dataset.src ?? '';
|
|
372
|
+
const framework = island.dataset.framework ?? '';
|
|
373
|
+
const index = Array.from(document.querySelectorAll(`[data-src="${src}"]`)).indexOf(island);
|
|
374
|
+
return `${framework}:${src}:${index}`;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* Global HMR coordinator instance
|
|
380
|
+
*/
|
|
381
|
+
let coordinatorInstance: HMRCoordinator | null = null;
|
|
382
|
+
|
|
383
|
+
export function getHMRCoordinator(): HMRCoordinator {
|
|
384
|
+
coordinatorInstance ??= new HMRCoordinator();
|
|
385
|
+
return coordinatorInstance;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
export function initializeHMR(): void {
|
|
389
|
+
// @ts-ignore - Vite HMR is available in browser context
|
|
390
|
+
if (!import.meta.hot) {
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
const coordinator = getHMRCoordinator();
|
|
395
|
+
coordinator.initialize();
|
|
396
|
+
}
|