@absolutejs/absolute 0.14.0 → 0.15.1
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/.claude/settings.local.json +11 -0
- package/CLAUDE.md +11 -2
- package/LICENSE +74 -18
- package/README.md +4 -4
- package/THIRD_PARTY_NOTICES.md +61 -0
- package/dist/cli/index.js +24 -8
- package/dist/dev/client/cssUtils.ts +288 -0
- package/dist/dev/client/domDiff.ts +261 -0
- package/dist/dev/client/domState.ts +271 -0
- package/dist/dev/client/errorOverlay.ts +145 -0
- package/dist/dev/client/frameworkDetect.ts +63 -0
- package/dist/dev/client/handlers/html.ts +415 -0
- package/dist/dev/client/handlers/htmx.ts +248 -0
- package/dist/dev/client/handlers/react.ts +80 -0
- package/dist/dev/client/handlers/rebuild.ts +147 -0
- package/dist/dev/client/handlers/svelte.ts +129 -0
- package/dist/dev/client/handlers/vue.ts +254 -0
- package/dist/dev/client/headPatch.ts +213 -0
- package/dist/dev/client/hmrClient.ts +204 -0
- package/dist/dev/client/moduleVersions.ts +57 -0
- package/dist/dev/client/reactRefreshSetup.ts +21 -0
- package/dist/index.js +3028 -478
- package/dist/index.js.map +49 -19
- package/dist/{build → src/build}/compileSvelte.d.ts +2 -1
- package/dist/src/build/compileVue.d.ts +33 -0
- package/dist/src/build/generateReactIndexes.d.ts +1 -0
- package/dist/src/build/htmlScriptHMRPlugin.d.ts +13 -0
- package/dist/src/build/wrapHTMLScript.d.ts +24 -0
- package/dist/{core → src/core}/build.d.ts +2 -2
- package/dist/src/core/devBuild.d.ts +6 -0
- package/dist/{core → src/core}/index.d.ts +2 -1
- package/dist/src/core/lookup.d.ts +3 -0
- package/dist/{core → src/core}/pageHandlers.d.ts +4 -4
- package/dist/src/dev/assetStore.d.ts +12 -0
- package/dist/src/dev/buildHMRClient.d.ts +1 -0
- package/dist/src/dev/clientManager.d.ts +26 -0
- package/dist/src/dev/configResolver.d.ts +13 -0
- package/dist/src/dev/dependencyGraph.d.ts +13 -0
- package/dist/src/dev/fileHashTracker.d.ts +2 -0
- package/dist/src/dev/fileWatcher.d.ts +3 -0
- package/dist/src/dev/moduleMapper.d.ts +21 -0
- package/dist/src/dev/moduleVersionTracker.d.ts +7 -0
- package/dist/src/dev/pathUtils.d.ts +5 -0
- package/dist/src/dev/reactComponentClassifier.d.ts +2 -0
- package/dist/src/dev/rebuildTrigger.d.ts +10 -0
- package/dist/src/dev/simpleHTMLHMR.d.ts +4 -0
- package/dist/src/dev/simpleHTMXHMR.d.ts +4 -0
- package/dist/src/dev/simpleSvelteHMR.d.ts +1 -0
- package/dist/src/dev/simpleVueHMR.d.ts +1 -0
- package/dist/src/dev/webSocket.d.ts +9 -0
- package/dist/{index.d.ts → src/index.d.ts} +1 -0
- package/dist/src/plugins/hmr.d.ts +62 -0
- package/dist/{plugins → src/plugins}/index.d.ts +2 -1
- package/dist/{svelte → src/svelte}/renderToReadableStream.d.ts +3 -1
- package/dist/src/utils/getRegisterClientScript.d.ts +10 -0
- package/dist/{utils → src/utils}/index.d.ts +2 -0
- package/dist/src/utils/logger.d.ts +45 -0
- package/dist/src/utils/networking.d.ts +2 -0
- package/dist/src/utils/normalizePath.d.ts +9 -0
- package/dist/src/utils/registerClientScript.d.ts +51 -0
- package/dist/{types.d.ts → types/build.d.ts} +6 -0
- package/dist/types/client.d.ts +104 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/messages.d.ts +138 -0
- package/dist/types/websocket.d.ts +6 -0
- package/eslint.config.mjs +5 -1
- package/package.json +19 -14
- package/tsconfig.build.json +1 -1
- package/types/build.ts +46 -0
- package/types/client.ts +109 -0
- package/types/index.ts +4 -0
- package/types/messages.ts +205 -0
- package/types/websocket.ts +12 -0
- package/types/window-globals.ts +53 -0
- package/dist/build/compileVue.d.ts +0 -5
- package/dist/build/generateReactIndexes.d.ts +0 -1
- package/dist/core/lookup.d.ts +0 -1
- package/dist/utils/networking.d.ts +0 -1
- /package/dist/{build → src/build}/generateManifest.d.ts +0 -0
- /package/dist/{build → src/build}/outputLogs.d.ts +0 -0
- /package/dist/{build → src/build}/scanEntryPoints.d.ts +0 -0
- /package/dist/{build → src/build}/updateAssetPaths.d.ts +0 -0
- /package/dist/{cli → src/cli}/index.d.ts +0 -0
- /package/dist/{constants.d.ts → src/constants.d.ts} +0 -0
- /package/dist/{plugins → src/plugins}/networking.d.ts +0 -0
- /package/dist/{plugins → src/plugins}/pageRouter.d.ts +0 -0
- /package/dist/{svelte → src/svelte}/renderToPipeableStream.d.ts +0 -0
- /package/dist/{svelte → src/svelte}/renderToString.d.ts +0 -0
- /package/dist/{utils → src/utils}/cleanup.d.ts +0 -0
- /package/dist/{utils → src/utils}/commonAncestor.d.ts +0 -0
- /package/dist/{utils → src/utils}/escapeScriptContent.d.ts +0 -0
- /package/dist/{utils → src/utils}/generateHeadElement.d.ts +0 -0
- /package/dist/{utils → src/utils}/getDurationString.d.ts +0 -0
- /package/dist/{utils → src/utils}/getEnv.d.ts +0 -0
- /package/dist/{utils → src/utils}/stringModifiers.d.ts +0 -0
- /package/dist/{utils → src/utils}/validateSafePath.d.ts +0 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/* Framework detection and manifest lookup utilities */
|
|
2
|
+
|
|
3
|
+
export const detectCurrentFramework = () => {
|
|
4
|
+
if (window.__HMR_FRAMEWORK__) return window.__HMR_FRAMEWORK__;
|
|
5
|
+
const path = window.location.pathname;
|
|
6
|
+
if (path === '/vue' || path.startsWith('/vue/')) return 'vue';
|
|
7
|
+
if (path === '/svelte' || path.startsWith('/svelte/')) return 'svelte';
|
|
8
|
+
if (path === '/htmx' || path.startsWith('/htmx/')) return 'htmx';
|
|
9
|
+
if (path === '/html' || path.startsWith('/html/')) return 'html';
|
|
10
|
+
if (path === '/') return 'html';
|
|
11
|
+
if (path === '/react' || path.startsWith('/react/')) return 'react';
|
|
12
|
+
if (window.__REACT_ROOT__) return 'react';
|
|
13
|
+
return null;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const getComponentNameFromPath = (filePath: string) => {
|
|
17
|
+
if (!filePath) return null;
|
|
18
|
+
const parts = filePath.replace(/\\/g, '/').split('/');
|
|
19
|
+
const fileName = parts[parts.length - 1] || '';
|
|
20
|
+
const baseName = fileName.replace(/\.(tsx?|jsx?|vue|svelte|html)$/, '');
|
|
21
|
+
return baseName
|
|
22
|
+
.split(/[-_]/)
|
|
23
|
+
.map(function (word) {
|
|
24
|
+
return word.charAt(0).toUpperCase() + word.slice(1);
|
|
25
|
+
})
|
|
26
|
+
.join('');
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export const findIndexPath = (
|
|
30
|
+
manifest: Record<string, string> | undefined,
|
|
31
|
+
sourceFile: string | undefined,
|
|
32
|
+
framework: string
|
|
33
|
+
) => {
|
|
34
|
+
if (!manifest) return null;
|
|
35
|
+
|
|
36
|
+
if (sourceFile) {
|
|
37
|
+
const componentName = getComponentNameFromPath(sourceFile);
|
|
38
|
+
if (componentName) {
|
|
39
|
+
const indexKey = componentName + 'Index';
|
|
40
|
+
if (manifest[indexKey]) return manifest[indexKey]!;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const frameworkPatterns: Record<string, RegExp> = {
|
|
45
|
+
react: /react/i,
|
|
46
|
+
svelte: /svelte/i,
|
|
47
|
+
vue: /vue/i
|
|
48
|
+
};
|
|
49
|
+
const pattern = frameworkPatterns[framework];
|
|
50
|
+
|
|
51
|
+
for (const key in manifest) {
|
|
52
|
+
if (
|
|
53
|
+
key.endsWith('Index') &&
|
|
54
|
+
(!pattern ||
|
|
55
|
+
pattern.test(key) ||
|
|
56
|
+
manifest[key]!.includes('/' + framework + '/'))
|
|
57
|
+
) {
|
|
58
|
+
return manifest[key]!;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return null;
|
|
63
|
+
};
|
|
@@ -0,0 +1,415 @@
|
|
|
1
|
+
/* HTML + script HMR update handlers */
|
|
2
|
+
|
|
3
|
+
import { patchDOMInPlace } from '../domDiff';
|
|
4
|
+
import {
|
|
5
|
+
saveDOMState,
|
|
6
|
+
restoreDOMState,
|
|
7
|
+
saveFormState,
|
|
8
|
+
restoreFormState,
|
|
9
|
+
saveScrollState,
|
|
10
|
+
restoreScrollState
|
|
11
|
+
} from '../domState';
|
|
12
|
+
import { processCSSLinks, waitForCSSAndUpdate } from '../cssUtils';
|
|
13
|
+
import { patchHeadInPlace } from '../headPatch';
|
|
14
|
+
import { detectCurrentFramework } from '../frameworkDetect';
|
|
15
|
+
import type { ScriptInfo } from '../../../../types/client';
|
|
16
|
+
import { hmrState } from '../../../../types/client';
|
|
17
|
+
|
|
18
|
+
export const handleScriptUpdate = (message: {
|
|
19
|
+
data: { framework?: string; scriptPath?: string };
|
|
20
|
+
}) => {
|
|
21
|
+
console.log('[HMR] Received script-update message');
|
|
22
|
+
const scriptFramework = message.data.framework;
|
|
23
|
+
const currentFw = detectCurrentFramework();
|
|
24
|
+
|
|
25
|
+
if (currentFw !== scriptFramework) {
|
|
26
|
+
console.log(
|
|
27
|
+
'[HMR] Skipping script update - different framework:',
|
|
28
|
+
currentFw,
|
|
29
|
+
'vs',
|
|
30
|
+
scriptFramework
|
|
31
|
+
);
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const scriptPath = message.data.scriptPath;
|
|
36
|
+
if (!scriptPath) {
|
|
37
|
+
console.warn('[HMR] No script path in update');
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
console.log('[HMR] Hot-reloading script:', scriptPath);
|
|
42
|
+
|
|
43
|
+
const interactiveSelectors =
|
|
44
|
+
'button, [onclick], [onchange], [oninput], details, input, select, textarea';
|
|
45
|
+
document.body.querySelectorAll(interactiveSelectors).forEach(function (el) {
|
|
46
|
+
const cloned = el.cloneNode(true);
|
|
47
|
+
if (el.parentNode) {
|
|
48
|
+
el.parentNode.replaceChild(cloned, el);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const counterSpan = document.querySelector('#counter');
|
|
53
|
+
if (counterSpan) {
|
|
54
|
+
window.__HMR_DOM_STATE__ = {
|
|
55
|
+
count: parseInt(counterSpan.textContent || '0', 10)
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const cacheBustedPath = scriptPath + '?t=' + Date.now();
|
|
60
|
+
import(/* @vite-ignore */ cacheBustedPath)
|
|
61
|
+
.then(function () {
|
|
62
|
+
console.log('[HMR] Script hot-reloaded successfully');
|
|
63
|
+
})
|
|
64
|
+
.catch(function (err: unknown) {
|
|
65
|
+
console.error(
|
|
66
|
+
'[HMR] Script hot-reload failed, falling back to page reload:',
|
|
67
|
+
err
|
|
68
|
+
);
|
|
69
|
+
window.location.reload();
|
|
70
|
+
});
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export const handleHTMLUpdate = (message: {
|
|
74
|
+
data: {
|
|
75
|
+
html?: string | { body?: string; head?: string } | null;
|
|
76
|
+
};
|
|
77
|
+
}) => {
|
|
78
|
+
console.log('[HMR] Received html-update message');
|
|
79
|
+
const htmlFrameworkCheck = detectCurrentFramework();
|
|
80
|
+
console.log('[HMR] Current framework:', htmlFrameworkCheck);
|
|
81
|
+
if (htmlFrameworkCheck !== 'html') {
|
|
82
|
+
console.log('[HMR] Skipping - not on HTML page');
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (window.__REACT_ROOT__) {
|
|
87
|
+
window.__REACT_ROOT__ = undefined;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
sessionStorage.setItem('__HMR_ACTIVE__', 'true');
|
|
91
|
+
|
|
92
|
+
const htmlDomState = saveDOMState(document.body);
|
|
93
|
+
|
|
94
|
+
let htmlBody: string | null = null;
|
|
95
|
+
let htmlHead: string | null = null;
|
|
96
|
+
if (typeof message.data.html === 'string') {
|
|
97
|
+
htmlBody = message.data.html;
|
|
98
|
+
} else if (message.data.html && typeof message.data.html === 'object') {
|
|
99
|
+
htmlBody = message.data.html.body || null;
|
|
100
|
+
htmlHead = message.data.html.head || null;
|
|
101
|
+
}
|
|
102
|
+
console.log('[HMR] htmlBody length:', htmlBody ? htmlBody.length : 'null');
|
|
103
|
+
console.log('[HMR] htmlHead:', htmlHead ? 'present' : 'null');
|
|
104
|
+
|
|
105
|
+
if (htmlBody) {
|
|
106
|
+
console.log('[HMR] Processing htmlBody');
|
|
107
|
+
if (htmlHead) {
|
|
108
|
+
console.log('[HMR] Has htmlHead, patching head elements');
|
|
109
|
+
|
|
110
|
+
const doPatchHead = function () {
|
|
111
|
+
patchHeadInPlace(htmlHead!);
|
|
112
|
+
};
|
|
113
|
+
if (hmrState.isFirstHMRUpdate) {
|
|
114
|
+
console.log(
|
|
115
|
+
'[HMR] First update - adding head patch stabilization delay'
|
|
116
|
+
);
|
|
117
|
+
setTimeout(doPatchHead, 50);
|
|
118
|
+
} else {
|
|
119
|
+
doPatchHead();
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
console.log('[HMR] Processing CSS links');
|
|
123
|
+
const cssResult = processCSSLinks(htmlHead);
|
|
124
|
+
|
|
125
|
+
const updateBodyAfterCSS = function () {
|
|
126
|
+
updateHTMLBody(htmlBody!, htmlDomState, document.body);
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
console.log(
|
|
130
|
+
'[HMR] linksToWaitFor count:',
|
|
131
|
+
cssResult.linksToWaitFor.length
|
|
132
|
+
);
|
|
133
|
+
waitForCSSAndUpdate(cssResult, updateBodyAfterCSS);
|
|
134
|
+
} else {
|
|
135
|
+
console.log('[HMR] No htmlHead, patching body directly');
|
|
136
|
+
const container = document.body;
|
|
137
|
+
if (container) {
|
|
138
|
+
updateHTMLBodyDirect(htmlBody, htmlDomState, container);
|
|
139
|
+
restoreDOMState(container, htmlDomState);
|
|
140
|
+
} else {
|
|
141
|
+
sessionStorage.removeItem('__HMR_ACTIVE__');
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
} else {
|
|
145
|
+
sessionStorage.removeItem('__HMR_ACTIVE__');
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
const updateHTMLBody = (
|
|
150
|
+
htmlBody: string,
|
|
151
|
+
htmlDomState: ReturnType<typeof saveDOMState>,
|
|
152
|
+
container: HTMLElement
|
|
153
|
+
) => {
|
|
154
|
+
console.log('[HMR] updateBodyAfterCSS called');
|
|
155
|
+
if (!container) {
|
|
156
|
+
console.log('[HMR] ERROR: document.body not found');
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const counterSpan = container.querySelector('#counter');
|
|
161
|
+
const counterValue = counterSpan
|
|
162
|
+
? parseInt(counterSpan.textContent || '0', 10)
|
|
163
|
+
: 0;
|
|
164
|
+
|
|
165
|
+
const savedState = {
|
|
166
|
+
componentState: { count: counterValue },
|
|
167
|
+
forms: saveFormState(),
|
|
168
|
+
scroll: saveScrollState()
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
let body = htmlBody;
|
|
172
|
+
if (counterValue > 0) {
|
|
173
|
+
body = body.replace(
|
|
174
|
+
new RegExp('<span id="counter">0<' + '/span>', 'g'),
|
|
175
|
+
'<span id="counter">' + counterValue + '<' + '/span>'
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const existingScripts = collectScripts(container);
|
|
180
|
+
const hmrScript = container.querySelector('script[data-hmr-client]');
|
|
181
|
+
const tempDiv = document.createElement('div');
|
|
182
|
+
tempDiv.innerHTML = body;
|
|
183
|
+
const newScripts = collectScriptsFromElement(tempDiv);
|
|
184
|
+
|
|
185
|
+
const scriptsChanged = didScriptsChange(existingScripts, newScripts);
|
|
186
|
+
const htmlStructureChanged = didHTMLStructureChange(container, tempDiv);
|
|
187
|
+
|
|
188
|
+
if (!htmlStructureChanged && !scriptsChanged) {
|
|
189
|
+
console.log('[HMR] CSS-only change detected - skipping body patch');
|
|
190
|
+
} else {
|
|
191
|
+
patchDOMInPlace(container, body);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (hmrScript && !container.querySelector('script[data-hmr-client]')) {
|
|
195
|
+
container.appendChild(hmrScript);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
requestAnimationFrame(function () {
|
|
199
|
+
restoreFormState(savedState.forms);
|
|
200
|
+
restoreScrollState(savedState.scroll);
|
|
201
|
+
|
|
202
|
+
const newCounterSpan = container.querySelector('#counter');
|
|
203
|
+
if (newCounterSpan && savedState.componentState.count !== undefined) {
|
|
204
|
+
newCounterSpan.textContent = String(
|
|
205
|
+
savedState.componentState.count
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if (scriptsChanged || htmlStructureChanged) {
|
|
210
|
+
cloneInteractiveElements(container);
|
|
211
|
+
window.__HMR_DOM_STATE__ = {
|
|
212
|
+
count: savedState.componentState.count || 0
|
|
213
|
+
};
|
|
214
|
+
reExecuteScripts(container, newScripts);
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
sessionStorage.removeItem('__HMR_ACTIVE__');
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
const updateHTMLBodyDirect = (
|
|
221
|
+
htmlBody: string,
|
|
222
|
+
htmlDomState: ReturnType<typeof saveDOMState>,
|
|
223
|
+
container: HTMLElement
|
|
224
|
+
) => {
|
|
225
|
+
const counterSpan = container.querySelector('#counter');
|
|
226
|
+
const counterValue = counterSpan
|
|
227
|
+
? parseInt(counterSpan.textContent || '0', 10)
|
|
228
|
+
: 0;
|
|
229
|
+
|
|
230
|
+
const savedState = {
|
|
231
|
+
componentState: { count: counterValue },
|
|
232
|
+
forms: saveFormState(),
|
|
233
|
+
scroll: saveScrollState()
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
let body = htmlBody;
|
|
237
|
+
if (counterValue > 0) {
|
|
238
|
+
body = body.replace(
|
|
239
|
+
new RegExp('<span id="counter">0<' + '/span>', 'g'),
|
|
240
|
+
'<span id="counter">' + counterValue + '<' + '/span>'
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const existingScripts = collectScripts(container);
|
|
245
|
+
const tempDiv = document.createElement('div');
|
|
246
|
+
tempDiv.innerHTML = body;
|
|
247
|
+
const newScripts = collectScriptsFromElement(tempDiv);
|
|
248
|
+
const scriptsChanged = didScriptsChange(existingScripts, newScripts);
|
|
249
|
+
const hmrScript = container.querySelector('script[data-hmr-client]');
|
|
250
|
+
|
|
251
|
+
patchDOMInPlace(container, body);
|
|
252
|
+
|
|
253
|
+
if (hmrScript && !container.querySelector('script[data-hmr-client]')) {
|
|
254
|
+
container.appendChild(hmrScript);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
requestAnimationFrame(function () {
|
|
258
|
+
restoreFormState(savedState.forms);
|
|
259
|
+
restoreScrollState(savedState.scroll);
|
|
260
|
+
|
|
261
|
+
const newCounterSpan = container.querySelector('#counter');
|
|
262
|
+
if (newCounterSpan && savedState.componentState.count !== undefined) {
|
|
263
|
+
newCounterSpan.textContent = String(
|
|
264
|
+
savedState.componentState.count
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
container
|
|
269
|
+
.querySelectorAll('[data-hmr-listeners-attached]')
|
|
270
|
+
.forEach(function (el) {
|
|
271
|
+
const cloned = el.cloneNode(true) as Element;
|
|
272
|
+
if (el.parentNode) {
|
|
273
|
+
el.parentNode.replaceChild(cloned, el);
|
|
274
|
+
}
|
|
275
|
+
cloned.removeAttribute('data-hmr-listeners-attached');
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
removeOldScripts(container);
|
|
279
|
+
newScripts.forEach(function (scriptInfo) {
|
|
280
|
+
const newScript = document.createElement('script');
|
|
281
|
+
const separator = scriptInfo.src.includes('?') ? '&' : '?';
|
|
282
|
+
newScript.src = scriptInfo.src + separator + 't=' + Date.now();
|
|
283
|
+
newScript.type = scriptInfo.type;
|
|
284
|
+
container.appendChild(newScript);
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
const inlineScripts = container.querySelectorAll('script:not([src])');
|
|
288
|
+
inlineScripts.forEach(function (script) {
|
|
289
|
+
if (!(script as Element).hasAttribute('data-hmr-client')) {
|
|
290
|
+
const newScript = document.createElement('script');
|
|
291
|
+
newScript.textContent = script.textContent || '';
|
|
292
|
+
newScript.type =
|
|
293
|
+
(script as HTMLScriptElement).type || 'text/javascript';
|
|
294
|
+
if (script.parentNode) {
|
|
295
|
+
script.parentNode.replaceChild(newScript, script);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
});
|
|
300
|
+
sessionStorage.removeItem('__HMR_ACTIVE__');
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
/* Shared helpers for HTML body updates */
|
|
304
|
+
|
|
305
|
+
const collectScripts = (container: HTMLElement) => {
|
|
306
|
+
return Array.from(container.querySelectorAll('script[src]')).map(
|
|
307
|
+
function (script) {
|
|
308
|
+
return {
|
|
309
|
+
src: script.getAttribute('src') || '',
|
|
310
|
+
type: script.getAttribute('type') || 'text/javascript'
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
);
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
const collectScriptsFromElement = (el: HTMLElement) => {
|
|
317
|
+
return Array.from(el.querySelectorAll('script[src]')).map(
|
|
318
|
+
function (script) {
|
|
319
|
+
return {
|
|
320
|
+
src: script.getAttribute('src') || '',
|
|
321
|
+
type: script.getAttribute('type') || 'text/javascript'
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
);
|
|
325
|
+
};
|
|
326
|
+
|
|
327
|
+
const didScriptsChange = (
|
|
328
|
+
oldScripts: ScriptInfo[],
|
|
329
|
+
newScripts: ScriptInfo[]
|
|
330
|
+
) => {
|
|
331
|
+
return (
|
|
332
|
+
oldScripts.length !== newScripts.length ||
|
|
333
|
+
oldScripts.some(function (oldScript, idx) {
|
|
334
|
+
const oldSrcBase = oldScript.src.split('?')[0]!.split('&')[0];
|
|
335
|
+
const newScript = newScripts[idx];
|
|
336
|
+
if (!newScript) return true;
|
|
337
|
+
const newSrcBase = newScript.src.split('?')[0]!.split('&')[0];
|
|
338
|
+
return oldSrcBase !== newSrcBase;
|
|
339
|
+
})
|
|
340
|
+
);
|
|
341
|
+
};
|
|
342
|
+
|
|
343
|
+
const normalizeHTMLForComparison = (element: HTMLElement) => {
|
|
344
|
+
const clone = element.cloneNode(true) as HTMLElement;
|
|
345
|
+
const scripts = clone.querySelectorAll('script');
|
|
346
|
+
scripts.forEach(function (script) {
|
|
347
|
+
if (script.parentNode) {
|
|
348
|
+
script.parentNode.removeChild(script);
|
|
349
|
+
}
|
|
350
|
+
});
|
|
351
|
+
const allElements = clone.querySelectorAll('*');
|
|
352
|
+
allElements.forEach(function (el) {
|
|
353
|
+
el.removeAttribute('data-hmr-listeners-attached');
|
|
354
|
+
});
|
|
355
|
+
if (clone.removeAttribute) {
|
|
356
|
+
clone.removeAttribute('data-hmr-listeners-attached');
|
|
357
|
+
}
|
|
358
|
+
return clone.innerHTML;
|
|
359
|
+
};
|
|
360
|
+
|
|
361
|
+
const didHTMLStructureChange = (
|
|
362
|
+
container: HTMLElement,
|
|
363
|
+
tempDiv: HTMLElement
|
|
364
|
+
) => {
|
|
365
|
+
return (
|
|
366
|
+
normalizeHTMLForComparison(container) !==
|
|
367
|
+
normalizeHTMLForComparison(tempDiv)
|
|
368
|
+
);
|
|
369
|
+
};
|
|
370
|
+
|
|
371
|
+
const cloneInteractiveElements = (container: HTMLElement) => {
|
|
372
|
+
const interactiveSelectors =
|
|
373
|
+
'button, [onclick], [onchange], [oninput], [onsubmit], ' +
|
|
374
|
+
'details, input[type="button"], input[type="submit"], input[type="reset"]';
|
|
375
|
+
container.querySelectorAll(interactiveSelectors).forEach(function (el) {
|
|
376
|
+
const cloned = el.cloneNode(true);
|
|
377
|
+
if (el.parentNode) {
|
|
378
|
+
el.parentNode.replaceChild(cloned, el);
|
|
379
|
+
}
|
|
380
|
+
});
|
|
381
|
+
};
|
|
382
|
+
|
|
383
|
+
const removeOldScripts = (container: HTMLElement) => {
|
|
384
|
+
const scriptsInNewHTML = container.querySelectorAll('script[src]');
|
|
385
|
+
scriptsInNewHTML.forEach(function (script) {
|
|
386
|
+
if (!(script as Element).hasAttribute('data-hmr-client')) {
|
|
387
|
+
script.remove();
|
|
388
|
+
}
|
|
389
|
+
});
|
|
390
|
+
};
|
|
391
|
+
|
|
392
|
+
const reExecuteScripts = (container: HTMLElement, newScripts: ScriptInfo[]) => {
|
|
393
|
+
removeOldScripts(container);
|
|
394
|
+
|
|
395
|
+
newScripts.forEach(function (scriptInfo) {
|
|
396
|
+
const newScript = document.createElement('script');
|
|
397
|
+
const separator = scriptInfo.src.includes('?') ? '&' : '?';
|
|
398
|
+
newScript.src = scriptInfo.src + separator + 't=' + Date.now();
|
|
399
|
+
newScript.type = scriptInfo.type;
|
|
400
|
+
container.appendChild(newScript);
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
const inlineScripts = container.querySelectorAll('script:not([src])');
|
|
404
|
+
inlineScripts.forEach(function (script) {
|
|
405
|
+
if (!(script as Element).hasAttribute('data-hmr-client')) {
|
|
406
|
+
const newScript = document.createElement('script');
|
|
407
|
+
newScript.textContent = script.textContent || '';
|
|
408
|
+
newScript.type =
|
|
409
|
+
(script as HTMLScriptElement).type || 'text/javascript';
|
|
410
|
+
if (script.parentNode) {
|
|
411
|
+
script.parentNode.replaceChild(newScript, script);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
});
|
|
415
|
+
};
|