@nativescript/vite 1.0.6-rc.1 → 1.0.6-rc.2
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/bin/cli.cjs +0 -0
- package/configuration/angular.js +10 -1
- package/configuration/angular.js.map +1 -1
- package/configuration/base.js +2 -2
- package/configuration/base.js.map +1 -1
- package/configuration/react.js +1 -1
- package/configuration/react.js.map +1 -1
- package/configuration/solid.js +1 -1
- package/configuration/solid.js.map +1 -1
- package/configuration/typescript.js +1 -1
- package/configuration/typescript.js.map +1 -1
- package/configuration/vue.js +1 -1
- package/configuration/vue.js.map +1 -1
- package/helpers/css-tree.js +0 -1
- package/helpers/css-tree.js.map +1 -1
- package/helpers/init.js +4 -4
- package/helpers/init.js.map +1 -1
- package/helpers/main-entry.js +50 -5
- package/helpers/main-entry.js.map +1 -1
- package/helpers/nativeclass-transform.js +1 -1
- package/helpers/nativeclass-transform.js.map +1 -1
- package/hmr/client/index.js +146 -398
- package/hmr/client/index.js.map +1 -1
- package/hmr/client/utils.d.ts +0 -2
- package/hmr/client/utils.js +25 -179
- package/hmr/client/utils.js.map +1 -1
- package/hmr/entry-runtime.js +18 -1
- package/hmr/entry-runtime.js.map +1 -1
- package/hmr/frameworks/vue/client/index.js +1 -5
- package/hmr/frameworks/vue/client/index.js.map +1 -1
- package/hmr/helpers/ast-normalizer.js +11 -0
- package/hmr/helpers/ast-normalizer.js.map +1 -1
- package/hmr/server/constants.js +4 -1
- package/hmr/server/constants.js.map +1 -1
- package/hmr/server/vite-plugin.js +66 -6
- package/hmr/server/vite-plugin.js.map +1 -1
- package/hmr/server/websocket.js +52 -173
- package/hmr/server/websocket.js.map +1 -1
- package/hmr/shared/runtime/hooks.d.ts +17 -0
- package/hmr/shared/runtime/hooks.js +68 -0
- package/hmr/shared/runtime/hooks.js.map +1 -0
- package/hmr/shared/runtime/http-only-boot.js +20 -3
- package/hmr/shared/runtime/http-only-boot.js.map +1 -1
- package/hmr/shared/vendor/manifest.js +8 -5
- package/hmr/shared/vendor/manifest.js.map +1 -1
- package/package.json +1 -1
package/hmr/client/index.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Always resolve core classes and Application from the vendor realm or globalThis at runtime.
|
|
6
6
|
* The HMR client is evaluated via HTTP ESM on device; static imports would create secondary instances.
|
|
7
7
|
*/
|
|
8
|
-
import { setHMRWsUrl, getHMRWsUrl, pendingModuleFetches, deriveHttpOrigin, setHttpOriginForVite, moduleFetchCache, requestModuleFromServer, getHttpOriginForVite, normalizeSpec, hmrMetrics, graph, setGraphVersion, getGraphVersion, getCurrentApp, getRootFrame, setCurrentApp, setRootFrame, getCore
|
|
8
|
+
import { setHMRWsUrl, getHMRWsUrl, pendingModuleFetches, deriveHttpOrigin, setHttpOriginForVite, moduleFetchCache, requestModuleFromServer, getHttpOriginForVite, normalizeSpec, hmrMetrics, graph, setGraphVersion, getGraphVersion, getCurrentApp, getRootFrame, setCurrentApp, setRootFrame, getCore } from './utils.js';
|
|
9
9
|
import { handleCssUpdates } from './css-handler.js';
|
|
10
10
|
const VERBOSE = typeof __NS_ENV_VERBOSE__ !== 'undefined' && __NS_ENV_VERBOSE__;
|
|
11
11
|
const APP_ROOT_VIRTUAL = typeof __NS_APP_ROOT_VIRTUAL__ === 'string' && __NS_APP_ROOT_VIRTUAL__ ? __NS_APP_ROOT_VIRTUAL__ : '/src';
|
|
@@ -14,14 +14,6 @@ const APP_MAIN_ENTRY_SPEC = `${APP_VIRTUAL_WITH_SLASH}app.ts`;
|
|
|
14
14
|
// Policy: by default, let the app's own main entry mount initially; HMR client handles updates/remounts only.
|
|
15
15
|
// Flip this to true via global __NS_HMR_ALLOW_INITIAL_MOUNT__ if you need the client to perform the first mount.
|
|
16
16
|
const ALLOW_INITIAL_MOUNT = !!globalThis.__NS_HMR_ALLOW_INITIAL_MOUNT__;
|
|
17
|
-
// When verbose mode is enabled, also enable runtime nav diagnostics so /ns/rt logs are visible
|
|
18
|
-
try {
|
|
19
|
-
if (VERBOSE) {
|
|
20
|
-
globalThis.__NS_DEV_LOGS__ = true;
|
|
21
|
-
globalThis.__NS_VERBOSE_RT_NAV__ = true;
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
catch { }
|
|
25
17
|
// Ensure core aliases are present on globalThis early so that /ns/rt exports resolve to functions
|
|
26
18
|
// before any SFCs are evaluated during HTTP-only dev boot.
|
|
27
19
|
function ensureCoreAliasesOnGlobalThis() {
|
|
@@ -46,46 +38,11 @@ function ensureCoreAliasesOnGlobalThis() {
|
|
|
46
38
|
g.Page = P;
|
|
47
39
|
}
|
|
48
40
|
catch { }
|
|
49
|
-
// Optional diagnostics: compare with vendor realm if available
|
|
50
|
-
if (VERBOSE) {
|
|
51
|
-
let vF, vA, vP;
|
|
52
|
-
try {
|
|
53
|
-
const reg = g.__nsVendorRegistry;
|
|
54
|
-
const vmod = reg?.get ? reg.get('@nativescript/core') : undefined;
|
|
55
|
-
const vns = (vmod && (vmod.default || vmod)) || vmod;
|
|
56
|
-
vF = vns?.Frame;
|
|
57
|
-
vA = vns?.Application;
|
|
58
|
-
vP = vns?.Page;
|
|
59
|
-
}
|
|
60
|
-
catch { }
|
|
61
|
-
try {
|
|
62
|
-
console.log('[hmr-client] core alias status', {
|
|
63
|
-
globalHas: { Frame: !!F, Application: !!A, Page: !!P },
|
|
64
|
-
globalMethods: {
|
|
65
|
-
FrameTopmost: typeof F?.topmost === 'function',
|
|
66
|
-
AppResetRoot: typeof A?.resetRootView === 'function',
|
|
67
|
-
},
|
|
68
|
-
sameRef: {
|
|
69
|
-
Frame: F && vF ? F === vF : undefined,
|
|
70
|
-
Application: A && vA ? A === vA : undefined,
|
|
71
|
-
Page: P && vP ? P === vP : undefined,
|
|
72
|
-
},
|
|
73
|
-
ctorNames: {
|
|
74
|
-
Frame: F?.name || F?.constructor?.name,
|
|
75
|
-
Application: A?.name || A?.constructor?.name,
|
|
76
|
-
Page: P?.name || P?.constructor?.name,
|
|
77
|
-
},
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
catch { }
|
|
81
|
-
}
|
|
82
41
|
}
|
|
83
42
|
catch { }
|
|
84
43
|
}
|
|
85
44
|
// Apply once on module evaluation
|
|
86
45
|
ensureCoreAliasesOnGlobalThis();
|
|
87
|
-
// Install low-level diagnostics for navigation and root replacement to trace duplicates and state
|
|
88
|
-
installDeepDiagnostics();
|
|
89
46
|
/**
|
|
90
47
|
* Flavor hooks
|
|
91
48
|
*/
|
|
@@ -93,207 +50,12 @@ import { installNsVueDevShims, ensureBackWrapperInstalled, getRootForVue, loadSf
|
|
|
93
50
|
import { handleAngularHotUpdateMessage, installAngularHmrClientHooks } from '../frameworks/angular/client/index.js';
|
|
94
51
|
switch (__NS_TARGET_FLAVOR__) {
|
|
95
52
|
case 'vue':
|
|
96
|
-
if (VERBOSE) {
|
|
97
|
-
console.log('[hmr-client] installing nativescript-vue dev shims');
|
|
98
|
-
}
|
|
99
53
|
installNsVueDevShims();
|
|
100
54
|
break;
|
|
101
55
|
case 'angular':
|
|
102
|
-
if (VERBOSE) {
|
|
103
|
-
try {
|
|
104
|
-
console.log('[hmr-client] Initializing Angular HMR shims');
|
|
105
|
-
}
|
|
106
|
-
catch { }
|
|
107
|
-
}
|
|
108
56
|
installAngularHmrClientHooks();
|
|
109
57
|
break;
|
|
110
58
|
}
|
|
111
|
-
// Global frame diagnostics: instrument Frame.navigate and Frame.topmost to detect
|
|
112
|
-
// navigation against non-authoritative frames across the app (helps gray-screen cases)
|
|
113
|
-
try {
|
|
114
|
-
const g = globalThis;
|
|
115
|
-
const F = getCore('Frame') || g.Frame;
|
|
116
|
-
if (F && F.prototype && !g.__NS_DEV_GLOBAL_FRAME_PATCHED__) {
|
|
117
|
-
const tag = (fr) => {
|
|
118
|
-
try {
|
|
119
|
-
if (!fr)
|
|
120
|
-
return;
|
|
121
|
-
if (!fr.__ns_tag)
|
|
122
|
-
fr.__ns_tag = Math.random().toString(36).slice(2);
|
|
123
|
-
}
|
|
124
|
-
catch { }
|
|
125
|
-
};
|
|
126
|
-
const proto = F.prototype;
|
|
127
|
-
const origNav = proto.navigate;
|
|
128
|
-
if (typeof origNav === 'function') {
|
|
129
|
-
proto.navigate = function __ns_diag_nav(entry) {
|
|
130
|
-
try {
|
|
131
|
-
tag(this);
|
|
132
|
-
console.log('[diag][global][frame.navigate]', {
|
|
133
|
-
tag: this.__ns_tag,
|
|
134
|
-
type: this?.constructor?.name,
|
|
135
|
-
hasCreate: !!entry?.create,
|
|
136
|
-
clearHistory: !!entry?.clearHistory,
|
|
137
|
-
animated: !!entry?.animated,
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
catch { }
|
|
141
|
-
return origNav.apply(this, arguments);
|
|
142
|
-
};
|
|
143
|
-
}
|
|
144
|
-
const origTop = typeof F.topmost === 'function' ? F.topmost.bind(F) : null;
|
|
145
|
-
if (origTop) {
|
|
146
|
-
F.topmost = function __ns_diag_topmost() {
|
|
147
|
-
const fr = origTop();
|
|
148
|
-
try {
|
|
149
|
-
tag(fr);
|
|
150
|
-
console.log('[diag][global][Frame.topmost]', {
|
|
151
|
-
tag: fr?.__ns_tag,
|
|
152
|
-
type: fr?.constructor?.name,
|
|
153
|
-
});
|
|
154
|
-
}
|
|
155
|
-
catch { }
|
|
156
|
-
return fr;
|
|
157
|
-
};
|
|
158
|
-
}
|
|
159
|
-
try {
|
|
160
|
-
g.__NS_DEV_GLOBAL_FRAME_PATCHED__ = true;
|
|
161
|
-
}
|
|
162
|
-
catch { }
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
catch { }
|
|
166
|
-
// --- Diagnostics helpers ----------------------------------------------------
|
|
167
|
-
function summarizeNavEntry(entry) {
|
|
168
|
-
try {
|
|
169
|
-
if (!entry)
|
|
170
|
-
return { kind: 'empty' };
|
|
171
|
-
if (typeof entry === 'string')
|
|
172
|
-
return { kind: 'string', moduleName: entry };
|
|
173
|
-
const hasCreate = typeof entry.create === 'function';
|
|
174
|
-
const moduleName = entry.moduleName;
|
|
175
|
-
const clearHistory = !!entry.clearHistory;
|
|
176
|
-
const animated = entry.animated;
|
|
177
|
-
const backstackVisible = entry.backstackVisible;
|
|
178
|
-
const contextKeys = Object.keys(entry.context || {});
|
|
179
|
-
return {
|
|
180
|
-
kind: 'entry',
|
|
181
|
-
hasCreate,
|
|
182
|
-
moduleName,
|
|
183
|
-
clearHistory,
|
|
184
|
-
animated,
|
|
185
|
-
backstackVisible,
|
|
186
|
-
contextKeys,
|
|
187
|
-
};
|
|
188
|
-
}
|
|
189
|
-
catch {
|
|
190
|
-
return { kind: 'unknown' };
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
function classifyResetArg(arg) {
|
|
194
|
-
try {
|
|
195
|
-
const ctorName = String(arg?.constructor?.name || '').replace(/^_+/, '');
|
|
196
|
-
const keys = Object.keys(arg || {});
|
|
197
|
-
const hasCreate = typeof arg?.create === 'function';
|
|
198
|
-
const hasModuleName = typeof arg?.moduleName === 'string';
|
|
199
|
-
const isFrameLike = !!arg && (ctorName === 'Frame' || /^Frame(\$\d+)?$/.test(ctorName) || (typeof arg?.navigate === 'function' && typeof arg?.addChild === 'function'));
|
|
200
|
-
const isPageLike = !!arg && (ctorName === 'Page' || /^Page(\$\d+)?$/.test(ctorName) || (typeof arg?.content !== 'undefined' && typeof arg?.addChild === 'function'));
|
|
201
|
-
return {
|
|
202
|
-
ctorName,
|
|
203
|
-
keys,
|
|
204
|
-
hasCreate,
|
|
205
|
-
hasModuleName,
|
|
206
|
-
isFrameLike,
|
|
207
|
-
isPageLike,
|
|
208
|
-
};
|
|
209
|
-
}
|
|
210
|
-
catch {
|
|
211
|
-
return { ctorName: 'unknown' };
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
function installDeepDiagnostics() {
|
|
215
|
-
if (!VERBOSE)
|
|
216
|
-
return;
|
|
217
|
-
const g = globalThis;
|
|
218
|
-
try {
|
|
219
|
-
// Patch Frame.navigate to log calls and a short stack
|
|
220
|
-
const F = getCore('Frame') || g.Frame;
|
|
221
|
-
if (F?.prototype && !F.prototype.__ns_diag_nav__) {
|
|
222
|
-
const orig = F.prototype.navigate;
|
|
223
|
-
if (typeof orig === 'function') {
|
|
224
|
-
F.prototype.__ns_diag_nav__ = true;
|
|
225
|
-
// Simple duplicate navigation suppression in dev: if the same target is navigated twice within a short window, ignore the 2nd.
|
|
226
|
-
F.prototype.navigate = function (...args) {
|
|
227
|
-
try {
|
|
228
|
-
const entry = args[0];
|
|
229
|
-
const summary = summarizeNavEntry(entry);
|
|
230
|
-
const stack = (new Error().stack || '').split('\n').slice(2, 8).join('\n');
|
|
231
|
-
console.log('[diag][Frame.navigate]', {
|
|
232
|
-
frameCtor: this?.constructor?.name,
|
|
233
|
-
summary,
|
|
234
|
-
stack,
|
|
235
|
-
});
|
|
236
|
-
try {
|
|
237
|
-
const gAny = globalThis;
|
|
238
|
-
const key = JSON.stringify({
|
|
239
|
-
k: 'nav',
|
|
240
|
-
m: summary.moduleName || '',
|
|
241
|
-
c: !!summary.hasCreate,
|
|
242
|
-
ch: !!summary.clearHistory,
|
|
243
|
-
a: !!summary.animated,
|
|
244
|
-
});
|
|
245
|
-
const now = Date.now();
|
|
246
|
-
const last = gAny.__NS_DIAG_LAST_NAV__;
|
|
247
|
-
if (last && last.key === key && now - last.t < 300) {
|
|
248
|
-
console.warn('[diag][Frame.navigate] duplicate nav suppressed (dev)', { withinMs: now - last.t, key });
|
|
249
|
-
return; // suppress duplicate
|
|
250
|
-
}
|
|
251
|
-
gAny.__NS_DIAG_LAST_NAV__ = { key, t: now };
|
|
252
|
-
}
|
|
253
|
-
catch { }
|
|
254
|
-
}
|
|
255
|
-
catch { }
|
|
256
|
-
return orig.apply(this, args);
|
|
257
|
-
};
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
catch { }
|
|
262
|
-
try {
|
|
263
|
-
// Wrap Application.resetRootView to log argument classification and stack
|
|
264
|
-
const App = getCore('Application') || g.Application;
|
|
265
|
-
const proto = App && Object.getPrototypeOf(App);
|
|
266
|
-
const orig = (App && App.resetRootView) || (proto && proto.resetRootView);
|
|
267
|
-
if (typeof orig === 'function' && !g.__NS_DIAG_RESET_WRAPPED__) {
|
|
268
|
-
const wrapped = function __ns_diag_resetRootView(entry) {
|
|
269
|
-
try {
|
|
270
|
-
const classification = classifyResetArg(entry);
|
|
271
|
-
const stack = (new Error().stack || '').split('\n').slice(2, 8).join('\n');
|
|
272
|
-
console.log('[diag][Application.resetRootView]', {
|
|
273
|
-
classification,
|
|
274
|
-
stack,
|
|
275
|
-
});
|
|
276
|
-
}
|
|
277
|
-
catch { }
|
|
278
|
-
return orig.call(this, entry);
|
|
279
|
-
};
|
|
280
|
-
try {
|
|
281
|
-
App.resetRootView = wrapped;
|
|
282
|
-
}
|
|
283
|
-
catch { }
|
|
284
|
-
try {
|
|
285
|
-
if (proto && typeof proto === 'object')
|
|
286
|
-
proto.resetRootView = wrapped;
|
|
287
|
-
}
|
|
288
|
-
catch { }
|
|
289
|
-
try {
|
|
290
|
-
g.__NS_DIAG_RESET_WRAPPED__ = true;
|
|
291
|
-
}
|
|
292
|
-
catch { }
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
catch { }
|
|
296
|
-
}
|
|
297
59
|
// Track whether we've mounted an initial app root yet in HTTP-only boot
|
|
298
60
|
let initialMounted = !!globalThis.__NS_HMR_BOOT_COMPLETE__;
|
|
299
61
|
// Prevent duplicate initial-mount scheduling across rapid full-graph broadcasts and re-evaluations
|
|
@@ -303,6 +65,7 @@ let tsModuleSet = null;
|
|
|
303
65
|
let tsMainId = null;
|
|
304
66
|
const changedQueue = [];
|
|
305
67
|
let processingQueue = false;
|
|
68
|
+
let processingPromise = null;
|
|
306
69
|
// Detect whether the early placeholder root is still active on screen
|
|
307
70
|
function isPlaceholderActive() {
|
|
308
71
|
try {
|
|
@@ -844,7 +607,6 @@ function __nsNavigateUsingApp(comp, opts = {}) {
|
|
|
844
607
|
if (typeof GApp?.resetRootView === 'function' && typeof F === 'function') {
|
|
845
608
|
GApp.resetRootView({
|
|
846
609
|
create: () => {
|
|
847
|
-
var _a;
|
|
848
610
|
const fr = new F();
|
|
849
611
|
const navEntry = {
|
|
850
612
|
create: () => buildTarget(),
|
|
@@ -855,19 +617,7 @@ function __nsNavigateUsingApp(comp, opts = {}) {
|
|
|
855
617
|
fr.navigate(navEntry);
|
|
856
618
|
}
|
|
857
619
|
catch { }
|
|
858
|
-
try {
|
|
859
|
-
attachDiagnosticsToFrame(fr);
|
|
860
|
-
}
|
|
861
|
-
catch { }
|
|
862
620
|
setRootFrame(fr);
|
|
863
|
-
try {
|
|
864
|
-
(_a = getRootFrame()).__ns_tag || (_a.__ns_tag = Math.random().toString(36).slice(2));
|
|
865
|
-
console.log('[diag][root] ROOT_FRAME set (app-nav)', {
|
|
866
|
-
tag: getRootFrame()?.__ns_tag,
|
|
867
|
-
type: getRootFrame()?.constructor?.name,
|
|
868
|
-
});
|
|
869
|
-
}
|
|
870
|
-
catch { }
|
|
871
621
|
return fr;
|
|
872
622
|
},
|
|
873
623
|
});
|
|
@@ -875,28 +625,8 @@ function __nsNavigateUsingApp(comp, opts = {}) {
|
|
|
875
625
|
}
|
|
876
626
|
throw new Error('Application.resetRootView unavailable');
|
|
877
627
|
}
|
|
878
|
-
try {
|
|
879
|
-
attachDiagnosticsToFrame(frame);
|
|
880
|
-
}
|
|
881
|
-
catch { }
|
|
882
628
|
const navEntry = { create: () => buildTarget(), ...(opts || {}) };
|
|
883
|
-
try {
|
|
884
|
-
const summary = summarizeNavEntry(navEntry);
|
|
885
|
-
if (VERBOSE)
|
|
886
|
-
console.log('[app-nav] navigate entry', summary);
|
|
887
|
-
}
|
|
888
|
-
catch { }
|
|
889
629
|
frame.navigate(navEntry);
|
|
890
|
-
try {
|
|
891
|
-
const top2 = (g.Frame && g.Frame.topmost && g.Frame.topmost()) || null;
|
|
892
|
-
const ctor2 = top2 && top2.constructor && top2.constructor.name;
|
|
893
|
-
if (VERBOSE)
|
|
894
|
-
console.log('[app-nav] after navigate', {
|
|
895
|
-
topCtor: ctor2,
|
|
896
|
-
hasTop: !!top2,
|
|
897
|
-
});
|
|
898
|
-
}
|
|
899
|
-
catch { }
|
|
900
630
|
return undefined;
|
|
901
631
|
}
|
|
902
632
|
// Expose deterministic app navigation globally so /ns/rt can guarantee single-path navigation
|
|
@@ -914,77 +644,81 @@ async function processQueue() {
|
|
|
914
644
|
}
|
|
915
645
|
catch { }
|
|
916
646
|
}, 150);
|
|
917
|
-
return;
|
|
647
|
+
return Promise.resolve();
|
|
918
648
|
}
|
|
919
649
|
if (processingQueue)
|
|
920
|
-
return;
|
|
650
|
+
return processingPromise || Promise.resolve();
|
|
921
651
|
processingQueue = true;
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
if (seen.has(id))
|
|
933
|
-
continue;
|
|
934
|
-
seen.add(id);
|
|
935
|
-
drained.push(id);
|
|
936
|
-
}
|
|
937
|
-
if (!drained.length)
|
|
938
|
-
return;
|
|
939
|
-
if (VERBOSE)
|
|
940
|
-
console.log('[hmr][queue] processing changed ids', drained);
|
|
941
|
-
// Evaluate changed modules best-effort; failures shouldn't completely break HMR.
|
|
942
|
-
for (const id of drained) {
|
|
943
|
-
try {
|
|
944
|
-
const spec = normalizeSpec(id);
|
|
945
|
-
const url = await requestModuleFromServer(spec);
|
|
946
|
-
if (!url)
|
|
652
|
+
processingPromise = (async () => {
|
|
653
|
+
try {
|
|
654
|
+
// Simple deterministic drain of the queue. We currently focus on TS flavor
|
|
655
|
+
// by re-importing changed modules (to refresh their HTTP ESM copies) and
|
|
656
|
+
// then performing a root reset so the UI reflects the new code.
|
|
657
|
+
const seen = new Set();
|
|
658
|
+
const drained = [];
|
|
659
|
+
while (changedQueue.length) {
|
|
660
|
+
const id = changedQueue.shift();
|
|
661
|
+
if (!id || typeof id !== 'string')
|
|
947
662
|
continue;
|
|
948
|
-
if (
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
catch (e) {
|
|
953
|
-
if (VERBOSE)
|
|
954
|
-
console.warn('[hmr][queue] re-import failed for', id, e);
|
|
663
|
+
if (seen.has(id))
|
|
664
|
+
continue;
|
|
665
|
+
seen.add(id);
|
|
666
|
+
drained.push(id);
|
|
955
667
|
}
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
case 'typescript': {
|
|
963
|
-
// For TS apps, always reset back to the conventional app root.
|
|
964
|
-
// This preserves the shell (Frame, ActionBar, etc.) that the app's
|
|
965
|
-
// own bootstrapping wires up via `Application.run`.
|
|
668
|
+
if (!drained.length)
|
|
669
|
+
return;
|
|
670
|
+
if (VERBOSE)
|
|
671
|
+
console.log('[hmr][queue] processing changed ids', drained);
|
|
672
|
+
// Evaluate changed modules best-effort; failures shouldn't completely break HMR.
|
|
673
|
+
for (const id of drained) {
|
|
966
674
|
try {
|
|
967
|
-
const
|
|
968
|
-
const
|
|
969
|
-
if (!
|
|
970
|
-
|
|
971
|
-
console.warn('[hmr][queue] TS flavor: Application.resetRootView unavailable; skipping UI refresh');
|
|
972
|
-
break;
|
|
973
|
-
}
|
|
675
|
+
const spec = normalizeSpec(id);
|
|
676
|
+
const url = await requestModuleFromServer(spec);
|
|
677
|
+
if (!url)
|
|
678
|
+
continue;
|
|
974
679
|
if (VERBOSE)
|
|
975
|
-
console.log('[hmr][queue]
|
|
976
|
-
|
|
680
|
+
console.log('[hmr][queue] re-import', { id, spec, url });
|
|
681
|
+
const mod = await import(/* @vite-ignore */ url);
|
|
977
682
|
}
|
|
978
683
|
catch (e) {
|
|
979
|
-
|
|
684
|
+
if (VERBOSE)
|
|
685
|
+
console.warn('[hmr][queue] re-import failed for', id, e);
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
// After evaluating the batch, perform flavor-specific UI refresh.
|
|
689
|
+
switch (__NS_TARGET_FLAVOR__) {
|
|
690
|
+
case 'vue':
|
|
691
|
+
// Vue SFCs are handled via the registry update path; nothing to do here.
|
|
692
|
+
break;
|
|
693
|
+
case 'typescript': {
|
|
694
|
+
// For TS apps, always reset back to the conventional app root.
|
|
695
|
+
// This preserves the shell (Frame, ActionBar, etc.) that the app's
|
|
696
|
+
// own bootstrapping wires up via `Application.run`.
|
|
697
|
+
try {
|
|
698
|
+
const g = globalThis;
|
|
699
|
+
const App = getCore('Application') || g.Application;
|
|
700
|
+
if (!App || typeof App.resetRootView !== 'function') {
|
|
701
|
+
if (VERBOSE)
|
|
702
|
+
console.warn('[hmr][queue] TS flavor: Application.resetRootView unavailable; skipping UI refresh');
|
|
703
|
+
break;
|
|
704
|
+
}
|
|
705
|
+
if (VERBOSE)
|
|
706
|
+
console.log('[hmr][queue] TS flavor: resetRootView(app-root) after changes');
|
|
707
|
+
App.resetRootView({ moduleName: 'app-root' });
|
|
708
|
+
}
|
|
709
|
+
catch (e) {
|
|
710
|
+
console.warn('[hmr][queue] TS flavor: resetRootView(app-root) failed', e);
|
|
711
|
+
}
|
|
712
|
+
break;
|
|
980
713
|
}
|
|
981
|
-
break;
|
|
982
714
|
}
|
|
983
715
|
}
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
716
|
+
finally {
|
|
717
|
+
processingQueue = false;
|
|
718
|
+
processingPromise = null;
|
|
719
|
+
}
|
|
720
|
+
})();
|
|
721
|
+
return processingPromise;
|
|
988
722
|
}
|
|
989
723
|
let hmrSocket = null;
|
|
990
724
|
// Track server-announced batches for each version so we can import in-order client-side
|
|
@@ -1140,12 +874,77 @@ async function handleHmrMessage(ev) {
|
|
|
1140
874
|
catch {
|
|
1141
875
|
return;
|
|
1142
876
|
}
|
|
1143
|
-
|
|
1144
|
-
|
|
877
|
+
// Notify optional app-level hook after an HMR batch is applied.
|
|
878
|
+
function notifyAppHmrUpdate(kind, changedIds) {
|
|
879
|
+
try {
|
|
880
|
+
const hook = globalThis.__NS_HMR_ON_UPDATE__;
|
|
881
|
+
if (typeof hook === 'function') {
|
|
882
|
+
hook({ type: kind, version: getGraphVersion(), changedIds: changedIds || [], raw: msg });
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
catch { }
|
|
886
|
+
}
|
|
1145
887
|
if (msg) {
|
|
1146
888
|
if (msg.type === 'ns:hmr-full-graph') {
|
|
889
|
+
// Bump a monotonic nonce so HTTP ESM imports can always be cache-busted per update.
|
|
890
|
+
try {
|
|
891
|
+
const g = globalThis;
|
|
892
|
+
g.__NS_HMR_IMPORT_NONCE__ = (typeof g.__NS_HMR_IMPORT_NONCE__ === 'number' ? g.__NS_HMR_IMPORT_NONCE__ : 0) + 1;
|
|
893
|
+
}
|
|
894
|
+
catch { }
|
|
895
|
+
// Capture previous graph snapshot so we can infer which modules changed.
|
|
896
|
+
const prevGraph = new Map(graph);
|
|
1147
897
|
setGraphVersion(Number(msg.version || getGraphVersion() || 0));
|
|
1148
898
|
applyFullGraph(msg);
|
|
899
|
+
// In some cases (e.g. server chooses full-graph resync / page reload), we won't
|
|
900
|
+
// receive a delta queue to re-import changed TS modules. Without re-import,
|
|
901
|
+
// HTTP ESM caching means module bodies (and side effects) won't re-run.
|
|
902
|
+
try {
|
|
903
|
+
const inferredChanged = [];
|
|
904
|
+
try {
|
|
905
|
+
for (const [id, next] of graph.entries()) {
|
|
906
|
+
const prev = prevGraph.get(id);
|
|
907
|
+
if (!prev || prev.hash !== next.hash)
|
|
908
|
+
inferredChanged.push(id);
|
|
909
|
+
}
|
|
910
|
+
// Removed modules are also "changed" but we don't import them.
|
|
911
|
+
}
|
|
912
|
+
catch { }
|
|
913
|
+
// Best-effort: only re-import real source modules (avoid .vue registry pipeline and virtual ids)
|
|
914
|
+
const toReimport = inferredChanged.filter((id) => {
|
|
915
|
+
if (!id || typeof id !== 'string')
|
|
916
|
+
return false;
|
|
917
|
+
if (/^\0|^\/\0/.test(id))
|
|
918
|
+
return false;
|
|
919
|
+
if (/plugin-vue:export-helper/.test(id))
|
|
920
|
+
return false;
|
|
921
|
+
if (/\.vue$/i.test(id))
|
|
922
|
+
return false;
|
|
923
|
+
if (id.endsWith(APP_MAIN_ENTRY_SPEC))
|
|
924
|
+
return false;
|
|
925
|
+
return true;
|
|
926
|
+
});
|
|
927
|
+
if (toReimport.length && VERBOSE)
|
|
928
|
+
console.log('[hmr][full-graph] inferred changed modules; re-importing', toReimport);
|
|
929
|
+
for (const id of toReimport) {
|
|
930
|
+
try {
|
|
931
|
+
const spec = normalizeSpec(id);
|
|
932
|
+
const url = await requestModuleFromServer(spec);
|
|
933
|
+
if (!url)
|
|
934
|
+
continue;
|
|
935
|
+
if (VERBOSE)
|
|
936
|
+
console.log('[hmr][full-graph] re-import', { id, spec, url });
|
|
937
|
+
await import(/* @vite-ignore */ url);
|
|
938
|
+
}
|
|
939
|
+
catch (e) {
|
|
940
|
+
if (VERBOSE)
|
|
941
|
+
console.warn('[hmr][full-graph] re-import failed for', id, e);
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
catch { }
|
|
946
|
+
const fullIds = Array.isArray(msg.modules) ? msg.modules.map((m) => m?.id).filter(Boolean) : [];
|
|
947
|
+
notifyAppHmrUpdate('full-graph', fullIds);
|
|
1149
948
|
return;
|
|
1150
949
|
}
|
|
1151
950
|
if (msg.type === 'ns:ts-module-registry') {
|
|
@@ -1176,7 +975,12 @@ async function handleHmrMessage(ev) {
|
|
|
1176
975
|
return;
|
|
1177
976
|
}
|
|
1178
977
|
if (msg.type === 'ns:hmr-delta') {
|
|
1179
|
-
|
|
978
|
+
// Bump a monotonic nonce so HTTP ESM imports can always be cache-busted per update.
|
|
979
|
+
try {
|
|
980
|
+
const g = globalThis;
|
|
981
|
+
g.__NS_HMR_IMPORT_NONCE__ = (typeof g.__NS_HMR_IMPORT_NONCE__ === 'number' ? g.__NS_HMR_IMPORT_NONCE__ : 0) + 1;
|
|
982
|
+
}
|
|
983
|
+
catch { }
|
|
1180
984
|
try {
|
|
1181
985
|
const ids = Array.isArray(msg.changed) ? msg.changed.map((c) => c?.id).filter(Boolean) : [];
|
|
1182
986
|
if (ids.length)
|
|
@@ -1184,6 +988,14 @@ async function handleHmrMessage(ev) {
|
|
|
1184
988
|
}
|
|
1185
989
|
catch { }
|
|
1186
990
|
applyDelta(msg);
|
|
991
|
+
// Ensure queued module re-imports complete before notifying app hooks.
|
|
992
|
+
// Otherwise app-level handlers can run against stale module bodies due to HTTP ESM caching.
|
|
993
|
+
try {
|
|
994
|
+
await processQueue();
|
|
995
|
+
}
|
|
996
|
+
catch { }
|
|
997
|
+
const deltaIds = Array.isArray(msg.changed) ? msg.changed.map((c) => c?.id).filter(Boolean) : [];
|
|
998
|
+
notifyAppHmrUpdate('delta', deltaIds);
|
|
1187
999
|
return;
|
|
1188
1000
|
}
|
|
1189
1001
|
else if (handleAngularHotUpdateMessage(msg, { getCore, verbose: VERBOSE })) {
|
|
@@ -1297,25 +1109,6 @@ async function performResetRoot(newComponent) {
|
|
|
1297
1109
|
ensureCoreAliasesOnGlobalThis();
|
|
1298
1110
|
}
|
|
1299
1111
|
catch { }
|
|
1300
|
-
try {
|
|
1301
|
-
if (VERBOSE)
|
|
1302
|
-
logUiSnapshot('pre-performResetRoot');
|
|
1303
|
-
}
|
|
1304
|
-
catch { }
|
|
1305
|
-
if (VERBOSE) {
|
|
1306
|
-
try {
|
|
1307
|
-
const g = globalThis;
|
|
1308
|
-
const vF = getCore('Frame');
|
|
1309
|
-
console.log('[hmr-client] alias check before remount', {
|
|
1310
|
-
globalFrameHasTopmost: typeof g?.Frame?.topmost === 'function',
|
|
1311
|
-
vendorFrameHasTopmost: typeof vF?.topmost === 'function',
|
|
1312
|
-
sameFrameRef: vF === g?.Frame,
|
|
1313
|
-
appHasReset: typeof g?.Application?.resetRootView === 'function',
|
|
1314
|
-
pageIsCtor: typeof g?.Page === 'function',
|
|
1315
|
-
});
|
|
1316
|
-
}
|
|
1317
|
-
catch { }
|
|
1318
|
-
}
|
|
1319
1112
|
if (VERBOSE) {
|
|
1320
1113
|
console.log('[hmr-client] Single-path: replace current root Page');
|
|
1321
1114
|
console.log('[hmr-client] Component details:', {
|
|
@@ -1522,12 +1315,6 @@ async function performResetRoot(newComponent) {
|
|
|
1522
1315
|
const isAuthoritativeFrame = !!existingAppFrame && existingAppFrame !== placeholderFrame;
|
|
1523
1316
|
if (!hadPlaceholder && !isFrameRoot && isAuthoritativeFrame && typeof existingAppFrame.navigate === 'function') {
|
|
1524
1317
|
try {
|
|
1525
|
-
if (VERBOSE)
|
|
1526
|
-
console.log('[hmr-client] navigating authoritative app Frame to new Page (no placeholder, smooth swap)');
|
|
1527
|
-
try {
|
|
1528
|
-
attachDiagnosticsToFrame(existingAppFrame);
|
|
1529
|
-
}
|
|
1530
|
-
catch { }
|
|
1531
1318
|
const navEntry = {
|
|
1532
1319
|
create: () => preparedRoot,
|
|
1533
1320
|
clearHistory: true,
|
|
@@ -1597,7 +1384,6 @@ async function performResetRoot(newComponent) {
|
|
|
1597
1384
|
// Use the previously created preparedRoot
|
|
1598
1385
|
const entry = {
|
|
1599
1386
|
create: () => {
|
|
1600
|
-
var _a, _b;
|
|
1601
1387
|
if (!isFrameRoot) {
|
|
1602
1388
|
const F = getCore('Frame');
|
|
1603
1389
|
const fr = new F();
|
|
@@ -1612,68 +1398,30 @@ async function performResetRoot(newComponent) {
|
|
|
1612
1398
|
};
|
|
1613
1399
|
try {
|
|
1614
1400
|
fr.navigate(navEntry);
|
|
1615
|
-
if (VERBOSE)
|
|
1616
|
-
console.log('[hmr-client] resetRootView:create navigated Frame');
|
|
1617
1401
|
}
|
|
1618
1402
|
catch (e) {
|
|
1619
1403
|
console.warn('[hmr-client] resetRootView:create navigate failed', e);
|
|
1620
1404
|
}
|
|
1621
|
-
try {
|
|
1622
|
-
attachDiagnosticsToFrame(fr);
|
|
1623
|
-
}
|
|
1624
|
-
catch { }
|
|
1625
1405
|
setRootFrame(fr);
|
|
1626
|
-
try {
|
|
1627
|
-
(_a = getRootFrame()).__ns_tag || (_a.__ns_tag = Math.random().toString(36).slice(2));
|
|
1628
|
-
console.log('[diag][root] ROOT_FRAME set (new)', {
|
|
1629
|
-
tag: getRootFrame()?.__ns_tag,
|
|
1630
|
-
type: getRootFrame()?.constructor?.name,
|
|
1631
|
-
});
|
|
1632
|
-
}
|
|
1633
|
-
catch { }
|
|
1634
1406
|
return fr;
|
|
1635
1407
|
}
|
|
1636
1408
|
else {
|
|
1637
1409
|
const fr = preparedRoot;
|
|
1638
|
-
if (VERBOSE)
|
|
1639
|
-
console.log('[hmr-client] resetRootView:create using provided Frame', { type: fr?.constructor?.name });
|
|
1640
|
-
try {
|
|
1641
|
-
attachDiagnosticsToFrame(fr);
|
|
1642
|
-
}
|
|
1643
|
-
catch { }
|
|
1644
1410
|
setRootFrame(fr);
|
|
1645
|
-
try {
|
|
1646
|
-
(_b = getRootFrame()).__ns_tag || (_b.__ns_tag = Math.random().toString(36).slice(2));
|
|
1647
|
-
console.log('[diag][root] ROOT_FRAME set (provided)', {
|
|
1648
|
-
tag: getRootFrame()?.__ns_tag,
|
|
1649
|
-
type: getRootFrame()?.constructor?.name,
|
|
1650
|
-
});
|
|
1651
|
-
}
|
|
1652
|
-
catch { }
|
|
1653
1411
|
return fr;
|
|
1654
1412
|
}
|
|
1655
1413
|
},
|
|
1656
1414
|
};
|
|
1657
|
-
if (VERBOSE)
|
|
1658
|
-
console.log('[hmr-client] invoking Application.resetRootView with entry (always)', { isFrameRoot, hadPlaceholder, isIOS });
|
|
1659
1415
|
// Always use an entry with a create() function to avoid cross‑realm instanceof checks on Android.
|
|
1660
1416
|
App2.resetRootView(entry);
|
|
1661
1417
|
// After authoritative reset, it's safe to detach the early placeholder launch handler
|
|
1662
1418
|
try {
|
|
1663
1419
|
const restore = globalThis.__NS_DEV_RESTORE_PLACEHOLDER__;
|
|
1664
1420
|
if (typeof restore === 'function') {
|
|
1665
|
-
if (VERBOSE)
|
|
1666
|
-
console.log('[hmr-client] restoring: detach early placeholder launch handler');
|
|
1667
1421
|
restore();
|
|
1668
1422
|
}
|
|
1669
1423
|
}
|
|
1670
1424
|
catch { }
|
|
1671
|
-
if (VERBOSE) {
|
|
1672
|
-
logUiSnapshot('post-resetRootView');
|
|
1673
|
-
console.log('[hmr-client] performResetRoot completed', {
|
|
1674
|
-
elapsedMs: Date.now() - tStart,
|
|
1675
|
-
});
|
|
1676
|
-
}
|
|
1677
1425
|
return true;
|
|
1678
1426
|
}
|
|
1679
1427
|
catch (e) {
|