@nativescript/vite 1.0.5 → 1.0.6-next.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/bin/cli.cjs +0 -0
- package/configuration/angular.js +1 -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 +1 -0
- package/helpers/css-tree.js.map +1 -1
- package/helpers/main-entry.js +5 -50
- package/helpers/main-entry.js.map +1 -1
- package/hmr/client/index.js +398 -146
- package/hmr/client/index.js.map +1 -1
- package/hmr/client/utils.d.ts +2 -0
- package/hmr/client/utils.js +179 -25
- package/hmr/client/utils.js.map +1 -1
- package/hmr/entry-runtime.js +1 -18
- package/hmr/entry-runtime.js.map +1 -1
- package/hmr/frameworks/vue/client/index.js +5 -1
- package/hmr/frameworks/vue/client/index.js.map +1 -1
- package/hmr/server/vite-plugin.js +6 -66
- package/hmr/server/vite-plugin.js.map +1 -1
- package/hmr/server/websocket.js +173 -52
- package/hmr/server/websocket.js.map +1 -1
- package/hmr/shared/runtime/http-only-boot.js +3 -20
- package/hmr/shared/runtime/http-only-boot.js.map +1 -1
- package/hmr/shared/vendor/manifest.js +5 -8
- package/hmr/shared/vendor/manifest.js.map +1 -1
- package/package.json +10 -1
- package/hmr/shared/runtime/hooks.d.ts +0 -17
- package/hmr/shared/runtime/hooks.js +0 -68
- package/hmr/shared/runtime/hooks.js.map +0 -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 } from './utils.js';
|
|
8
|
+
import { setHMRWsUrl, getHMRWsUrl, pendingModuleFetches, deriveHttpOrigin, setHttpOriginForVite, moduleFetchCache, requestModuleFromServer, getHttpOriginForVite, normalizeSpec, hmrMetrics, graph, setGraphVersion, getGraphVersion, getCurrentApp, getRootFrame, setCurrentApp, setRootFrame, getCore, attachDiagnosticsToFrame, logUiSnapshot } 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,6 +14,14 @@ 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 { }
|
|
17
25
|
// Ensure core aliases are present on globalThis early so that /ns/rt exports resolve to functions
|
|
18
26
|
// before any SFCs are evaluated during HTTP-only dev boot.
|
|
19
27
|
function ensureCoreAliasesOnGlobalThis() {
|
|
@@ -38,11 +46,46 @@ function ensureCoreAliasesOnGlobalThis() {
|
|
|
38
46
|
g.Page = P;
|
|
39
47
|
}
|
|
40
48
|
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
|
+
}
|
|
41
82
|
}
|
|
42
83
|
catch { }
|
|
43
84
|
}
|
|
44
85
|
// Apply once on module evaluation
|
|
45
86
|
ensureCoreAliasesOnGlobalThis();
|
|
87
|
+
// Install low-level diagnostics for navigation and root replacement to trace duplicates and state
|
|
88
|
+
installDeepDiagnostics();
|
|
46
89
|
/**
|
|
47
90
|
* Flavor hooks
|
|
48
91
|
*/
|
|
@@ -50,12 +93,207 @@ import { installNsVueDevShims, ensureBackWrapperInstalled, getRootForVue, loadSf
|
|
|
50
93
|
import { handleAngularHotUpdateMessage, installAngularHmrClientHooks } from '../frameworks/angular/client/index.js';
|
|
51
94
|
switch (__NS_TARGET_FLAVOR__) {
|
|
52
95
|
case 'vue':
|
|
96
|
+
if (VERBOSE) {
|
|
97
|
+
console.log('[hmr-client] installing nativescript-vue dev shims');
|
|
98
|
+
}
|
|
53
99
|
installNsVueDevShims();
|
|
54
100
|
break;
|
|
55
101
|
case 'angular':
|
|
102
|
+
if (VERBOSE) {
|
|
103
|
+
try {
|
|
104
|
+
console.log('[hmr-client] Initializing Angular HMR shims');
|
|
105
|
+
}
|
|
106
|
+
catch { }
|
|
107
|
+
}
|
|
56
108
|
installAngularHmrClientHooks();
|
|
57
109
|
break;
|
|
58
110
|
}
|
|
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
|
+
}
|
|
59
297
|
// Track whether we've mounted an initial app root yet in HTTP-only boot
|
|
60
298
|
let initialMounted = !!globalThis.__NS_HMR_BOOT_COMPLETE__;
|
|
61
299
|
// Prevent duplicate initial-mount scheduling across rapid full-graph broadcasts and re-evaluations
|
|
@@ -65,7 +303,6 @@ let tsModuleSet = null;
|
|
|
65
303
|
let tsMainId = null;
|
|
66
304
|
const changedQueue = [];
|
|
67
305
|
let processingQueue = false;
|
|
68
|
-
let processingPromise = null;
|
|
69
306
|
// Detect whether the early placeholder root is still active on screen
|
|
70
307
|
function isPlaceholderActive() {
|
|
71
308
|
try {
|
|
@@ -607,6 +844,7 @@ function __nsNavigateUsingApp(comp, opts = {}) {
|
|
|
607
844
|
if (typeof GApp?.resetRootView === 'function' && typeof F === 'function') {
|
|
608
845
|
GApp.resetRootView({
|
|
609
846
|
create: () => {
|
|
847
|
+
var _a;
|
|
610
848
|
const fr = new F();
|
|
611
849
|
const navEntry = {
|
|
612
850
|
create: () => buildTarget(),
|
|
@@ -617,7 +855,19 @@ function __nsNavigateUsingApp(comp, opts = {}) {
|
|
|
617
855
|
fr.navigate(navEntry);
|
|
618
856
|
}
|
|
619
857
|
catch { }
|
|
858
|
+
try {
|
|
859
|
+
attachDiagnosticsToFrame(fr);
|
|
860
|
+
}
|
|
861
|
+
catch { }
|
|
620
862
|
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 { }
|
|
621
871
|
return fr;
|
|
622
872
|
},
|
|
623
873
|
});
|
|
@@ -625,8 +875,28 @@ function __nsNavigateUsingApp(comp, opts = {}) {
|
|
|
625
875
|
}
|
|
626
876
|
throw new Error('Application.resetRootView unavailable');
|
|
627
877
|
}
|
|
878
|
+
try {
|
|
879
|
+
attachDiagnosticsToFrame(frame);
|
|
880
|
+
}
|
|
881
|
+
catch { }
|
|
628
882
|
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 { }
|
|
629
889
|
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 { }
|
|
630
900
|
return undefined;
|
|
631
901
|
}
|
|
632
902
|
// Expose deterministic app navigation globally so /ns/rt can guarantee single-path navigation
|
|
@@ -644,81 +914,77 @@ async function processQueue() {
|
|
|
644
914
|
}
|
|
645
915
|
catch { }
|
|
646
916
|
}, 150);
|
|
647
|
-
return
|
|
917
|
+
return;
|
|
648
918
|
}
|
|
649
919
|
if (processingQueue)
|
|
650
|
-
return
|
|
920
|
+
return;
|
|
651
921
|
processingQueue = true;
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
922
|
+
try {
|
|
923
|
+
// Simple deterministic drain of the queue. We currently focus on TS flavor
|
|
924
|
+
// by re-importing changed modules (to refresh their HTTP ESM copies) and
|
|
925
|
+
// then performing a root reset so the UI reflects the new code.
|
|
926
|
+
const seen = new Set();
|
|
927
|
+
const drained = [];
|
|
928
|
+
while (changedQueue.length) {
|
|
929
|
+
const id = changedQueue.shift();
|
|
930
|
+
if (!id || typeof id !== 'string')
|
|
931
|
+
continue;
|
|
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)
|
|
664
947
|
continue;
|
|
665
|
-
|
|
666
|
-
|
|
948
|
+
if (VERBOSE)
|
|
949
|
+
console.log('[hmr][queue] re-import', { id, spec, url });
|
|
950
|
+
await import(/* @vite-ignore */ url);
|
|
667
951
|
}
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
952
|
+
catch (e) {
|
|
953
|
+
if (VERBOSE)
|
|
954
|
+
console.warn('[hmr][queue] re-import failed for', id, e);
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
// After evaluating the batch, perform flavor-specific UI refresh.
|
|
958
|
+
switch (__NS_TARGET_FLAVOR__) {
|
|
959
|
+
case 'vue':
|
|
960
|
+
// Vue SFCs are handled via the registry update path; nothing to do here.
|
|
961
|
+
break;
|
|
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`.
|
|
674
966
|
try {
|
|
675
|
-
const
|
|
676
|
-
const
|
|
677
|
-
if (!
|
|
678
|
-
|
|
967
|
+
const g = globalThis;
|
|
968
|
+
const App = getCore('Application') || g.Application;
|
|
969
|
+
if (!App || typeof App.resetRootView !== 'function') {
|
|
970
|
+
if (VERBOSE)
|
|
971
|
+
console.warn('[hmr][queue] TS flavor: Application.resetRootView unavailable; skipping UI refresh');
|
|
972
|
+
break;
|
|
973
|
+
}
|
|
679
974
|
if (VERBOSE)
|
|
680
|
-
console.log('[hmr][queue]
|
|
681
|
-
|
|
975
|
+
console.log('[hmr][queue] TS flavor: resetRootView(app-root) after changes');
|
|
976
|
+
App.resetRootView({ moduleName: 'app-root' });
|
|
682
977
|
}
|
|
683
978
|
catch (e) {
|
|
684
|
-
|
|
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;
|
|
979
|
+
console.warn('[hmr][queue] TS flavor: resetRootView(app-root) failed', e);
|
|
713
980
|
}
|
|
981
|
+
break;
|
|
714
982
|
}
|
|
715
983
|
}
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
})();
|
|
721
|
-
return processingPromise;
|
|
984
|
+
}
|
|
985
|
+
finally {
|
|
986
|
+
processingQueue = false;
|
|
987
|
+
}
|
|
722
988
|
}
|
|
723
989
|
let hmrSocket = null;
|
|
724
990
|
// Track server-announced batches for each version so we can import in-order client-side
|
|
@@ -874,77 +1140,12 @@ async function handleHmrMessage(ev) {
|
|
|
874
1140
|
catch {
|
|
875
1141
|
return;
|
|
876
1142
|
}
|
|
877
|
-
|
|
878
|
-
|
|
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
|
-
}
|
|
1143
|
+
if (VERBOSE)
|
|
1144
|
+
console.log('[hmr-client] msg', msg);
|
|
887
1145
|
if (msg) {
|
|
888
1146
|
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);
|
|
897
1147
|
setGraphVersion(Number(msg.version || getGraphVersion() || 0));
|
|
898
1148
|
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);
|
|
948
1149
|
return;
|
|
949
1150
|
}
|
|
950
1151
|
if (msg.type === 'ns:ts-module-registry') {
|
|
@@ -975,12 +1176,7 @@ async function handleHmrMessage(ev) {
|
|
|
975
1176
|
return;
|
|
976
1177
|
}
|
|
977
1178
|
if (msg.type === 'ns:hmr-delta') {
|
|
978
|
-
|
|
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 { }
|
|
1179
|
+
setGraphVersion(Number(msg.newVersion || getGraphVersion() || 0));
|
|
984
1180
|
try {
|
|
985
1181
|
const ids = Array.isArray(msg.changed) ? msg.changed.map((c) => c?.id).filter(Boolean) : [];
|
|
986
1182
|
if (ids.length)
|
|
@@ -988,14 +1184,6 @@ async function handleHmrMessage(ev) {
|
|
|
988
1184
|
}
|
|
989
1185
|
catch { }
|
|
990
1186
|
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);
|
|
999
1187
|
return;
|
|
1000
1188
|
}
|
|
1001
1189
|
else if (handleAngularHotUpdateMessage(msg, { getCore, verbose: VERBOSE })) {
|
|
@@ -1109,6 +1297,25 @@ async function performResetRoot(newComponent) {
|
|
|
1109
1297
|
ensureCoreAliasesOnGlobalThis();
|
|
1110
1298
|
}
|
|
1111
1299
|
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
|
+
}
|
|
1112
1319
|
if (VERBOSE) {
|
|
1113
1320
|
console.log('[hmr-client] Single-path: replace current root Page');
|
|
1114
1321
|
console.log('[hmr-client] Component details:', {
|
|
@@ -1315,6 +1522,12 @@ async function performResetRoot(newComponent) {
|
|
|
1315
1522
|
const isAuthoritativeFrame = !!existingAppFrame && existingAppFrame !== placeholderFrame;
|
|
1316
1523
|
if (!hadPlaceholder && !isFrameRoot && isAuthoritativeFrame && typeof existingAppFrame.navigate === 'function') {
|
|
1317
1524
|
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 { }
|
|
1318
1531
|
const navEntry = {
|
|
1319
1532
|
create: () => preparedRoot,
|
|
1320
1533
|
clearHistory: true,
|
|
@@ -1384,6 +1597,7 @@ async function performResetRoot(newComponent) {
|
|
|
1384
1597
|
// Use the previously created preparedRoot
|
|
1385
1598
|
const entry = {
|
|
1386
1599
|
create: () => {
|
|
1600
|
+
var _a, _b;
|
|
1387
1601
|
if (!isFrameRoot) {
|
|
1388
1602
|
const F = getCore('Frame');
|
|
1389
1603
|
const fr = new F();
|
|
@@ -1398,30 +1612,68 @@ async function performResetRoot(newComponent) {
|
|
|
1398
1612
|
};
|
|
1399
1613
|
try {
|
|
1400
1614
|
fr.navigate(navEntry);
|
|
1615
|
+
if (VERBOSE)
|
|
1616
|
+
console.log('[hmr-client] resetRootView:create navigated Frame');
|
|
1401
1617
|
}
|
|
1402
1618
|
catch (e) {
|
|
1403
1619
|
console.warn('[hmr-client] resetRootView:create navigate failed', e);
|
|
1404
1620
|
}
|
|
1621
|
+
try {
|
|
1622
|
+
attachDiagnosticsToFrame(fr);
|
|
1623
|
+
}
|
|
1624
|
+
catch { }
|
|
1405
1625
|
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 { }
|
|
1406
1634
|
return fr;
|
|
1407
1635
|
}
|
|
1408
1636
|
else {
|
|
1409
1637
|
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 { }
|
|
1410
1644
|
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 { }
|
|
1411
1653
|
return fr;
|
|
1412
1654
|
}
|
|
1413
1655
|
},
|
|
1414
1656
|
};
|
|
1657
|
+
if (VERBOSE)
|
|
1658
|
+
console.log('[hmr-client] invoking Application.resetRootView with entry (always)', { isFrameRoot, hadPlaceholder, isIOS });
|
|
1415
1659
|
// Always use an entry with a create() function to avoid cross‑realm instanceof checks on Android.
|
|
1416
1660
|
App2.resetRootView(entry);
|
|
1417
1661
|
// After authoritative reset, it's safe to detach the early placeholder launch handler
|
|
1418
1662
|
try {
|
|
1419
1663
|
const restore = globalThis.__NS_DEV_RESTORE_PLACEHOLDER__;
|
|
1420
1664
|
if (typeof restore === 'function') {
|
|
1665
|
+
if (VERBOSE)
|
|
1666
|
+
console.log('[hmr-client] restoring: detach early placeholder launch handler');
|
|
1421
1667
|
restore();
|
|
1422
1668
|
}
|
|
1423
1669
|
}
|
|
1424
1670
|
catch { }
|
|
1671
|
+
if (VERBOSE) {
|
|
1672
|
+
logUiSnapshot('post-resetRootView');
|
|
1673
|
+
console.log('[hmr-client] performResetRoot completed', {
|
|
1674
|
+
elapsedMs: Date.now() - tStart,
|
|
1675
|
+
});
|
|
1676
|
+
}
|
|
1425
1677
|
return true;
|
|
1426
1678
|
}
|
|
1427
1679
|
catch (e) {
|