@absolutejs/absolute 0.19.0-beta.705 → 0.19.0-beta.706

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 (84) hide show
  1. package/dist/angular/browser.js +6 -4
  2. package/dist/angular/browser.js.map +3 -3
  3. package/dist/angular/index.js +19 -10
  4. package/dist/angular/index.js.map +3 -3
  5. package/dist/angular/server.js +19 -10
  6. package/dist/angular/server.js.map +3 -3
  7. package/dist/build.js +145 -78
  8. package/dist/build.js.map +10 -10
  9. package/dist/cli/index.js +18 -11
  10. package/dist/client/index.js +4 -2
  11. package/dist/client/index.js.map +2 -2
  12. package/dist/index.js +166 -90
  13. package/dist/index.js.map +12 -12
  14. package/dist/islands/index.js +5 -3
  15. package/dist/islands/index.js.map +2 -2
  16. package/dist/react/browser.js +7 -7
  17. package/dist/react/browser.js.map +2 -2
  18. package/dist/react/components/browser/index.js +101 -101
  19. package/dist/react/components/index.js +104 -104
  20. package/dist/react/components/index.js.map +2 -2
  21. package/dist/react/index.js +29 -20
  22. package/dist/react/index.js.map +3 -3
  23. package/dist/react/server.js +15 -8
  24. package/dist/react/server.js.map +3 -3
  25. package/dist/src/angular/components/defer-slot-templates.directive.d.ts +0 -7
  26. package/dist/src/angular/components/defer-slot.component.d.ts +2 -5
  27. package/dist/src/angular/components/image.component.d.ts +2 -5
  28. package/dist/src/angular/components/index.d.ts +4 -4
  29. package/dist/src/angular/components/stream-slot.component.d.ts +0 -3
  30. package/dist/src/build/buildAngularVendor.d.ts +3 -4
  31. package/dist/src/utils/imageProcessing.d.ts +1 -1
  32. package/dist/src/vue/components/Image.d.ts +1 -1
  33. package/dist/svelte/index.js +19 -10
  34. package/dist/svelte/index.js.map +3 -3
  35. package/dist/svelte/server.js +16 -9
  36. package/dist/svelte/server.js.map +3 -3
  37. package/dist/vue/index.js +19 -10
  38. package/dist/vue/index.js.map +3 -3
  39. package/dist/vue/server.js +15 -8
  40. package/dist/vue/server.js.map +3 -3
  41. package/package.json +1 -1
  42. package/dist/angular/components/constants.js +0 -77
  43. package/dist/angular/components/core/streamingSlotRegistrar.js +0 -58
  44. package/dist/angular/components/core/streamingSlotRegistry.js +0 -114
  45. package/dist/angular/components/defer-slot-payload.js +0 -6
  46. package/dist/angular/components/defer-slot-templates.directive.js +0 -44
  47. package/dist/angular/components/defer-slot.component.js +0 -149
  48. package/dist/angular/components/image.component.js +0 -202
  49. package/dist/angular/components/index.js +0 -4
  50. package/dist/angular/components/stream-slot.component.js +0 -103
  51. package/dist/dev/client/constants.ts +0 -26
  52. package/dist/dev/client/cssUtils.ts +0 -307
  53. package/dist/dev/client/domDiff.ts +0 -226
  54. package/dist/dev/client/domState.ts +0 -421
  55. package/dist/dev/client/domTracker.ts +0 -61
  56. package/dist/dev/client/errorOverlay.ts +0 -184
  57. package/dist/dev/client/frameworkDetect.ts +0 -63
  58. package/dist/dev/client/handlers/angular.ts +0 -551
  59. package/dist/dev/client/handlers/angularRuntime.ts +0 -206
  60. package/dist/dev/client/handlers/html.ts +0 -363
  61. package/dist/dev/client/handlers/htmx.ts +0 -272
  62. package/dist/dev/client/handlers/react.ts +0 -108
  63. package/dist/dev/client/handlers/rebuild.ts +0 -153
  64. package/dist/dev/client/handlers/svelte.ts +0 -332
  65. package/dist/dev/client/handlers/vue.ts +0 -292
  66. package/dist/dev/client/headPatch.ts +0 -233
  67. package/dist/dev/client/hmrClient.ts +0 -251
  68. package/dist/dev/client/hmrState.ts +0 -14
  69. package/dist/dev/client/moduleVersions.ts +0 -62
  70. package/dist/dev/client/reactRefreshSetup.ts +0 -33
  71. package/dist/src/angular/components/constants.d.ts +0 -74
  72. package/dist/svelte/components/AwaitSlot.svelte +0 -39
  73. package/dist/svelte/components/AwaitSlot.svelte.d.ts +0 -2
  74. package/dist/svelte/components/Head.svelte +0 -144
  75. package/dist/svelte/components/Head.svelte.d.ts +0 -2
  76. package/dist/svelte/components/Image.svelte +0 -164
  77. package/dist/svelte/components/Image.svelte.d.ts +0 -5
  78. package/dist/svelte/components/Island.svelte +0 -71
  79. package/dist/svelte/components/Island.svelte.d.ts +0 -5
  80. package/dist/svelte/components/JsonLd.svelte +0 -21
  81. package/dist/svelte/components/JsonLd.svelte.d.ts +0 -2
  82. package/dist/svelte/components/StreamSlot.svelte +0 -41
  83. package/dist/svelte/components/StreamSlot.svelte.d.ts +0 -2
  84. package/dist/types/globals.d.ts +0 -121
@@ -1,332 +0,0 @@
1
- import type {} from '../../../types/globals';
2
- /* Svelte HMR update handler */
3
-
4
- import { SVELTE_CSS_LOAD_TIMEOUT_MS } from '../constants';
5
- import {
6
- saveDOMState,
7
- restoreDOMState,
8
- saveScrollState,
9
- restoreScrollState
10
- } from '../domState';
11
- import { detectCurrentFramework, findIndexPath } from '../frameworkDetect';
12
-
13
- /* Swap a stylesheet link by matching cssBaseName or framework name */
14
- const swapStylesheet = (
15
- cssUrl: string,
16
- cssBaseName: string,
17
- framework: string
18
- ) => {
19
- let existingLink: HTMLLinkElement | null = null;
20
- document
21
- .querySelectorAll<HTMLLinkElement>('link[rel="stylesheet"]')
22
- .forEach((link) => {
23
- const href = link.getAttribute('href') ?? '';
24
- if (href.includes(cssBaseName) || href.includes(framework)) {
25
- existingLink = link;
26
- }
27
- });
28
-
29
- if (!existingLink) {
30
- return;
31
- }
32
-
33
- const capturedExisting: HTMLLinkElement = existingLink;
34
- const newLink = document.createElement('link');
35
- newLink.rel = 'stylesheet';
36
- newLink.href = `${cssUrl}?t=${Date.now()}`;
37
- newLink.onload = () => {
38
- if (capturedExisting && capturedExisting.parentNode) {
39
- capturedExisting.remove();
40
- }
41
- };
42
- document.head.appendChild(newLink);
43
- };
44
-
45
- const extractCountFromDOM = () => {
46
- const countButton = document.querySelector('button');
47
- if (!countButton || !countButton.textContent) {
48
- return {};
49
- }
50
-
51
- const countMatch = countButton.textContent.match(/(\d+)/);
52
- if (!countMatch) {
53
- return {};
54
- }
55
-
56
- return { initialCount: parseInt(countMatch[1] ?? '0', 10) };
57
- };
58
-
59
- const loadStateFromSession = () => {
60
- try {
61
- const stored = sessionStorage.getItem('__SVELTE_HMR_STATE__');
62
- if (!stored) {
63
- return {};
64
- }
65
-
66
- const parsed: Record<string, unknown> = JSON.parse(stored);
67
- if (parsed && Object.keys(parsed).length > 0) {
68
- return parsed;
69
- }
70
-
71
- return {};
72
- } catch {
73
- return {};
74
- }
75
- };
76
-
77
- const saveStateToSession = (preservedState: Record<string, unknown>) => {
78
- if (Object.keys(preservedState).length === 0) {
79
- return;
80
- }
81
-
82
- try {
83
- sessionStorage.setItem(
84
- '__SVELTE_HMR_STATE__',
85
- JSON.stringify(preservedState)
86
- );
87
- } catch {
88
- /* ignore */
89
- }
90
- };
91
-
92
- const collectCssRules = (sheet: CSSStyleSheet) => {
93
- let rules = '';
94
- for (let idx = 0; idx < sheet.cssRules.length; idx++) {
95
- const rule = sheet.cssRules[idx];
96
- if (!rule) continue;
97
- rules += `${rule.cssText}\n`;
98
- }
99
-
100
- return rules;
101
- };
102
-
103
- const preserveLinkAsInlineStyle = (link: HTMLLinkElement) => {
104
- try {
105
- const { sheet } = link;
106
- if (!sheet || sheet.cssRules.length === 0) {
107
- return null;
108
- }
109
-
110
- const style = document.createElement('style');
111
- style.dataset.hmrPreserved = 'true';
112
- style.textContent = collectCssRules(sheet);
113
- document.head.appendChild(style);
114
-
115
- return style;
116
- } catch {
117
- /* Cross-origin sheets (e.g. Google Fonts) — clone as fallback */
118
- const clone = document.createElement('link');
119
- clone.rel = link.rel;
120
- clone.href = link.href;
121
- clone.dataset.hmrPreserved = 'true';
122
- document.head.appendChild(clone);
123
-
124
- return null;
125
- }
126
- };
127
-
128
- const preserveAllStylesheets = () => {
129
- const preservedStyles: HTMLStyleElement[] = [];
130
- document
131
- .querySelectorAll<HTMLLinkElement>('head link[rel="stylesheet"]')
132
- .forEach((link) => {
133
- const style = preserveLinkAsInlineStyle(link);
134
- if (style) {
135
- preservedStyles.push(style);
136
- }
137
- });
138
-
139
- /* Also preserve Svelte injected <style> tags (css: 'injected' mode) */
140
- document
141
- .querySelectorAll<HTMLStyleElement>(
142
- 'head style:not([data-hmr-preserved])'
143
- )
144
- .forEach((style) => {
145
- const clone = document.createElement('style');
146
- clone.dataset.hmrPreserved = 'true';
147
- clone.textContent = style.textContent;
148
- document.head.appendChild(clone);
149
- });
150
-
151
- return preservedStyles;
152
- };
153
-
154
- const buildLinkLoadPromise = (link: HTMLLinkElement) => {
155
- if (link.sheet && link.sheet.cssRules.length > 0) {
156
- return null;
157
- }
158
-
159
- // eslint-disable-next-line promise/avoid-new -- wrapping DOM event callbacks requires a new Promise
160
- return new Promise<void>((resolve) => {
161
- link.onload = () => {
162
- resolve();
163
- };
164
- link.onerror = () => {
165
- resolve();
166
- };
167
- setTimeout(resolve, SVELTE_CSS_LOAD_TIMEOUT_MS);
168
- });
169
- };
170
-
171
- const cleanupAfterImport = (
172
- domState: ReturnType<typeof saveDOMState>,
173
- scrollState: ReturnType<typeof saveScrollState>
174
- ) => {
175
- document
176
- .querySelectorAll('[data-hmr-preserved="true"]')
177
- .forEach((element) => {
178
- element.remove();
179
- });
180
- restoreDOMState(document.body, domState);
181
- restoreScrollState(scrollState);
182
- };
183
-
184
- const waitForStylesAndCleanup = (
185
- domState: ReturnType<typeof saveDOMState>,
186
- scrollState: ReturnType<typeof saveScrollState>
187
- ) => {
188
- const newLinks = document.querySelectorAll<HTMLLinkElement>(
189
- 'head link[rel="stylesheet"]:not([data-hmr-preserved])'
190
- );
191
- const loadPromises: Promise<void>[] = [];
192
- newLinks.forEach((link) => {
193
- const promise = buildLinkLoadPromise(link);
194
- if (promise) {
195
- loadPromises.push(promise);
196
- }
197
- });
198
-
199
- const cleanup = () => {
200
- cleanupAfterImport(domState, scrollState);
201
- };
202
-
203
- if (loadPromises.length > 0) {
204
- void Promise.all(loadPromises).then(cleanup);
205
- } else {
206
- cleanup();
207
- }
208
- };
209
-
210
- export const handleSvelteUpdate = (message: {
211
- data: {
212
- cssBaseName?: string;
213
- cssUrl?: string;
214
- html?: string;
215
- manifest?: Record<string, string>;
216
- pageModuleUrl?: string;
217
- serverDuration?: number;
218
- sourceFile?: string;
219
- updateType?: string;
220
- };
221
- }) => {
222
- const svelteFrameworkCheck = detectCurrentFramework();
223
- if (svelteFrameworkCheck !== 'svelte') return;
224
-
225
- /* CSS-only update: hot-swap stylesheet, no remount needed */
226
- if (message.data.updateType === 'css-only' && message.data.cssUrl) {
227
- swapStylesheet(
228
- message.data.cssUrl,
229
- message.data.cssBaseName || '',
230
- 'svelte'
231
- );
232
-
233
- return;
234
- }
235
-
236
- /* Component update: preserve state, re-import (bootstrap handles unmount + mount) */
237
-
238
- /* Save DOM state and scroll position */
239
- const domState = saveDOMState(document.body);
240
- const scrollState = saveScrollState();
241
-
242
- let preservedState: Record<string, unknown> = extractCountFromDOM();
243
-
244
- if (Object.keys(preservedState).length === 0) {
245
- preservedState = loadStateFromSession();
246
- }
247
-
248
- /* Set preserved state on window + backup to sessionStorage */
249
- window.__HMR_PRESERVED_STATE__ = preservedState;
250
- saveStateToSession(preservedState);
251
-
252
- /* CSS pre-update: swap stylesheet BEFORE importing to prevent FOUC */
253
- if (message.data.cssUrl) {
254
- swapStylesheet(
255
- message.data.cssUrl,
256
- message.data.cssBaseName || '',
257
- 'svelte'
258
- );
259
- }
260
-
261
- // O(1) Svelte 5 HMR: import the changed module, then call its
262
- // accept callback. Svelte's $.hmr() reactive wrapper swaps the
263
- // component in place — parent state and DOM survive untouched.
264
- const { pageModuleUrl } = message.data;
265
- if (pageModuleUrl) {
266
- const clientStart = performance.now();
267
- const modulePath = `${pageModuleUrl}?t=${Date.now()}`;
268
-
269
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions, @typescript-eslint/no-explicit-any
270
- const acceptRegistry = (window as any).__SVELTE_HMR_ACCEPT__ as
271
- | Record<string, (mod: unknown) => void>
272
- | undefined;
273
-
274
- // Save the OLD module's accept callback BEFORE importing.
275
- const acceptFn = acceptRegistry?.[pageModuleUrl];
276
-
277
- import(modulePath)
278
- .then((newModule) => {
279
- if (acceptFn) {
280
- acceptFn(newModule);
281
- }
282
-
283
- if (
284
- window.__HMR_WS__ &&
285
- message.data.serverDuration !== undefined
286
- ) {
287
- const clientMs = Math.round(
288
- performance.now() - clientStart
289
- );
290
- const total = (message.data.serverDuration ?? 0) + clientMs;
291
- window.__HMR_WS__.send(
292
- JSON.stringify({ duration: total, type: 'hmr-timing' })
293
- );
294
- }
295
-
296
- return undefined;
297
- })
298
- .catch((err: unknown) => {
299
- console.warn('[HMR] Svelte HMR failed, reloading:', err);
300
- window.location.reload();
301
- });
302
-
303
- return;
304
- }
305
-
306
- // Bundled fallback: re-import the index file
307
- const indexPath = findIndexPath(
308
- message.data.manifest,
309
- message.data.sourceFile,
310
- 'svelte'
311
- );
312
- if (!indexPath) {
313
- console.warn('[HMR] Svelte index path not found, reloading');
314
- window.location.reload();
315
-
316
- return;
317
- }
318
-
319
- preserveAllStylesheets();
320
-
321
- const modulePath = `${indexPath}?t=${Date.now()}`;
322
- import(modulePath)
323
- .then(() => {
324
- waitForStylesAndCleanup(domState, scrollState);
325
-
326
- return undefined;
327
- })
328
- .catch((err: unknown) => {
329
- console.warn('[HMR] Svelte import failed, reloading:', err);
330
- window.location.reload();
331
- });
332
- };
@@ -1,292 +0,0 @@
1
- import type {} from '../../../types/globals';
2
- /* Vue HMR update handler */
3
-
4
- import type { VueComponentInstance, VueVNode } from '../../../types/vue';
5
- import { saveDOMState, restoreDOMState } from '../domState';
6
- import { detectCurrentFramework, findIndexPath } from '../frameworkDetect';
7
-
8
- /* Collect reactive value from a setup state entry into the target record */
9
- const collectSetupValue = (
10
- target: Record<string, unknown>,
11
- key: string,
12
- value: unknown
13
- ) => {
14
- if (value && typeof value === 'object' && 'value' in value) {
15
- target[key] = value.value;
16
-
17
- return;
18
- }
19
-
20
- if (typeof value !== 'function') {
21
- target[key] = value;
22
- }
23
- };
24
-
25
- /* Copy all setup state entries from a record into the target */
26
- const collectSetupState = (
27
- target: Record<string, unknown>,
28
- setupState: Record<string, unknown>
29
- ) => {
30
- const keys = Object.keys(setupState);
31
- for (let idx = 0; idx < keys.length; idx++) {
32
- const key = keys[idx];
33
- if (key === undefined) continue;
34
- collectSetupValue(target, key, setupState[key]);
35
- }
36
- };
37
-
38
- /* Walk a VNode tree and collect setup state from all child components */
39
- const walkVNode = (
40
- vnode: VueVNode | undefined,
41
- state: Record<string, unknown>
42
- ) => {
43
- if (!vnode) return;
44
-
45
- if (vnode.component && vnode.component.setupState) {
46
- collectSetupState(state, vnode.component.setupState);
47
- }
48
-
49
- if (vnode.children && Array.isArray(vnode.children)) {
50
- vnode.children.forEach((child) => {
51
- walkVNode(child, state);
52
- });
53
- }
54
-
55
- if (vnode.component && vnode.component.subTree) {
56
- walkVNode(vnode.component.subTree, state);
57
- }
58
- };
59
-
60
- /* Extract state from child Vue component instances recursively */
61
- const extractChildComponentState = (
62
- instance: VueComponentInstance,
63
- state: Record<string, unknown>
64
- ) => {
65
- if (!instance || !instance.subTree) return;
66
-
67
- walkVNode(instance.subTree, state);
68
- };
69
-
70
- /* Find an existing stylesheet link matching the given base name */
71
- const findMatchingStylesheetLink = (cssBaseName: string) => {
72
- let found: HTMLLinkElement | null = null;
73
- document
74
- .querySelectorAll<HTMLLinkElement>('link[rel="stylesheet"]')
75
- .forEach((link) => {
76
- const href = link.getAttribute('href') ?? '';
77
- if (cssBaseName && href.includes(cssBaseName)) {
78
- found = link;
79
- }
80
- });
81
-
82
- return found;
83
- };
84
-
85
- /* Swap a stylesheet link with a new one, removing the old on load */
86
- const swapStylesheet = (cssUrl: string, cssBaseName: string) => {
87
- const existingLink = findMatchingStylesheetLink(cssBaseName);
88
- if (!existingLink) return;
89
-
90
- const capturedExisting: HTMLLinkElement = existingLink;
91
- const newLink = document.createElement('link');
92
- newLink.rel = 'stylesheet';
93
- newLink.href = `${cssUrl}?t=${Date.now()}`;
94
- newLink.onload = function () {
95
- if (capturedExisting && capturedExisting.parentNode) {
96
- capturedExisting.remove();
97
- }
98
- };
99
- document.head.appendChild(newLink);
100
- };
101
-
102
- /* Extract Vue reactive state from app instance */
103
- const extractVueAppState = (vuePreservedState: Record<string, unknown>) => {
104
- if (!window.__VUE_APP__ || !window.__VUE_APP__._instance) return;
105
-
106
- const instance = window.__VUE_APP__._instance;
107
-
108
- if (instance.setupState) {
109
- collectSetupState(vuePreservedState, instance.setupState);
110
- }
111
-
112
- extractChildComponentState(instance, vuePreservedState);
113
- };
114
-
115
- /* DOM fallback: extract count from button text when app instance is unavailable */
116
- const extractCountFromDOM = (vuePreservedState: Record<string, unknown>) => {
117
- if (Object.keys(vuePreservedState).length > 0) return;
118
-
119
- const countButton = document.querySelector('button');
120
- if (!countButton || !countButton.textContent) return;
121
-
122
- const countMatch = countButton.textContent.match(/count is (\d+)/i);
123
- if (!countMatch) return;
124
-
125
- vuePreservedState.initialCount = parseInt(countMatch[1] ?? '0', 10);
126
- };
127
-
128
- /* Handle completion of Vue module reimport */
129
- const handleVueImportSuccess = (
130
- vueRoot: HTMLElement | null,
131
- vueDomState: ReturnType<typeof saveDOMState> | null
132
- ) => {
133
- if (vueRoot && vueDomState) {
134
- restoreDOMState(vueRoot, vueDomState);
135
- }
136
- sessionStorage.removeItem('__HMR_ACTIVE__');
137
- };
138
-
139
- /* Force-reload a Vue component via HMR runtime when setup() must re-run */
140
- const forceReloadVueComponent = (mod: Record<string, unknown>) => {
141
- const hmrRuntime = window.__VUE_HMR_RUNTIME__;
142
- if (!hmrRuntime) return;
143
-
144
- const component = mod?.default ?? Object.values(mod ?? {})[0];
145
- if (!component || typeof component !== 'object') return;
146
- if (!('__hmrId' in component)) return;
147
-
148
- const { __hmrId: hmrId } = component;
149
- if (typeof hmrId === 'string') {
150
- hmrRuntime.reload(hmrId, component);
151
- }
152
- };
153
-
154
- export const handleVueUpdate = (message: {
155
- data: {
156
- cssBaseName?: string;
157
- cssUrl?: string;
158
- forceReload?: boolean;
159
- html?: string;
160
- manifest?: Record<string, string>;
161
- pageModuleUrl?: string;
162
- serverDuration?: number;
163
- sourceFile?: string;
164
- updateType?: string;
165
- };
166
- }) => {
167
- const vueFrameworkCheck = detectCurrentFramework();
168
- if (vueFrameworkCheck !== 'vue') return;
169
-
170
- if (message.data.updateType === 'css-only' && message.data.cssUrl) {
171
- swapStylesheet(message.data.cssUrl, message.data.cssBaseName || '');
172
-
173
- return;
174
- }
175
-
176
- sessionStorage.setItem('__HMR_ACTIVE__', 'true');
177
-
178
- const vueRoot = document.getElementById('root');
179
- const vueDomState = vueRoot ? saveDOMState(vueRoot) : null;
180
-
181
- /* Extract Vue reactive state from app instance (not DOM) */
182
- const vuePreservedState: Record<string, unknown> = {};
183
-
184
- extractVueAppState(vuePreservedState);
185
-
186
- /* DOM fallback if app instance not available */
187
- extractCountFromDOM(vuePreservedState);
188
-
189
- /* Map count -> initialCount for prop-based state (used by CountButton) */
190
- if (
191
- vuePreservedState.count !== undefined &&
192
- vuePreservedState.initialCount === undefined
193
- ) {
194
- vuePreservedState.initialCount = vuePreservedState.count;
195
- }
196
-
197
- /* Backup to sessionStorage for resilience */
198
- try {
199
- sessionStorage.setItem(
200
- '__VUE_HMR_STATE__',
201
- JSON.stringify(vuePreservedState)
202
- );
203
- } catch {
204
- /* ignore */
205
- }
206
-
207
- window.__HMR_PRESERVED_STATE__ = vuePreservedState;
208
-
209
- // O(1) Vue HMR: import the changed module directly.
210
- // __VUE_HMR_RUNTIME__.reload() inside the module hot-swaps the
211
- // component in place — same pattern as React Fast Refresh.
212
- const { pageModuleUrl } = message.data;
213
- if (pageModuleUrl) {
214
- const clientStart = performance.now();
215
- const modulePath = `${pageModuleUrl}?t=${Date.now()}`;
216
-
217
- import(modulePath)
218
- .then((mod) => {
219
- // When a composable/utility file changed (not the .vue file itself),
220
- // force reload via __VUE_HMR_RUNTIME__ so setup() re-runs.
221
- // Vue's rerender only swaps the template, not the setup closure.
222
- if (message.data.forceReload) {
223
- forceReloadVueComponent(mod);
224
- }
225
- sessionStorage.removeItem('__HMR_ACTIVE__');
226
-
227
- if (
228
- window.__HMR_WS__ &&
229
- message.data.serverDuration !== undefined
230
- ) {
231
- const clientMs = Math.round(
232
- performance.now() - clientStart
233
- );
234
- const total = (message.data.serverDuration ?? 0) + clientMs;
235
- window.__HMR_WS__.send(
236
- JSON.stringify({ duration: total, type: 'hmr-timing' })
237
- );
238
- }
239
-
240
- return undefined;
241
- })
242
- .catch((err: unknown) => {
243
- console.warn('[HMR] Vue HMR failed, reloading:', err);
244
- sessionStorage.removeItem('__HMR_ACTIVE__');
245
- window.location.reload();
246
- });
247
-
248
- return;
249
- }
250
-
251
- /* CSS pre-update: swap stylesheet BEFORE unmounting to prevent FOUC */
252
- if (message.data.cssUrl) {
253
- swapStylesheet(message.data.cssUrl, message.data.cssBaseName || '');
254
- }
255
-
256
- /* Unmount old Vue app but keep DOM visually intact during async import.
257
- unmount() clears the container — snapshot and restore synchronously. */
258
- const savedHTML = vueRoot ? vueRoot.innerHTML : '';
259
- if (window.__VUE_APP__) {
260
- window.__VUE_APP__.unmount();
261
- window.__VUE_APP__ = null;
262
- }
263
- if (vueRoot) {
264
- vueRoot.innerHTML = savedHTML;
265
- }
266
-
267
- // Bundled fallback: re-import the index file
268
- const indexPath = findIndexPath(
269
- message.data.manifest,
270
- message.data.sourceFile,
271
- 'vue'
272
- );
273
- if (!indexPath) {
274
- console.warn('[HMR] Vue index path not found, reloading');
275
- window.location.reload();
276
-
277
- return;
278
- }
279
-
280
- const modulePath = `${indexPath}?t=${Date.now()}`;
281
- import(modulePath)
282
- .then(() => {
283
- handleVueImportSuccess(vueRoot, vueDomState);
284
-
285
- return undefined;
286
- })
287
- .catch((err: unknown) => {
288
- console.warn('[HMR] Vue import failed:', err);
289
- sessionStorage.removeItem('__HMR_ACTIVE__');
290
- window.location.reload();
291
- });
292
- };