@nativescript/vite 0.0.1-alpha.1 → 0.0.1-alpha.3
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/dist/configuration/base.js +135 -37
- package/dist/helpers/external-configs.js +1 -1
- package/dist/helpers/global-defines.d.ts +1 -0
- package/dist/helpers/global-defines.js +2 -0
- package/dist/helpers/main-entry-hmr-includes.d.ts +1 -0
- package/dist/helpers/main-entry-hmr-includes.js +18 -0
- package/dist/helpers/main-entry.d.ts +3 -3
- package/dist/helpers/main-entry.js +59 -95
- package/dist/helpers/module-runner-patch.d.ts +3 -0
- package/dist/helpers/module-runner-patch.js +65 -0
- package/dist/helpers/ns-cli-plugins.d.ts +1 -14
- package/dist/helpers/ns-cli-plugins.js +54 -107
- package/dist/helpers/package-platform-aliases.d.ts +1 -1
- package/dist/helpers/package-platform-aliases.js +4 -4
- package/dist/helpers/ts-config-paths.d.ts +1 -1
- package/dist/helpers/ts-config-paths.js +3 -3
- package/dist/hmr/client-vue.d.ts +6 -0
- package/dist/hmr/client-vue.js +563 -0
- package/dist/hmr/component-tracker.d.ts +23 -0
- package/dist/hmr/component-tracker.js +193 -0
- package/dist/hmr/css-handler.d.ts +4 -0
- package/dist/hmr/css-handler.js +77 -0
- package/dist/hmr/message-handler.d.ts +1 -0
- package/dist/hmr/message-handler.js +590 -0
- package/dist/hmr/nsv-hooks.d.ts +2 -0
- package/dist/hmr/nsv-hooks.js +481 -0
- package/dist/hmr/plugin-vue.d.ts +2 -0
- package/dist/hmr/plugin-vue.js +38 -0
- package/dist/hmr/plugins/index.d.ts +1 -0
- package/dist/hmr/plugins/index.js +16 -0
- package/dist/hmr/plugins/plugin-vue.d.ts +2 -0
- package/dist/hmr/plugins/plugin-vue.js +41 -0
- package/dist/hmr/plugins/websocket-vue.d.ts +2 -0
- package/dist/hmr/plugins/websocket-vue.js +882 -0
- package/dist/hmr/runtime-vue.d.ts +13 -0
- package/dist/hmr/runtime-vue.js +2306 -0
- package/dist/hmr/types.d.ts +24 -0
- package/dist/hmr/types.js +2 -0
- package/dist/hmr/websocket-vue.d.ts +2 -0
- package/dist/hmr/websocket-vue.js +875 -0
- package/dist/shims/node-module.d.ts +5 -0
- package/dist/shims/node-module.js +12 -0
- package/package.json +2 -1
- package/dist/configuration/old-without-merge-base.d.ts +0 -13
- package/dist/configuration/old-without-merge-base.js +0 -249
- package/dist/helpers/side-effects.d.ts +0 -14
- package/dist/helpers/side-effects.js +0 -69
- package/dist/hmr/hmr-angular.d.ts +0 -1
- package/dist/hmr/hmr-angular.js +0 -34
- package/dist/hmr/hmr-bridge.d.ts +0 -18
- package/dist/hmr/hmr-bridge.js +0 -154
- package/dist/hmr/hmr-client.d.ts +0 -5
- package/dist/hmr/hmr-client.js +0 -93
- package/dist/hmr/hmr-server.d.ts +0 -20
- package/dist/hmr/hmr-server.js +0 -179
|
@@ -0,0 +1,590 @@
|
|
|
1
|
+
// Message handling and routing
|
|
2
|
+
import { handleCssUpdates, handleCustomCss } from './css-handler';
|
|
3
|
+
import { ensureVueHMRRuntimeEnhanced } from './runtime-vue';
|
|
4
|
+
import { setupNativeScriptVueHooks } from './nsv-hooks';
|
|
5
|
+
const VERBOSE = !!globalThis.__NS_ENV_VERBOSE__;
|
|
6
|
+
export function handleMessage(data, httpOrigin) {
|
|
7
|
+
let message;
|
|
8
|
+
try {
|
|
9
|
+
message = JSON.parse(data);
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
if (VERBOSE) {
|
|
15
|
+
console.info('[ns-hmr] Received message:', {
|
|
16
|
+
type: message.type,
|
|
17
|
+
event: message.event,
|
|
18
|
+
hasData: !!message.data,
|
|
19
|
+
hasUpdates: !!message.updates,
|
|
20
|
+
dataKeys: message.data ? Object.keys(message.data) : []
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
// Handle custom CSS events for live apply
|
|
24
|
+
if (message.type === 'custom' && message.event === 'ns:css' && message.data) {
|
|
25
|
+
try {
|
|
26
|
+
const cssText = message.data.css;
|
|
27
|
+
handleCustomCss(cssText);
|
|
28
|
+
}
|
|
29
|
+
catch (e) {
|
|
30
|
+
console.warn('[ns-hmr] Custom CSS apply failed:', e?.message || String(e));
|
|
31
|
+
}
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
// Handle Vue SFC template rerender payloads from the server
|
|
35
|
+
if (message.type === 'custom' && message.event === 'ns:vue-template' && message.data) {
|
|
36
|
+
try {
|
|
37
|
+
const payload = message.data;
|
|
38
|
+
if (!payload?.src)
|
|
39
|
+
return;
|
|
40
|
+
// Proactively ensure NS-Vue hooks are applied so instances are registered
|
|
41
|
+
try {
|
|
42
|
+
const g = globalThis;
|
|
43
|
+
if (!g.__NS_VUE_HOOKS_APPLIED__) {
|
|
44
|
+
if (VERBOSE)
|
|
45
|
+
console.info('[ns-hmr] NS-Vue hooks not applied before vue-template; applying now');
|
|
46
|
+
setupNativeScriptVueHooks();
|
|
47
|
+
try {
|
|
48
|
+
if (VERBOSE)
|
|
49
|
+
console.info('[ns-hmr] Applied NS-Vue hooks on-demand for vue-template; flag now:', !!g.__NS_VUE_HOOKS_APPLIED__);
|
|
50
|
+
}
|
|
51
|
+
catch { }
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
catch { }
|
|
55
|
+
try {
|
|
56
|
+
const idsPreview = Array.isArray(payload.ids) ? payload.ids.join(', ') : (payload.id || '(none)');
|
|
57
|
+
console.info('[ns-hmr] ns:vue-template received; ids:', idsPreview);
|
|
58
|
+
}
|
|
59
|
+
catch { }
|
|
60
|
+
applyVueTemplateRerender(payload);
|
|
61
|
+
}
|
|
62
|
+
catch (e) {
|
|
63
|
+
console.warn('[ns-hmr] Vue template apply failed:', e?.message || String(e));
|
|
64
|
+
}
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
// Disable ad-hoc Vue code delivery to favor Vite ModuleRunner path
|
|
68
|
+
if (message.type === 'custom' && message.event === 'ns:vue-component' && message.data) {
|
|
69
|
+
if (VERBOSE)
|
|
70
|
+
console.info('[ns-hmr] Ignoring ns:vue-component (prefer standard Vite update)');
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
// Ignore custom file-changed for Vue and rely on standard Vite update payloads
|
|
74
|
+
if (message.type === 'custom' && message.event === 'file-changed' && message.data && message.data.file) {
|
|
75
|
+
const filePath = String(message.data.file || '');
|
|
76
|
+
if (/\.vue(\?|$)/.test(filePath)) {
|
|
77
|
+
if (VERBOSE)
|
|
78
|
+
console.info('[ns-hmr] Ignoring custom file-changed for .vue; waiting for Vite update');
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
// For non-vue, nothing to do here
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
// Handle Vite update events
|
|
85
|
+
if (message.type === 'update' && Array.isArray(message.updates)) {
|
|
86
|
+
// Handle CSS updates
|
|
87
|
+
const cssUpdates = message.updates.filter((u) => u && u.type === 'css-update');
|
|
88
|
+
if (cssUpdates.length) {
|
|
89
|
+
handleCssUpdates(cssUpdates, httpOrigin);
|
|
90
|
+
}
|
|
91
|
+
// Handle Vue updates by delegating to the ModuleRunner-based client.
|
|
92
|
+
handleUpdateEvents(message.updates);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
function handleUpdateEvents(updates) {
|
|
96
|
+
let handledVueUpdates = 0;
|
|
97
|
+
if (VERBOSE)
|
|
98
|
+
console.info('[ns-hmr] Processing updates:', updates.length);
|
|
99
|
+
for (const update of updates) {
|
|
100
|
+
const path = update.path || update.acceptedPath || '';
|
|
101
|
+
if (VERBOSE)
|
|
102
|
+
console.info('[ns-hmr] Checking update:', { path, type: update.type });
|
|
103
|
+
// Enhanced Vue update detection
|
|
104
|
+
if (isVueUpdate(path, update)) {
|
|
105
|
+
if (VERBOSE)
|
|
106
|
+
console.info('[ns-hmr] Identified as Vue update:', path);
|
|
107
|
+
// Defer to Vite ModuleRunner-based client (built into dist runtime) to apply .vue HMR
|
|
108
|
+
// Avoid triggering our manual fallback which can cause restart.
|
|
109
|
+
handledVueUpdates++;
|
|
110
|
+
if (VERBOSE)
|
|
111
|
+
console.info('[ns-hmr] Delegating .vue update to ModuleRunner pipeline');
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
if (VERBOSE)
|
|
115
|
+
console.info('[ns-hmr] Not a Vue update:', path);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
if (VERBOSE)
|
|
119
|
+
console.info(`[ns-hmr] Handled ${handledVueUpdates} Vue update(s)`);
|
|
120
|
+
}
|
|
121
|
+
function isVueUpdate(path, update) {
|
|
122
|
+
// Check for .vue files
|
|
123
|
+
if (/\.vue(\?|$)/.test(path)) {
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
// Check for Vue-related query parameters that indicate Vue SFC parts
|
|
127
|
+
if (path.includes('vue&type=')) {
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
130
|
+
// Check update type for Vue-specific updates
|
|
131
|
+
if (update.type === 'vue-reload' || update.type === 'vue-rerender') {
|
|
132
|
+
return true;
|
|
133
|
+
}
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
// Note: Custom Vue update helpers removed. We intentionally rely on Vite's
|
|
137
|
+
// standard 'update' flow handled by the ModuleRunner in the full runtime client.
|
|
138
|
+
function applyVueTemplateRerender(payload) {
|
|
139
|
+
const g = globalThis;
|
|
140
|
+
// Try to ensure Vue HMR runtime is present/enhanced before we proceed
|
|
141
|
+
const runtime = ensureVueHMRRuntimeEnhanced() || g.__VUE_HMR_RUNTIME__;
|
|
142
|
+
const hasRuntime = !!(runtime && typeof runtime.rerender === 'function');
|
|
143
|
+
if (!hasRuntime) {
|
|
144
|
+
console.info('[ns-hmr] Vue HMR runtime not ready; will attempt direct instance patch and retry later');
|
|
145
|
+
// Cache and retry a few times in case runtime appears after startup
|
|
146
|
+
try {
|
|
147
|
+
g.__NS_LAST_VUE_TEMPLATE__ = payload;
|
|
148
|
+
scheduleVueTemplateRetry(payload, 5);
|
|
149
|
+
}
|
|
150
|
+
catch { }
|
|
151
|
+
}
|
|
152
|
+
try {
|
|
153
|
+
// Build a function in a sandbox with helpers bound to NS-Vue/Vue exports
|
|
154
|
+
const vueBase = safeRequire('vue') || {};
|
|
155
|
+
const nsvBase = safeRequire('nativescript-vue') || {};
|
|
156
|
+
// Merge to prefer NS-Vue overrides but fill missing helpers from Vue
|
|
157
|
+
const nsVue = Object.assign({}, vueBase, nsvBase);
|
|
158
|
+
// Ensure common helper aliases exist on the object (underscore vs non-underscore and synonyms)
|
|
159
|
+
const aliasPairs = [
|
|
160
|
+
// underscore <-> plain
|
|
161
|
+
['_resolveComponent', 'resolveComponent'],
|
|
162
|
+
['_openBlock', 'openBlock'],
|
|
163
|
+
['_createBlock', 'createBlock'],
|
|
164
|
+
['_createElementBlock', 'createElementBlock'],
|
|
165
|
+
['_createVNode', 'createVNode'],
|
|
166
|
+
['_createElementVNode', 'createElementVNode'],
|
|
167
|
+
['_toDisplayString', 'toDisplayString'],
|
|
168
|
+
['_withCtx', 'withCtx'],
|
|
169
|
+
['_unref', 'unref'],
|
|
170
|
+
['_Fragment', 'Fragment'],
|
|
171
|
+
['_createTextVNode', 'createTextVNode'],
|
|
172
|
+
];
|
|
173
|
+
const synonymPairs = [
|
|
174
|
+
// createElementBlock <-> createBlock
|
|
175
|
+
['createElementBlock', 'createBlock'],
|
|
176
|
+
['createElementVNode', 'createVNode'],
|
|
177
|
+
];
|
|
178
|
+
const appliedShims = [];
|
|
179
|
+
const ensureAlias = (to, from) => {
|
|
180
|
+
try {
|
|
181
|
+
if (typeof nsVue[to] === 'undefined' && typeof nsVue[from] !== 'undefined') {
|
|
182
|
+
nsVue[to] = nsVue[from];
|
|
183
|
+
appliedShims.push({ to, from });
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
catch { }
|
|
187
|
+
};
|
|
188
|
+
// 1) Fill underscore/plain in both directions
|
|
189
|
+
for (const [a, b] of aliasPairs) {
|
|
190
|
+
ensureAlias(a, b);
|
|
191
|
+
ensureAlias(b, a);
|
|
192
|
+
}
|
|
193
|
+
// 2) Fill synonyms
|
|
194
|
+
for (const [a, b] of synonymPairs) {
|
|
195
|
+
ensureAlias(a, b);
|
|
196
|
+
ensureAlias(b, a);
|
|
197
|
+
// Also cover underscore variants for synonyms
|
|
198
|
+
ensureAlias(`_${a}`, `_${b}`);
|
|
199
|
+
ensureAlias(`_${b}`, `_${a}`);
|
|
200
|
+
}
|
|
201
|
+
if (VERBOSE && appliedShims.length) {
|
|
202
|
+
try {
|
|
203
|
+
console.info('[ns-hmr] Applied helper shims:', appliedShims);
|
|
204
|
+
}
|
|
205
|
+
catch { }
|
|
206
|
+
}
|
|
207
|
+
// As a last resort, provide a shim for resolveComponent from the running app context
|
|
208
|
+
const getAppComponent = (n) => {
|
|
209
|
+
try {
|
|
210
|
+
const app = globalThis.__NS_VUE_APP__;
|
|
211
|
+
// Vue 3 app context registry
|
|
212
|
+
const c1 = app && app._context && app._context.components && app._context.components[n];
|
|
213
|
+
if (c1)
|
|
214
|
+
return c1;
|
|
215
|
+
// Some runtimes might store registered components under app.component registry
|
|
216
|
+
const c2 = app && app.component && app.component(n);
|
|
217
|
+
if (c2)
|
|
218
|
+
return c2;
|
|
219
|
+
// Try via root instance appContext
|
|
220
|
+
const root = globalThis.__NS_VUE_ROOT_INSTANCE__;
|
|
221
|
+
const internal = root && (root.$ || root);
|
|
222
|
+
const appCtx = internal && (internal.appContext || internal.app?._context);
|
|
223
|
+
const c3 = appCtx && appCtx.components && appCtx.components[n];
|
|
224
|
+
if (c3)
|
|
225
|
+
return c3;
|
|
226
|
+
}
|
|
227
|
+
catch { }
|
|
228
|
+
return null;
|
|
229
|
+
};
|
|
230
|
+
const shimResolve = (name) => {
|
|
231
|
+
const comp = getAppComponent(name);
|
|
232
|
+
if (VERBOSE) {
|
|
233
|
+
try {
|
|
234
|
+
console.info('[ns-hmr] shim resolveComponent', { name, found: !!comp, type: comp ? typeof comp : 'null' });
|
|
235
|
+
}
|
|
236
|
+
catch { }
|
|
237
|
+
}
|
|
238
|
+
// Return component if found, otherwise fall back to name (some renderers handle string types)
|
|
239
|
+
return comp || name;
|
|
240
|
+
};
|
|
241
|
+
if (typeof nsVue.resolveComponent !== 'function' && typeof nsVue._resolveComponent !== 'function') {
|
|
242
|
+
nsVue.resolveComponent = shimResolve;
|
|
243
|
+
nsVue._resolveComponent = shimResolve;
|
|
244
|
+
}
|
|
245
|
+
else if (typeof nsVue.resolveComponent !== 'function' && typeof nsVue._resolveComponent === 'function') {
|
|
246
|
+
nsVue.resolveComponent = nsVue._resolveComponent;
|
|
247
|
+
}
|
|
248
|
+
else if (typeof nsVue._resolveComponent !== 'function' && typeof nsVue.resolveComponent === 'function') {
|
|
249
|
+
nsVue._resolveComponent = nsVue.resolveComponent;
|
|
250
|
+
}
|
|
251
|
+
// Minimal safe fallbacks for helpers to prevent runtime aborts
|
|
252
|
+
const appliedFallbacks = [];
|
|
253
|
+
const ensureFunc = (key, fn) => {
|
|
254
|
+
try {
|
|
255
|
+
if (typeof nsVue[key] !== 'function') {
|
|
256
|
+
nsVue[key] = fn;
|
|
257
|
+
appliedFallbacks.push(key);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
catch { }
|
|
261
|
+
};
|
|
262
|
+
// Base creators using either Vue's createVNode or h
|
|
263
|
+
const baseCreateVNode = nsVue.createVNode || nsVue._createVNode || nsVue.h || null;
|
|
264
|
+
const createVNodeLike = (type, props, children) => {
|
|
265
|
+
try {
|
|
266
|
+
if (typeof nsVue.createVNode === 'function')
|
|
267
|
+
return nsVue.createVNode(type, props, children);
|
|
268
|
+
if (typeof nsVue._createVNode === 'function')
|
|
269
|
+
return nsVue._createVNode(type, props, children);
|
|
270
|
+
if (typeof nsVue.h === 'function')
|
|
271
|
+
return nsVue.h(type, props, children);
|
|
272
|
+
}
|
|
273
|
+
catch { }
|
|
274
|
+
return { type, props: props || null, children };
|
|
275
|
+
};
|
|
276
|
+
const createTextVNodeLike = (text) => {
|
|
277
|
+
try {
|
|
278
|
+
if (typeof nsVue.createTextVNode === 'function')
|
|
279
|
+
return nsVue.createTextVNode(text);
|
|
280
|
+
if (typeof nsVue._createTextVNode === 'function')
|
|
281
|
+
return nsVue._createTextVNode(text);
|
|
282
|
+
// Fallback: wrap string children; many renderers accept plain strings as children
|
|
283
|
+
}
|
|
284
|
+
catch { }
|
|
285
|
+
return String(text);
|
|
286
|
+
};
|
|
287
|
+
ensureFunc('_openBlock', () => { });
|
|
288
|
+
ensureFunc('openBlock', () => { });
|
|
289
|
+
ensureFunc('_withCtx', (fn) => fn);
|
|
290
|
+
ensureFunc('withCtx', (fn) => fn);
|
|
291
|
+
ensureFunc('_createVNode', createVNodeLike);
|
|
292
|
+
ensureFunc('createVNode', createVNodeLike);
|
|
293
|
+
ensureFunc('_createElementVNode', createVNodeLike);
|
|
294
|
+
ensureFunc('createElementVNode', createVNodeLike);
|
|
295
|
+
ensureFunc('_createBlock', createVNodeLike);
|
|
296
|
+
ensureFunc('createBlock', createVNodeLike);
|
|
297
|
+
ensureFunc('_createElementBlock', createVNodeLike);
|
|
298
|
+
ensureFunc('createElementBlock', createVNodeLike);
|
|
299
|
+
ensureFunc('_createTextVNode', createTextVNodeLike);
|
|
300
|
+
ensureFunc('createTextVNode', createTextVNodeLike);
|
|
301
|
+
ensureFunc('_toDisplayString', (v) => {
|
|
302
|
+
try {
|
|
303
|
+
return nsVue.toDisplayString ? nsVue.toDisplayString(v) : String(v);
|
|
304
|
+
}
|
|
305
|
+
catch {
|
|
306
|
+
return String(v);
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
ensureFunc('toDisplayString', (v) => {
|
|
310
|
+
try {
|
|
311
|
+
return nsVue.toDisplayString ? nsVue.toDisplayString(v) : String(v);
|
|
312
|
+
}
|
|
313
|
+
catch {
|
|
314
|
+
return String(v);
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
ensureFunc('_unref', (v) => (v && typeof v === 'object' && 'value' in v ? v.value : v));
|
|
318
|
+
ensureFunc('unref', (v) => (v && typeof v === 'object' && 'value' in v ? v.value : v));
|
|
319
|
+
if (appliedFallbacks.length) {
|
|
320
|
+
try {
|
|
321
|
+
console.info('[ns-hmr] Applied helper fallbacks:', appliedFallbacks);
|
|
322
|
+
}
|
|
323
|
+
catch { }
|
|
324
|
+
}
|
|
325
|
+
// Log helper presence/types for critical helpers
|
|
326
|
+
try {
|
|
327
|
+
const keys = ['_resolveComponent', 'resolveComponent', '_openBlock', 'openBlock', '_createBlock', 'createBlock', '_createElementBlock', 'createElementBlock', '_createVNode', 'createVNode', '_createElementVNode', 'createElementVNode', '_withCtx', 'withCtx', '_unref', 'unref', '_createTextVNode', 'createTextVNode'];
|
|
328
|
+
const status = {};
|
|
329
|
+
for (const k of keys) {
|
|
330
|
+
const v = nsVue[k];
|
|
331
|
+
status[k] = typeof v;
|
|
332
|
+
}
|
|
333
|
+
console.info('[ns-hmr] Helper status:', status);
|
|
334
|
+
}
|
|
335
|
+
catch { }
|
|
336
|
+
// Enumerate available helper function names so we see clearly what's in scope
|
|
337
|
+
try {
|
|
338
|
+
const allKeys = Object.keys(nsVue).sort();
|
|
339
|
+
const funcKeys = allKeys.filter((k) => typeof nsVue[k] === 'function');
|
|
340
|
+
const underscoredCount = funcKeys.filter((k) => k.startsWith('_')).length;
|
|
341
|
+
const sample = funcKeys.slice(0, 80);
|
|
342
|
+
console.info('[ns-hmr] NSVUE function keys (sample):', { count: funcKeys.length, underscoredCount, sample });
|
|
343
|
+
}
|
|
344
|
+
catch { }
|
|
345
|
+
const helperNames = Array.isArray(payload.helpers) ? payload.helpers : [];
|
|
346
|
+
const localNames = Array.isArray(payload.locals) && payload.locals.length === helperNames.length ? payload.locals : helperNames;
|
|
347
|
+
try {
|
|
348
|
+
console.info('[ns-hmr] Payload expected helpers:', helperNames);
|
|
349
|
+
}
|
|
350
|
+
catch { }
|
|
351
|
+
// Generate declarations for each helper alias to avoid using dynamic argument names
|
|
352
|
+
const decls = [];
|
|
353
|
+
const missing = [];
|
|
354
|
+
const presentDiag = [];
|
|
355
|
+
for (let i = 0; i < helperNames.length; i++) {
|
|
356
|
+
const orig = helperNames[i];
|
|
357
|
+
const local = localNames[i] || orig;
|
|
358
|
+
// Declare all locals to avoid ReferenceError during eval
|
|
359
|
+
// We bind to NSVUE[orig] at runtime; if missing, value will be undefined
|
|
360
|
+
decls.push(`const ${local} = NSVUE && Object.prototype.hasOwnProperty.call(NSVUE, ${JSON.stringify(orig)}) ? NSVUE[${JSON.stringify(orig)}] : undefined;`);
|
|
361
|
+
if (!(orig in nsVue))
|
|
362
|
+
missing.push(`${orig} as ${local}`);
|
|
363
|
+
else {
|
|
364
|
+
try {
|
|
365
|
+
presentDiag.push({ name: orig, local, typeof: typeof nsVue[orig] });
|
|
366
|
+
}
|
|
367
|
+
catch { }
|
|
368
|
+
}
|
|
369
|
+
// Also add an alias declaration for underscore/non-underscore variant if not the same
|
|
370
|
+
const altLocal = local.startsWith('_') ? local.slice(1) : ('_' + local);
|
|
371
|
+
if (altLocal !== local) {
|
|
372
|
+
decls.push(`const ${altLocal} = (typeof ${local} !== 'undefined') ? ${local} : (NSVUE && (NSVUE[${JSON.stringify(orig)}] ?? NSVUE[${JSON.stringify(altLocal.replace(/^_/, ''))}]));`);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
if (missing.length) {
|
|
376
|
+
if (VERBOSE)
|
|
377
|
+
console.info('[ns-hmr] Missing helpers in nativescript-vue:', missing.join(', '));
|
|
378
|
+
}
|
|
379
|
+
if (VERBOSE) {
|
|
380
|
+
try {
|
|
381
|
+
console.info('[ns-hmr] Helper bindings:', presentDiag);
|
|
382
|
+
}
|
|
383
|
+
catch { }
|
|
384
|
+
}
|
|
385
|
+
// Determine if payload.src already includes a full 'function render' or 'const render =' declaration
|
|
386
|
+
const hasFullRender = /\bfunction\s+render\s*\(|\bconst\s+render\s*=/.test(payload.src);
|
|
387
|
+
const lines = [
|
|
388
|
+
`'use strict';`,
|
|
389
|
+
...decls,
|
|
390
|
+
];
|
|
391
|
+
if (hasFullRender) {
|
|
392
|
+
lines.push(payload.src);
|
|
393
|
+
}
|
|
394
|
+
else {
|
|
395
|
+
lines.push(payload.src);
|
|
396
|
+
}
|
|
397
|
+
lines.push(`return render;`);
|
|
398
|
+
const body = lines.join('\n');
|
|
399
|
+
// Inspect tokens present in the body to know which helpers the render expects
|
|
400
|
+
try {
|
|
401
|
+
const tokenReport = {
|
|
402
|
+
hasResolveComponent: /\b_?resolveComponent\b/.test(body),
|
|
403
|
+
hasOpenBlock: /\b_?openBlock\b/.test(body),
|
|
404
|
+
hasCreateBlock: /\b_?create(Block|ElementBlock)\b/.test(body),
|
|
405
|
+
hasCreateVNode: /\b_?create(VNode|ElementVNode)\b/.test(body),
|
|
406
|
+
hasWithCtx: /\b_?withCtx\b/.test(body),
|
|
407
|
+
hasToDisplayString: /\b_?toDisplayString\b/.test(body),
|
|
408
|
+
};
|
|
409
|
+
console.info('[ns-hmr] Render token usage:', tokenReport);
|
|
410
|
+
}
|
|
411
|
+
catch { }
|
|
412
|
+
// Ensure critical helpers like resolveComponent exist
|
|
413
|
+
try {
|
|
414
|
+
if (typeof nsVue._resolveComponent === 'undefined' && typeof nsVue.resolveComponent === 'function') {
|
|
415
|
+
nsVue._resolveComponent = nsVue.resolveComponent.bind(nsVue);
|
|
416
|
+
}
|
|
417
|
+
if (typeof nsVue.resolveComponent === 'undefined' && typeof nsVue._resolveComponent === 'function') {
|
|
418
|
+
nsVue.resolveComponent = nsVue._resolveComponent.bind(nsVue);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
catch { }
|
|
422
|
+
const factory = new Function('NSVUE', body);
|
|
423
|
+
let newRender = factory(nsVue);
|
|
424
|
+
// If compile emitted a render that expects global helpers under different names, shim them
|
|
425
|
+
if (typeof newRender !== 'function') {
|
|
426
|
+
if (VERBOSE)
|
|
427
|
+
console.info('[ns-hmr] Evaluated render is not a function; aborting');
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
// Introspect the compiled render to confirm which helpers it will call
|
|
431
|
+
try {
|
|
432
|
+
const srcStr = Function.prototype.toString.call(newRender);
|
|
433
|
+
console.info('[ns-hmr] New render tokens:', {
|
|
434
|
+
len: srcStr.length,
|
|
435
|
+
openBlock: /\b_?openBlock\b/.test(srcStr),
|
|
436
|
+
createBlock: /\b_?create(Block|ElementBlock)\b/.test(srcStr),
|
|
437
|
+
resolveComponent: /\b_?resolveComponent\b/.test(srcStr),
|
|
438
|
+
withCtx: /\b_?withCtx\b/.test(srcStr),
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
catch { }
|
|
442
|
+
// If runtime is unavailable, cache and retry later to avoid direct instance patch side-effects
|
|
443
|
+
if (!hasRuntime && typeof newRender === 'function') {
|
|
444
|
+
try {
|
|
445
|
+
g.__NS_LAST_VUE_TEMPLATE__ = payload;
|
|
446
|
+
scheduleVueTemplateRetry(payload, 5);
|
|
447
|
+
}
|
|
448
|
+
catch { }
|
|
449
|
+
return;
|
|
450
|
+
}
|
|
451
|
+
// Build candidate ids with useful variations (with/without query, absolute/relative, with/without ?vue)
|
|
452
|
+
const baseIds = Array.isArray(payload.ids) && payload.ids.length ? payload.ids.slice() : (payload.id ? [payload.id] : []);
|
|
453
|
+
const candidatesSet = new Set();
|
|
454
|
+
const addVariants = (id) => {
|
|
455
|
+
if (!id)
|
|
456
|
+
return;
|
|
457
|
+
const norm = String(id).replace(/\\/g, '/');
|
|
458
|
+
const noQuery = norm.split('?')[0];
|
|
459
|
+
const withVueQ = noQuery + '?vue';
|
|
460
|
+
const relFromSrc = noQuery.replace(/^.*?\/src\//, '/src/');
|
|
461
|
+
const relNoLead = relFromSrc.replace(/^\//, '');
|
|
462
|
+
[norm, noQuery, withVueQ, relFromSrc, relNoLead, relNoLead + '?vue'].forEach((v) => v && candidatesSet.add(v));
|
|
463
|
+
};
|
|
464
|
+
baseIds.forEach(addVariants);
|
|
465
|
+
const candidates = Array.from(candidatesSet);
|
|
466
|
+
try {
|
|
467
|
+
console.info('[ns-hmr] id candidates ->', candidates);
|
|
468
|
+
}
|
|
469
|
+
catch { }
|
|
470
|
+
if (typeof newRender === 'function' && candidates.length) {
|
|
471
|
+
let applied = false;
|
|
472
|
+
// Use a more conservative approach: add delay and readiness checks
|
|
473
|
+
// This prevents the "entry.create" errors by ensuring native views are ready
|
|
474
|
+
const req = globalThis.require;
|
|
475
|
+
const vueMod = req && (() => { try {
|
|
476
|
+
return req('vue');
|
|
477
|
+
}
|
|
478
|
+
catch {
|
|
479
|
+
return null;
|
|
480
|
+
} })();
|
|
481
|
+
const nextTick = vueMod && vueMod.nextTick;
|
|
482
|
+
const doRerender = () => {
|
|
483
|
+
// Rerender-only for template changes; avoid partial reloads that can break component state
|
|
484
|
+
for (const id of candidates) {
|
|
485
|
+
try {
|
|
486
|
+
console.info('[ns-hmr] Attempting Vue template rerender for', id);
|
|
487
|
+
globalThis.__NS_LAST_RERENDER_ID__ = id;
|
|
488
|
+
runtime.rerender(id, newRender);
|
|
489
|
+
applied = true;
|
|
490
|
+
console.info('[ns-hmr] Applied Vue template rerender for', id);
|
|
491
|
+
break;
|
|
492
|
+
}
|
|
493
|
+
catch (e) {
|
|
494
|
+
console.info('[ns-hmr] Rerender attempt failed for', id, e?.message || String(e));
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
if (!applied) {
|
|
498
|
+
console.info('[ns-hmr] No matching Vue HMR record for ids:', candidates.join(', '));
|
|
499
|
+
// Fuzzy match: try to find a record id by suffix match against path
|
|
500
|
+
try {
|
|
501
|
+
const path = String(payload.path || '');
|
|
502
|
+
const base = path.split('?')[0].replace(/\\/g, '/');
|
|
503
|
+
const baseRel = base.replace(/^.*?\/src\//, '/src/');
|
|
504
|
+
const suffixes = Array.from(new Set([
|
|
505
|
+
baseRel,
|
|
506
|
+
baseRel + '?vue',
|
|
507
|
+
(baseRel || '').replace(/^\//, ''),
|
|
508
|
+
(baseRel || '').replace(/^\//, '') + '?vue',
|
|
509
|
+
(base.split('/').pop() || ''),
|
|
510
|
+
(base.split('/').pop() || '') + '?vue'
|
|
511
|
+
].filter(Boolean)));
|
|
512
|
+
const map = runtime.map || runtime.records || {};
|
|
513
|
+
const keys = map && typeof map.keys === 'function'
|
|
514
|
+
? Array.from(map.keys())
|
|
515
|
+
: (map && typeof map === 'object' ? Object.keys(map) : []);
|
|
516
|
+
try {
|
|
517
|
+
console.info('[ns-hmr] Vue HMR record keys:', keys);
|
|
518
|
+
}
|
|
519
|
+
catch { }
|
|
520
|
+
for (const key of keys) {
|
|
521
|
+
const k = String(key);
|
|
522
|
+
if (suffixes.some((s) => k.endsWith(s))) {
|
|
523
|
+
try {
|
|
524
|
+
console.info('[ns-hmr] Fuzzy match rerender for', k);
|
|
525
|
+
runtime.rerender(k, newRender);
|
|
526
|
+
applied = true;
|
|
527
|
+
console.info('[ns-hmr] Applied Vue template rerender for', k);
|
|
528
|
+
break;
|
|
529
|
+
}
|
|
530
|
+
catch (e) {
|
|
531
|
+
console.info('[ns-hmr] Fuzzy rerender failed for', k, e?.message || String(e));
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
catch { }
|
|
537
|
+
if (!applied) {
|
|
538
|
+
console.info('[ns-hmr] Could not find a matching Vue HMR record by fuzzy path; skipping direct instance patch (avoid double update)');
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
};
|
|
542
|
+
// Use nextTick if available to ensure proper timing
|
|
543
|
+
if (typeof nextTick === 'function') {
|
|
544
|
+
nextTick(() => {
|
|
545
|
+
// Add a small additional delay to let any pending native view operations complete
|
|
546
|
+
setTimeout(doRerender, 16);
|
|
547
|
+
});
|
|
548
|
+
}
|
|
549
|
+
else {
|
|
550
|
+
// Fallback with delay
|
|
551
|
+
setTimeout(doRerender, 32);
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
catch (e) {
|
|
556
|
+
console.warn('[ns-hmr] Failed to eval Vue template render:', e?.message || String(e));
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
function scheduleVueTemplateRetry(payload, attempts) {
|
|
560
|
+
const g = globalThis;
|
|
561
|
+
if (attempts <= 0)
|
|
562
|
+
return;
|
|
563
|
+
setTimeout(() => {
|
|
564
|
+
const rt = ensureVueHMRRuntimeEnhanced() || g.__VUE_HMR_RUNTIME__;
|
|
565
|
+
if (!rt || typeof rt.rerender !== 'function') {
|
|
566
|
+
console.info('[ns-hmr] Vue HMR runtime still not ready; attempts left:', attempts - 1);
|
|
567
|
+
scheduleVueTemplateRetry(payload, attempts - 1);
|
|
568
|
+
return;
|
|
569
|
+
}
|
|
570
|
+
try {
|
|
571
|
+
console.info('[ns-hmr] Retrying Vue template apply');
|
|
572
|
+
applyVueTemplateRerender(payload);
|
|
573
|
+
}
|
|
574
|
+
catch (e) {
|
|
575
|
+
console.info('[ns-hmr] Retry failed:', e?.message || String(e));
|
|
576
|
+
scheduleVueTemplateRetry(payload, attempts - 1);
|
|
577
|
+
}
|
|
578
|
+
}, 250);
|
|
579
|
+
}
|
|
580
|
+
// Direct instance patch removed to avoid interfering with Vue HMR scheduler
|
|
581
|
+
function safeRequire(name) {
|
|
582
|
+
try {
|
|
583
|
+
// In NativeScript runtime, require is available globally
|
|
584
|
+
const req = globalThis.require || null;
|
|
585
|
+
if (req)
|
|
586
|
+
return req(name);
|
|
587
|
+
}
|
|
588
|
+
catch { }
|
|
589
|
+
return null;
|
|
590
|
+
}
|