@nativescript/vite 8.0.0-alpha.16 → 8.0.0-alpha.18
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/helpers/main-entry.js +64 -2
- package/helpers/main-entry.js.map +1 -1
- package/hmr/client/index.js +7 -1
- package/hmr/client/index.js.map +1 -1
- package/hmr/helpers/ast-normalizer.js +7 -0
- package/hmr/helpers/ast-normalizer.js.map +1 -1
- package/hmr/helpers/package-exports.d.ts +16 -0
- package/hmr/helpers/package-exports.js +396 -0
- package/hmr/helpers/package-exports.js.map +1 -0
- package/hmr/server/ns-rt-bridge.d.ts +51 -0
- package/hmr/server/ns-rt-bridge.js +131 -0
- package/hmr/server/ns-rt-bridge.js.map +1 -0
- package/hmr/server/websocket.js +92 -161
- package/hmr/server/websocket.js.map +1 -1
- package/hmr/shared/runtime/root-placeholder.js +96 -56
- package/hmr/shared/runtime/root-placeholder.js.map +1 -1
- package/package.json +1 -1
- package/hmr/server/websocket-runtime-compat.d.ts +0 -19
- package/hmr/server/websocket-runtime-compat.js +0 -292
- package/hmr/server/websocket-runtime-compat.js.map +0 -1
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export interface NsRtBridgeOptions {
|
|
2
|
+
/** Version segment from `/ns/rt/<ver>`. Retained for the URL dispatcher; the bridge body intentionally ignores it. */
|
|
3
|
+
rtVer: string;
|
|
4
|
+
/** Prologue installed verbatim before the bridge body (typically the require URL guard). */
|
|
5
|
+
requireGuardSnippet: string;
|
|
6
|
+
/**
|
|
7
|
+
* The discovered ESM export names of the underlying vendor package
|
|
8
|
+
* (`nativescript-vue`, including its `@vue/runtime-core` re-export
|
|
9
|
+
* chain). Each name becomes `export const <name> = (__ensure().<name>);` —
|
|
10
|
+
* a single canonical specifier (`/ns/rt`) forwards *every* symbol the
|
|
11
|
+
* vendor publishes.
|
|
12
|
+
*
|
|
13
|
+
* Required: discovery is the only source of truth. There is no hand-curated
|
|
14
|
+
* fallback — if discovery cannot see the package, the bridge serves no
|
|
15
|
+
* passthroughs and the call site is expected to surface that as a config
|
|
16
|
+
* error rather than silently degrade.
|
|
17
|
+
*/
|
|
18
|
+
vendorExports: Iterable<string>;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Build the `/ns/rt` runtime bridge module text.
|
|
22
|
+
*
|
|
23
|
+
* Single-realm policy: every named export the vendor package publishes
|
|
24
|
+
* appears as `export const X = (__ensure().X);` — a constant binding, not a
|
|
25
|
+
* function wrapper. Constant bindings preserve identity for Vue's Symbol
|
|
26
|
+
* markers (`Fragment`, `Teleport`, …) AND work transparently for functions
|
|
27
|
+
* (`ref`, `createApp`, …) since the user code calls the underlying value
|
|
28
|
+
* directly. Calling `__ensure()` at module evaluation time is safe because
|
|
29
|
+
* the vendor bundle is registered earlier in the boot graph (vendor.mjs →
|
|
30
|
+
* `__nsVendorRegistry`), and the bridge resolves the same `nativescript-vue`
|
|
31
|
+
* record everyone else uses.
|
|
32
|
+
*
|
|
33
|
+
* HMR-specific shims (`$navigateTo`, `$navigateBack`, `$showModal`) and the
|
|
34
|
+
* Vite client polyfill (`vite__injectQuery`) are emitted as overrides that
|
|
35
|
+
* replace the would-be passthrough — those exports route through the HMR
|
|
36
|
+
* navigator instead of the vendor's native version, so the bridge must
|
|
37
|
+
* provide the override, not the discovered original.
|
|
38
|
+
*/
|
|
39
|
+
export declare function buildNsRtBridgeModule(options: NsRtBridgeOptions): string;
|
|
40
|
+
/**
|
|
41
|
+
* Resolve the set of names the bridge should re-export for `nativescript-vue`
|
|
42
|
+
* given a project root. Static discovery via `enumeratePackageExports` is the
|
|
43
|
+
* only source — there is no curated fallback. If `nativescript-vue` is not
|
|
44
|
+
* resolvable from `projectRoot`, the returned set is empty and the bridge
|
|
45
|
+
* built from it will not emit passthroughs; the caller should treat that as
|
|
46
|
+
* the misconfiguration it is rather than mask it with a stale baseline.
|
|
47
|
+
*
|
|
48
|
+
* Caching lives inside `enumeratePackageExports`, so repeated calls in a dev
|
|
49
|
+
* session are effectively free.
|
|
50
|
+
*/
|
|
51
|
+
export declare function discoverNsvBridgeExports(projectRoot: string): Set<string>;
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { enumeratePackageExports } from '../helpers/package-exports.js';
|
|
2
|
+
// Exports the bridge replaces with HMR-routed implementations — discovery
|
|
3
|
+
// must not emit a plain passthrough for these names or the override would be
|
|
4
|
+
// shadowed and navigation would silently fall back to the vendor's native
|
|
5
|
+
// version (which doesn't know about the HMR app navigator).
|
|
6
|
+
const NSV_SHIM_OVERRIDES = new Set(['$navigateTo', '$navigateBack', '$showModal', 'vite__injectQuery']);
|
|
7
|
+
// Bridge-internal identifiers that would clash with the emitted preamble if
|
|
8
|
+
// the vendor package happens to publish a colliding name.
|
|
9
|
+
const RESERVED_BRIDGE_LOCALS = new Set(['__realm', '__cached_rt', '__cached_vm', '__ensure', '__get', 'default']);
|
|
10
|
+
const IDENT_RE = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
11
|
+
/**
|
|
12
|
+
* Build the `/ns/rt` runtime bridge module text.
|
|
13
|
+
*
|
|
14
|
+
* Single-realm policy: every named export the vendor package publishes
|
|
15
|
+
* appears as `export const X = (__ensure().X);` — a constant binding, not a
|
|
16
|
+
* function wrapper. Constant bindings preserve identity for Vue's Symbol
|
|
17
|
+
* markers (`Fragment`, `Teleport`, …) AND work transparently for functions
|
|
18
|
+
* (`ref`, `createApp`, …) since the user code calls the underlying value
|
|
19
|
+
* directly. Calling `__ensure()` at module evaluation time is safe because
|
|
20
|
+
* the vendor bundle is registered earlier in the boot graph (vendor.mjs →
|
|
21
|
+
* `__nsVendorRegistry`), and the bridge resolves the same `nativescript-vue`
|
|
22
|
+
* record everyone else uses.
|
|
23
|
+
*
|
|
24
|
+
* HMR-specific shims (`$navigateTo`, `$navigateBack`, `$showModal`) and the
|
|
25
|
+
* Vite client polyfill (`vite__injectQuery`) are emitted as overrides that
|
|
26
|
+
* replace the would-be passthrough — those exports route through the HMR
|
|
27
|
+
* navigator instead of the vendor's native version, so the bridge must
|
|
28
|
+
* provide the override, not the discovered original.
|
|
29
|
+
*/
|
|
30
|
+
export function buildNsRtBridgeModule(options) {
|
|
31
|
+
// Sort for stable output — useful for diffing the served bridge across requests.
|
|
32
|
+
const passthrough = new Set();
|
|
33
|
+
for (const name of options.vendorExports) {
|
|
34
|
+
if (typeof name === 'string' && IDENT_RE.test(name) && !NSV_SHIM_OVERRIDES.has(name) && !RESERVED_BRIDGE_LOCALS.has(name)) {
|
|
35
|
+
passthrough.add(name);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
const passthroughNames = Array.from(passthrough).sort();
|
|
39
|
+
const passthroughExports = passthroughNames.map((n) => `export const ${n} = (__ensure().${n});`).join('\n');
|
|
40
|
+
const defaultListing = passthroughNames.concat(['$navigateTo', '$navigateBack', '$showModal', 'vite__injectQuery']).join(', ');
|
|
41
|
+
const code = `// [ns-rt][v2.4] NativeScript-Vue runtime bridge (module-scoped cache, no globals)\n` +
|
|
42
|
+
`// Single-realm policy: every export is a constant binding off the vendor module's\n` +
|
|
43
|
+
`// canonical instance, so app code, plugins, and the vendor bundle itself share one\n` +
|
|
44
|
+
`// module record. The set of exports below is derived from the package's static ESM\n` +
|
|
45
|
+
`// shape (see hmr/helpers/package-exports.ts), not a hand-curated list, so any symbol\n` +
|
|
46
|
+
`// the vendor publishes flows through automatically.\n` +
|
|
47
|
+
`const __origin = ((typeof globalThis !== 'undefined' && globalThis && globalThis.__NS_HTTP_ORIGIN__) || (new URL(import.meta.url)).origin);\n` +
|
|
48
|
+
// Use the canonical, unversioned `/ns/core` URL so this dynamic import
|
|
49
|
+
// shares an iOS HTTP-ESM module record (and therefore a single class-
|
|
50
|
+
// identity realm) with vendor `require('@nativescript/core')` lookups
|
|
51
|
+
// resolved via the runtime import map, plus every app-side import that
|
|
52
|
+
// goes through the core bridge. The `rtVer` is intentionally unused.
|
|
53
|
+
`let __ns_core_bridge = null; try { import(__origin + "/ns/core").then(m => { __ns_core_bridge = m; }).catch(() => {}); } catch {}\n` +
|
|
54
|
+
`const g = globalThis;\n` +
|
|
55
|
+
`const reg = (g.__nsVendorRegistry ||= new Map());\n` +
|
|
56
|
+
`const req = reg && reg.get ? (g.__nsVendorRequire || g.__nsRequire || g.require) : (g.__nsRequire || g.require);\n` +
|
|
57
|
+
`let __cached_rt = null;\n` +
|
|
58
|
+
`let __cached_vm = null;\n` +
|
|
59
|
+
`const __RT_REALM_TAG = (globalThis.__NS_RT_REALM__ ||= Math.random().toString(36).slice(2));\n` +
|
|
60
|
+
`try { if (!(globalThis.__NS_RT_ONCE__ && globalThis.__NS_RT_ONCE__.eval)) { (globalThis.__NS_RT_ONCE__ ||= {}).eval = true; if (globalThis.__NS_ENV_VERBOSE__) console.log('[ns-rt] evaluated', { rtRealm: __RT_REALM_TAG }); } } catch {}\n` +
|
|
61
|
+
`function __ensure(){\n` +
|
|
62
|
+
` if (__cached_rt) return __cached_rt;\n` +
|
|
63
|
+
` let vm = null;\n` +
|
|
64
|
+
` try { vm = reg && reg.has && reg.has('nativescript-vue') ? reg.get('nativescript-vue') : (typeof req==='function' ? req('nativescript-vue') : null); } catch {}\n` +
|
|
65
|
+
` if (!vm) { try { vm = reg && reg.has && reg.has('vue') ? reg.get('vue') : (typeof req==='function' ? req('vue') : null); } catch {} }\n` +
|
|
66
|
+
` const rt = (vm && (vm.default ?? vm)) || {};\n` +
|
|
67
|
+
` __cached_vm = vm;\n` +
|
|
68
|
+
` __cached_rt = rt;\n` +
|
|
69
|
+
` return rt;\n` +
|
|
70
|
+
`}\n` +
|
|
71
|
+
// Soft-globals for @nativescript/core when missing (dev-only safety).
|
|
72
|
+
// This stays even with the auto-derived passthrough because Frame /
|
|
73
|
+
// Page / Application aren't `nativescript-vue` exports — they're
|
|
74
|
+
// hoisted onto `globalThis` so the navigation shims (and any legacy
|
|
75
|
+
// `global.Frame.topmost()`-style call site inside the vendor bundle)
|
|
76
|
+
// see the same identities served by `/ns/core`.
|
|
77
|
+
`try {\n` +
|
|
78
|
+
` const dev = typeof __DEV__ !== 'undefined' ? __DEV__ : true;\n` +
|
|
79
|
+
` if (dev) {\n` +
|
|
80
|
+
` const ns = (__ns_core_bridge && (__ns_core_bridge.__esModule && __ns_core_bridge.default ? __ns_core_bridge.default : (__ns_core_bridge.default || __ns_core_bridge))) || __ns_core_bridge || {};\n` +
|
|
81
|
+
` if (ns) {\n` +
|
|
82
|
+
` if (!g.Frame && ns.Frame) g.Frame = ns.Frame;\n` +
|
|
83
|
+
` if (!g.Page && ns.Page) g.Page = ns.Page;\n` +
|
|
84
|
+
` if (!g.Application && (ns.Application||ns.app||ns.application)) g.Application = (ns.Application||ns.app||ns.application);\n` +
|
|
85
|
+
` }\n` +
|
|
86
|
+
` }\n` +
|
|
87
|
+
`} catch {}\n` +
|
|
88
|
+
`export const __realm = __RT_REALM_TAG;\n` +
|
|
89
|
+
// Auto-emitted passthrough exports. Discovery-driven, sorted, dedupe'd.
|
|
90
|
+
passthroughExports +
|
|
91
|
+
`\n` +
|
|
92
|
+
// HMR-routed navigation helpers (replace the would-be passthroughs).
|
|
93
|
+
// These run through `globalThis.__nsNavigateUsingApp` etc. instead of
|
|
94
|
+
// the vendor's native navigation, so HMR can re-route navigation
|
|
95
|
+
// targets after module updates.
|
|
96
|
+
`export const $navigateTo = (...a) => { const vm = (__cached_vm || (void __ensure(), __cached_vm)); const rt = __ensure(); try { if (!(g && g.Frame)) { const ns = (__ns_core_bridge && (__ns_core_bridge.__esModule && __ns_core_bridge.default ? __ns_core_bridge.default : (__ns_core_bridge.default || __ns_core_bridge))) || __ns_core_bridge || {}; if (ns) { if (!g.Frame && ns.Frame) g.Frame = ns.Frame; if (!g.Page && ns.Page) g.Page = ns.Page; if (!g.Application && (ns.Application||ns.app||ns.application)) g.Application = (ns.Application||ns.app||ns.application); } } } catch {} try { const hmrRealm = (g && g.__NS_HMR_REALM__) || 'unknown'; const hasTop = !!(g && g.Frame && g.Frame.topmost && g.Frame.topmost()); const top = hasTop ? g.Frame.topmost() : null; const ctor = top && top.constructor && top.constructor.name; } catch {} if (g && typeof g.__nsNavigateUsingApp === 'function') { try { return g.__nsNavigateUsingApp(...a); } catch (e) { console.error('[ns-rt] $navigateTo app navigator error', e); throw e; } } console.error('[ns-rt] $navigateTo unavailable: app navigator missing'); throw new Error('$navigateTo unavailable: app navigator missing'); } ;\n` +
|
|
97
|
+
`export const $navigateBack = (...a) => { const vm = (__cached_vm || (void __ensure(), __cached_vm)); const rt = __ensure(); const impl = (vm && (vm.$navigateBack || (vm.default && vm.default.$navigateBack))) || (rt && (rt.$navigateBack || (rt.runtimeHelpers && rt.runtimeHelpers.navigateBack))); let res; try { const via = (impl && (impl === (vm && vm.$navigateBack) || impl === (vm && vm.default && vm.default.$navigateBack))) ? 'vm' : (impl ? 'rt' : 'none'); } catch {} try { if (typeof impl === 'function') res = impl(...a); } catch {} try { const top = (g && g.Frame && g.Frame.topmost && g.Frame.topmost()); if (!res && top && top.canGoBack && top.canGoBack()) { res = top.goBack(); } } catch {} try { const hook = g && (g.__NS_HMR_ON_NAVIGATE_BACK || g.__NS_HMR_ON_BACK || g.__nsAttemptBackRemount); if (typeof hook === 'function') hook(); } catch {} return res; }\n` +
|
|
98
|
+
`export const $showModal = (...a) => { const vm = (__cached_vm || (void __ensure(), __cached_vm)); const rt = __ensure(); const impl = (vm && (vm.$showModal || (vm.default && vm.default.$showModal))) || (rt && (rt.$showModal || (rt.runtimeHelpers && rt.runtimeHelpers.showModal))); try { if (typeof impl === 'function') return impl(...a); } catch (e) { } return undefined; }\n` +
|
|
99
|
+
// Vite client polyfill — see the comment in websocket.ts for full rationale.
|
|
100
|
+
`export const vite__injectQuery = (url, queryToInject) => {\n` +
|
|
101
|
+
` if (typeof url !== 'string') return url;\n` +
|
|
102
|
+
` if (url[0] !== '.' && url[0] !== '/') return url;\n` +
|
|
103
|
+
` const pathname = url.replace(/[?#].*$/, '');\n` +
|
|
104
|
+
` let search = '', hash = '';\n` +
|
|
105
|
+
` try { const u = new URL(url, 'http://vite.dev'); search = u.search || ''; hash = u.hash || ''; } catch {}\n` +
|
|
106
|
+
` return pathname + '?' + queryToInject + (search ? '&' + search.slice(1) : '') + (hash || '');\n` +
|
|
107
|
+
`};\n` +
|
|
108
|
+
`export default { ${defaultListing} };\n`;
|
|
109
|
+
return options.requireGuardSnippet + code;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Resolve the set of names the bridge should re-export for `nativescript-vue`
|
|
113
|
+
* given a project root. Static discovery via `enumeratePackageExports` is the
|
|
114
|
+
* only source — there is no curated fallback. If `nativescript-vue` is not
|
|
115
|
+
* resolvable from `projectRoot`, the returned set is empty and the bridge
|
|
116
|
+
* built from it will not emit passthroughs; the caller should treat that as
|
|
117
|
+
* the misconfiguration it is rather than mask it with a stale baseline.
|
|
118
|
+
*
|
|
119
|
+
* Caching lives inside `enumeratePackageExports`, so repeated calls in a dev
|
|
120
|
+
* session are effectively free.
|
|
121
|
+
*/
|
|
122
|
+
export function discoverNsvBridgeExports(projectRoot) {
|
|
123
|
+
const out = new Set();
|
|
124
|
+
const shape = enumeratePackageExports('nativescript-vue', projectRoot);
|
|
125
|
+
for (const n of shape.names) {
|
|
126
|
+
if (typeof n === 'string' && IDENT_RE.test(n))
|
|
127
|
+
out.add(n);
|
|
128
|
+
}
|
|
129
|
+
return out;
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=ns-rt-bridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ns-rt-bridge.js","sourceRoot":"","sources":["../../../../../packages/vite/hmr/server/ns-rt-bridge.ts"],"names":[],"mappings":"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"}
|
package/hmr/server/websocket.js
CHANGED
|
@@ -18,6 +18,7 @@ import * as path from 'path';
|
|
|
18
18
|
import { createHash } from 'crypto';
|
|
19
19
|
import * as PAT from './constants.js';
|
|
20
20
|
import { getVendorManifest, resolveVendorSpecifier } from '../shared/vendor/registry.js';
|
|
21
|
+
import { buildNsRtBridgeModule, discoverNsvBridgeExports } from './ns-rt-bridge.js';
|
|
21
22
|
import { getMonorepoWorkspaceRoot, getPackageJson, getProjectFilePath, getProjectRootPath } from '../../helpers/project.js';
|
|
22
23
|
import { loadPrebuiltVendorManifest } from '../shared/vendor/manifest-loader.js';
|
|
23
24
|
import '../vendor-bootstrap.js';
|
|
@@ -4210,167 +4211,15 @@ export const piniaSymbol = p.piniaSymbol;
|
|
|
4210
4211
|
res.setHeader('Expires', '0');
|
|
4211
4212
|
const rtVerSeg = urlObj.pathname.replace(/^\/ns\/rt\/?/, '');
|
|
4212
4213
|
const rtVer = /^[0-9]+$/.test(rtVerSeg) ? rtVerSeg : String(graphVersion || 0);
|
|
4213
|
-
|
|
4214
|
-
|
|
4215
|
-
|
|
4216
|
-
|
|
4217
|
-
|
|
4218
|
-
|
|
4219
|
-
|
|
4220
|
-
|
|
4221
|
-
|
|
4222
|
-
`const g = globalThis;\n` +
|
|
4223
|
-
`const reg = (g.__nsVendorRegistry ||= new Map());\n` +
|
|
4224
|
-
`const req = reg && reg.get ? (g.__nsVendorRequire || g.__nsRequire || g.require) : (g.__nsRequire || g.require);\n` +
|
|
4225
|
-
`let __cached_rt = null;\n` +
|
|
4226
|
-
`let __cached_vm = null;\n` +
|
|
4227
|
-
`const __RT_REALM_TAG = (globalThis.__NS_RT_REALM__ ||= Math.random().toString(36).slice(2));\n` +
|
|
4228
|
-
// One-shot evaluation marker to confirm the bridge is executed on
|
|
4229
|
-
// device. Gated on __NS_ENV_VERBOSE__ so it stays silent unless
|
|
4230
|
-
// the developer opts in via NS_VITE_VERBOSE / VITE_DEBUG_LOGS.
|
|
4231
|
-
`try { if (!(globalThis.__NS_RT_ONCE__ && globalThis.__NS_RT_ONCE__.eval)) { (globalThis.__NS_RT_ONCE__ ||= {}).eval = true; if (globalThis.__NS_ENV_VERBOSE__) console.log('[ns-rt] evaluated', { rtRealm: __RT_REALM_TAG }); } } catch {}\n` +
|
|
4232
|
-
`function __ensure(){\n` +
|
|
4233
|
-
` if (__cached_rt) return __cached_rt;\n` +
|
|
4234
|
-
` let vm = null;\n` +
|
|
4235
|
-
` try { vm = reg && reg.has && reg.has('nativescript-vue') ? reg.get('nativescript-vue') : (typeof req==='function' ? req('nativescript-vue') : null); } catch {}\n` +
|
|
4236
|
-
` if (!vm) { try { vm = reg && reg.has && reg.has('vue') ? reg.get('vue') : (typeof req==='function' ? req('vue') : null); } catch {} }\n` +
|
|
4237
|
-
` const rt = (vm && (vm.default ?? vm)) || {};\n` +
|
|
4238
|
-
` __cached_vm = vm;\n` +
|
|
4239
|
-
` __cached_rt = rt;\n` +
|
|
4240
|
-
` return rt;\n` +
|
|
4241
|
-
`}\n` +
|
|
4242
|
-
`// Soft-globals for @nativescript/core when missing (dev-only safety)\n` +
|
|
4243
|
-
`try {\n` +
|
|
4244
|
-
` const dev = typeof __DEV__ !== 'undefined' ? __DEV__ : true;\n` +
|
|
4245
|
-
` if (dev) {\n` +
|
|
4246
|
-
` const ns = (__ns_core_bridge && (__ns_core_bridge.__esModule && __ns_core_bridge.default ? __ns_core_bridge.default : (__ns_core_bridge.default || __ns_core_bridge))) || __ns_core_bridge || {};\n` +
|
|
4247
|
-
` if (ns) {\n` +
|
|
4248
|
-
` if (!g.Frame && ns.Frame) g.Frame = ns.Frame;\n` +
|
|
4249
|
-
` if (!g.Page && ns.Page) g.Page = ns.Page;\n` +
|
|
4250
|
-
` if (!g.Application && (ns.Application||ns.app||ns.application)) g.Application = (ns.Application||ns.app||ns.application);\n` +
|
|
4251
|
-
` }\n` +
|
|
4252
|
-
` }\n` +
|
|
4253
|
-
`} catch {}\n` +
|
|
4254
|
-
`const __get = (k) => { const rt = __ensure(); const v = rt && rt[k]; if (typeof v !== 'function' && v === undefined) { throw new Error('[ns-rt] missing export '+k); } return v; };\n` +
|
|
4255
|
-
`export const __realm = __RT_REALM_TAG;\n` +
|
|
4256
|
-
`export const defineComponent = (...a) => (__get('defineComponent'))(...a);\n` +
|
|
4257
|
-
`export const resolveComponent = (...a) => (__ensure().resolveComponent)(...a);\n` +
|
|
4258
|
-
`export const createVNode = (...a) => (__ensure().createVNode)(...a);\n` +
|
|
4259
|
-
`export const createTextVNode = (...a) => (__ensure().createTextVNode)(...a);\n` +
|
|
4260
|
-
`export const createCommentVNode = (...a) => (__ensure().createCommentVNode)(...a);\n` +
|
|
4261
|
-
`export const Fragment = (__ensure().Fragment);\n` +
|
|
4262
|
-
`export const Teleport = (__ensure().Teleport);\n` +
|
|
4263
|
-
`export const Transition = (__ensure().Transition);\n` +
|
|
4264
|
-
`export const TransitionGroup = (__ensure().TransitionGroup);\n` +
|
|
4265
|
-
`export const KeepAlive = (__ensure().KeepAlive);\n` +
|
|
4266
|
-
`export const Suspense = (__ensure().Suspense);\n` +
|
|
4267
|
-
`export const withCtx = (...a) => (__ensure().withCtx)(...a);\n` +
|
|
4268
|
-
`export const openBlock = (...a) => (__ensure().openBlock)(...a);\n` +
|
|
4269
|
-
`export const createBlock = (...a) => (__ensure().createBlock)(...a);\n` +
|
|
4270
|
-
`export const createElementVNode = (...a) => (__ensure().createElementVNode)(...a);\n` +
|
|
4271
|
-
`export const createElementBlock = (...a) => (__ensure().createElementBlock)(...a);\n` +
|
|
4272
|
-
`export const renderSlot = (...a) => (__ensure().renderSlot)(...a);\n` +
|
|
4273
|
-
`export const mergeProps = (...a) => (__ensure().mergeProps)(...a);\n` +
|
|
4274
|
-
`export const toHandlers = (...a) => (__ensure().toHandlers)(...a);\n` +
|
|
4275
|
-
`export const renderList = (...a) => (__ensure().renderList)(...a);\n` +
|
|
4276
|
-
`export const normalizeProps = (...a) => (__ensure().normalizeProps)(...a);\n` +
|
|
4277
|
-
`export const guardReactiveProps = (...a) => (__ensure().guardReactiveProps)(...a);\n` +
|
|
4278
|
-
`export const normalizeClass = (...a) => (__ensure().normalizeClass)(...a);\n` +
|
|
4279
|
-
`export const normalizeStyle = (...a) => (__ensure().normalizeStyle)(...a);\n` +
|
|
4280
|
-
`export const toDisplayString = (...a) => (__ensure().toDisplayString)(...a);\n` +
|
|
4281
|
-
`export const withDirectives = (...a) => (__ensure().withDirectives)(...a);\n` +
|
|
4282
|
-
`export const resolveDirective = (...a) => (__ensure().resolveDirective)(...a);\n` +
|
|
4283
|
-
`export const withModifiers = (...a) => (__ensure().withModifiers)(...a);\n` +
|
|
4284
|
-
`export const withKeys = (...a) => (__ensure().withKeys)(...a);\n` +
|
|
4285
|
-
`export const resolveDynamicComponent = (...a) => (__ensure().resolveDynamicComponent)(...a);\n` +
|
|
4286
|
-
`export const isVNode = (...a) => (__ensure().isVNode)(...a);\n` +
|
|
4287
|
-
`export const cloneVNode = (...a) => (__ensure().cloneVNode)(...a);\n` +
|
|
4288
|
-
`export const isRef = (...a) => (__ensure().isRef)(...a);\n` +
|
|
4289
|
-
`export const ref = (...a) => (__ensure().ref)(...a);\n` +
|
|
4290
|
-
`export const shallowRef = (...a) => (__ensure().shallowRef)(...a);\n` +
|
|
4291
|
-
`export const unref = (...a) => (__ensure().unref)(...a);\n` +
|
|
4292
|
-
`export const computed = (...a) => (__ensure().computed)(...a);\n` +
|
|
4293
|
-
`export const reactive = (...a) => (__ensure().reactive)(...a);\n` +
|
|
4294
|
-
`export const readonly = (...a) => (__ensure().readonly)(...a);\n` +
|
|
4295
|
-
`export const isReactive = (...a) => (__ensure().isReactive)(...a);\n` +
|
|
4296
|
-
`export const isReadonly = (...a) => (__ensure().isReadonly)(...a);\n` +
|
|
4297
|
-
`export const toRaw = (...a) => (__ensure().toRaw)(...a);\n` +
|
|
4298
|
-
`export const markRaw = (...a) => (__ensure().markRaw)(...a);\n` +
|
|
4299
|
-
`export const shallowReactive = (...a) => (__ensure().shallowReactive)(...a);\n` +
|
|
4300
|
-
`export const shallowReadonly = (...a) => (__ensure().shallowReadonly)(...a);\n` +
|
|
4301
|
-
`export const watch = (...a) => (__ensure().watch)(...a);\n` +
|
|
4302
|
-
`export const watchEffect = (...a) => (__ensure().watchEffect)(...a);\n` +
|
|
4303
|
-
`export const watchPostEffect = (...a) => (__ensure().watchPostEffect)(...a);\n` +
|
|
4304
|
-
`export const watchSyncEffect = (...a) => (__ensure().watchSyncEffect)(...a);\n` +
|
|
4305
|
-
`export const onBeforeMount = (...a) => (__ensure().onBeforeMount)(...a);\n` +
|
|
4306
|
-
`export const onMounted = (...a) => (__ensure().onMounted)(...a);\n` +
|
|
4307
|
-
`export const onBeforeUpdate = (...a) => (__ensure().onBeforeUpdate)(...a);\n` +
|
|
4308
|
-
`export const onUpdated = (...a) => (__ensure().onUpdated)(...a);\n` +
|
|
4309
|
-
`export const onBeforeUnmount = (...a) => (__ensure().onBeforeUnmount)(...a);\n` +
|
|
4310
|
-
`export const onUnmounted = (...a) => (__ensure().onUnmounted)(...a);\n` +
|
|
4311
|
-
`export const onActivated = (...a) => (__ensure().onActivated)(...a);\n` +
|
|
4312
|
-
`export const onDeactivated = (...a) => (__ensure().onDeactivated)(...a);\n` +
|
|
4313
|
-
`export const onErrorCaptured = (...a) => (__ensure().onErrorCaptured)(...a);\n` +
|
|
4314
|
-
`export const onRenderTracked = (...a) => (__ensure().onRenderTracked)(...a);\n` +
|
|
4315
|
-
`export const onRenderTriggered = (...a) => (__ensure().onRenderTriggered)(...a);\n` +
|
|
4316
|
-
`export const nextTick = (...a) => (__ensure().nextTick)(...a);\n` +
|
|
4317
|
-
`export const h = (...a) => (__ensure().h)(...a);\n` +
|
|
4318
|
-
`export const provide = (...a) => (__ensure().provide)(...a);\n` +
|
|
4319
|
-
`export const inject = (...a) => (__ensure().inject)(...a);\n` +
|
|
4320
|
-
`export const vShow = (__ensure().vShow);\n` +
|
|
4321
|
-
`export const createApp = (...a) => (__ensure().createApp)(...a);\n` +
|
|
4322
|
-
`export const registerElement = (...a) => (__ensure().registerElement)(...a);\n` +
|
|
4323
|
-
`export const $navigateTo = (...a) => { const vm = (__cached_vm || (void __ensure(), __cached_vm)); const rt = __ensure(); try { if (!(g && g.Frame)) { const ns = (__ns_core_bridge && (__ns_core_bridge.__esModule && __ns_core_bridge.default ? __ns_core_bridge.default : (__ns_core_bridge.default || __ns_core_bridge))) || __ns_core_bridge || {}; if (ns) { if (!g.Frame && ns.Frame) g.Frame = ns.Frame; if (!g.Page && ns.Page) g.Page = ns.Page; if (!g.Application && (ns.Application||ns.app||ns.application)) g.Application = (ns.Application||ns.app||ns.application); } } } catch {} try { const hmrRealm = (g && g.__NS_HMR_REALM__) || 'unknown'; const hasTop = !!(g && g.Frame && g.Frame.topmost && g.Frame.topmost()); const top = hasTop ? g.Frame.topmost() : null; const ctor = top && top.constructor && top.constructor.name; } catch {} if (g && typeof g.__nsNavigateUsingApp === 'function') { try { return g.__nsNavigateUsingApp(...a); } catch (e) { console.error('[ns-rt] $navigateTo app navigator error', e); throw e; } } console.error('[ns-rt] $navigateTo unavailable: app navigator missing'); throw new Error('$navigateTo unavailable: app navigator missing'); } ;\n` +
|
|
4324
|
-
`export const $navigateBack = (...a) => { const vm = (__cached_vm || (void __ensure(), __cached_vm)); const rt = __ensure(); const impl = (vm && (vm.$navigateBack || (vm.default && vm.default.$navigateBack))) || (rt && (rt.$navigateBack || (rt.runtimeHelpers && rt.runtimeHelpers.navigateBack))); let res; try { const via = (impl && (impl === (vm && vm.$navigateBack) || impl === (vm && vm.default && vm.default.$navigateBack))) ? 'vm' : (impl ? 'rt' : 'none'); } catch {} try { if (typeof impl === 'function') res = impl(...a); } catch {} try { const top = (g && g.Frame && g.Frame.topmost && g.Frame.topmost()); if (!res && top && top.canGoBack && top.canGoBack()) { res = top.goBack(); } } catch {} try { const hook = g && (g.__NS_HMR_ON_NAVIGATE_BACK || g.__NS_HMR_ON_BACK || g.__nsAttemptBackRemount); if (typeof hook === 'function') hook(); } catch {} return res; }\n` +
|
|
4325
|
-
`export const $showModal = (...a) => { const vm = (__cached_vm || (void __ensure(), __cached_vm)); const rt = __ensure(); const impl = (vm && (vm.$showModal || (vm.default && vm.default.$showModal))) || (rt && (rt.$showModal || (rt.runtimeHelpers && rt.runtimeHelpers.showModal))); try { if (typeof impl === 'function') return impl(...a); } catch (e) { } return undefined; }\n` +
|
|
4326
|
-
// Vite client helpers re-exported through the runtime bridge.
|
|
4327
|
-
//
|
|
4328
|
-
// Vite's `vite:import-analysis` plugin rewrites unresolvable dynamic
|
|
4329
|
-
// imports (where the URL is not a static string literal) as
|
|
4330
|
-
// `__vite__injectQuery(<expr>, 'import')` and prepends an import
|
|
4331
|
-
// from `/@vite/client`. The /* @vite-ignore */ comment only
|
|
4332
|
-
// suppresses the warning, not the rewrite — Vite gates the rewrite
|
|
4333
|
-
// on `urlIsStringRE`, not `hasViteIgnoreRE`.
|
|
4334
|
-
//
|
|
4335
|
-
// In NativeScript dev, the AST normalizer (packages/vite/hmr/helpers/
|
|
4336
|
-
// ast-normalizer.ts) correctly strips the /@vite/client import (the
|
|
4337
|
-
// browser-only client module is not loadable on-device), then sees
|
|
4338
|
-
// the unbound `__vite__injectQuery` identifier and synthesizes
|
|
4339
|
-
// `const { vite__injectQuery: __vite__injectQuery } = __ns_rt_ns_1`
|
|
4340
|
-
// from this bridge. Without this export the destructure binds to
|
|
4341
|
-
// undefined and Angular 21's component HMR loader (and any other
|
|
4342
|
-
// caller of dynamic-import-with-non-literal-URL) fails with
|
|
4343
|
-
// `__vite__injectQuery is not a function` at module evaluation.
|
|
4344
|
-
//
|
|
4345
|
-
// This polyfill mirrors Vite 8's `__vite__injectQuery` in
|
|
4346
|
-
// node_modules/vite/dist/node/chunks/node.js — for relative or
|
|
4347
|
-
// absolute-path URLs it appends `?<queryToInject>` (preserving
|
|
4348
|
-
// existing search/hash); for already-absolute URLs (http(s):, etc.)
|
|
4349
|
-
// it returns the URL unchanged. Angular's `ɵɵgetReplaceMetadataURL`
|
|
4350
|
-
// returns absolute HTTP URLs, so this acts as a passthrough at
|
|
4351
|
-
// runtime, matching Vite's web behavior.
|
|
4352
|
-
`export const vite__injectQuery = (url, queryToInject) => {\n` +
|
|
4353
|
-
` if (typeof url !== 'string') return url;\n` +
|
|
4354
|
-
` if (url[0] !== '.' && url[0] !== '/') return url;\n` +
|
|
4355
|
-
` const pathname = url.replace(/[?#].*$/, '');\n` +
|
|
4356
|
-
` let search = '', hash = '';\n` +
|
|
4357
|
-
` try { const u = new URL(url, 'http://vite.dev'); search = u.search || ''; hash = u.hash || ''; } catch {}\n` +
|
|
4358
|
-
` return pathname + '?' + queryToInject + (search ? '&' + search.slice(1) : '') + (hash || '');\n` +
|
|
4359
|
-
`};\n` +
|
|
4360
|
-
`export default {\n` +
|
|
4361
|
-
` defineComponent, resolveComponent, createVNode, createTextVNode, createCommentVNode,\n` +
|
|
4362
|
-
` Fragment, Teleport, Transition, TransitionGroup, KeepAlive, Suspense, withCtx, openBlock,\n` +
|
|
4363
|
-
` createBlock, createElementVNode, createElementBlock, renderSlot, mergeProps, toHandlers,\n` +
|
|
4364
|
-
` renderList, normalizeProps, guardReactiveProps, normalizeClass, normalizeStyle, toDisplayString,\n` +
|
|
4365
|
-
` withDirectives, resolveDirective, withModifiers, withKeys, resolveDynamicComponent,\n` +
|
|
4366
|
-
` isVNode, cloneVNode, isRef, ref, shallowRef, unref, computed, reactive, readonly, isReactive, isReadonly, toRaw, markRaw, shallowReactive, shallowReadonly,\n` +
|
|
4367
|
-
` watch, watchEffect, watchPostEffect, watchSyncEffect, onBeforeMount, onMounted, onBeforeUpdate, onUpdated,\n` +
|
|
4368
|
-
` onBeforeUnmount, onUnmounted, onActivated, onDeactivated, onErrorCaptured, onRenderTracked, onRenderTriggered, nextTick, h, provide, inject, vShow, createApp, registerElement,\n` +
|
|
4369
|
-
` $navigateTo, $navigateBack, $showModal,\n` +
|
|
4370
|
-
` vite__injectQuery\n` +
|
|
4371
|
-
`};\n`;
|
|
4372
|
-
// Prepend guard and ship (harmless, keeps diagnostics consistent)
|
|
4373
|
-
code = REQUIRE_GUARD_SNIPPET + code;
|
|
4214
|
+
// Single-realm bridge: discover every export `nativescript-vue`
|
|
4215
|
+
// (plus its `@vue/runtime-core` re-export chain) publishes so
|
|
4216
|
+
// the bridge never silently drops a symbol. `discoverNsvBridgeExports`
|
|
4217
|
+
// returns the union of static discovery and the curated baseline,
|
|
4218
|
+
// with the baseline acting as the floor if discovery fails. The
|
|
4219
|
+
// shared builder owns the bridge body (preamble, passthroughs,
|
|
4220
|
+
// HMR shims, polyfills, default export) — there's no inline copy.
|
|
4221
|
+
const vendorExports = discoverNsvBridgeExports(getProjectRootPath());
|
|
4222
|
+
const code = buildNsRtBridgeModule({ rtVer, requireGuardSnippet: REQUIRE_GUARD_SNIPPET, vendorExports });
|
|
4374
4223
|
res.statusCode = 200;
|
|
4375
4224
|
res.end(code);
|
|
4376
4225
|
}
|
|
@@ -6605,6 +6454,88 @@ export const piniaSymbol = p.piniaSymbol;
|
|
|
6605
6454
|
return;
|
|
6606
6455
|
if (verbose)
|
|
6607
6456
|
console.log(`[hmr-ws] Hot update for: ${file}`);
|
|
6457
|
+
// Tailwind / content-scanning CSS broadcast for non-CSS edits.
|
|
6458
|
+
//
|
|
6459
|
+
// Background: when a `.html` template or `.ts` file scanned
|
|
6460
|
+
// by Tailwind's `content` config gets a brand-new utility
|
|
6461
|
+
// class (e.g. `pt-6` that was never used in the codebase
|
|
6462
|
+
// before), the booted CSS bundle doesn't contain a rule for
|
|
6463
|
+
// it. The Angular template HMR swaps the markup, the view
|
|
6464
|
+
// re-renders, the class lookup misses, and the layout
|
|
6465
|
+
// regresses to its default.
|
|
6466
|
+
//
|
|
6467
|
+
// In a "normal" Vite setup, the `vite:css` plugin consumes
|
|
6468
|
+
// each PostCSS `dependency` message via `addWatchFile`, and
|
|
6469
|
+
// `vite:css-analysis` later registers each watched file as
|
|
6470
|
+
// an importer of the CSS module. A content-file edit then
|
|
6471
|
+
// invalidates the CSS module through the moduleGraph and
|
|
6472
|
+
// `ctx.modules`/`mod.importers` would surface it.
|
|
6473
|
+
//
|
|
6474
|
+
// NS HMR breaks that chain: `app.css` is loaded via a
|
|
6475
|
+
// virtual module (`virtual:ns-app-css`) whose `load` hook
|
|
6476
|
+
// calls `preprocessCSS(...)` and emits a JS module — the
|
|
6477
|
+
// CSS itself is never a moduleGraph node, so the importer
|
|
6478
|
+
// chain never forms. `ctx.modules` for the html edit only
|
|
6479
|
+
// contains the html-as-Angular-template module with the
|
|
6480
|
+
// component `.ts` as its importer.
|
|
6481
|
+
//
|
|
6482
|
+
// To bridge that gap, `mainEntryPlugin` stores the set of
|
|
6483
|
+
// `preprocessCSS` deps for `app.css` on the server as
|
|
6484
|
+
// `__nsAppCssDeps` (refreshed when `app.css` /
|
|
6485
|
+
// `tailwind.config.*` change, or when files are added /
|
|
6486
|
+
// removed). If the changed file is in that set, we
|
|
6487
|
+
// broadcast a `ns:css-updates` for `app.css` so the device
|
|
6488
|
+
// fetches fresh CSS through `?direct=1` and Vite re-runs
|
|
6489
|
+
// PostCSS+Tailwind — picking up the new utility class.
|
|
6490
|
+
//
|
|
6491
|
+
// This MUST run before the framework branches because
|
|
6492
|
+
// several of them return early (notably the Angular HTML
|
|
6493
|
+
// live-reload path), and the broadcast must land alongside
|
|
6494
|
+
// the framework's own template-update payload.
|
|
6495
|
+
if (!file.endsWith('.css')) {
|
|
6496
|
+
try {
|
|
6497
|
+
const deps = server.__nsAppCssDeps;
|
|
6498
|
+
const appCssPath = server.__nsAppCssPath;
|
|
6499
|
+
if (deps && appCssPath) {
|
|
6500
|
+
const normalizedFile = path.resolve(file).replace(/\\/g, '/');
|
|
6501
|
+
if (deps.has(normalizedFile)) {
|
|
6502
|
+
const rootPosix = root.replace(/\\/g, '/').replace(/\/$/, '');
|
|
6503
|
+
const relRaw = path.posix.normalize(path.posix.relative(rootPosix, appCssPath));
|
|
6504
|
+
const appCssRel = relRaw && relRaw !== '.' && !relRaw.startsWith('..') ? (relRaw.startsWith('/') ? relRaw : `/${relRaw}`) : null;
|
|
6505
|
+
if (appCssRel) {
|
|
6506
|
+
const origin = getServerOrigin(server);
|
|
6507
|
+
const timestamp = Date.now();
|
|
6508
|
+
const msg = {
|
|
6509
|
+
type: 'ns:css-updates',
|
|
6510
|
+
origin,
|
|
6511
|
+
updates: [
|
|
6512
|
+
{
|
|
6513
|
+
type: 'css-update',
|
|
6514
|
+
path: appCssRel,
|
|
6515
|
+
acceptedPath: appCssRel,
|
|
6516
|
+
timestamp,
|
|
6517
|
+
},
|
|
6518
|
+
],
|
|
6519
|
+
};
|
|
6520
|
+
wss.clients.forEach((client) => {
|
|
6521
|
+
if (isSocketClientOpen(client)) {
|
|
6522
|
+
try {
|
|
6523
|
+
client.send(JSON.stringify(msg));
|
|
6524
|
+
updateMetrics.recipients += 1;
|
|
6525
|
+
}
|
|
6526
|
+
catch { }
|
|
6527
|
+
}
|
|
6528
|
+
});
|
|
6529
|
+
if (verbose)
|
|
6530
|
+
console.info(`[ns-hmr][server] Tailwind/PostCSS content-file edit (${path.basename(file)}) broadcast ${appCssRel}`);
|
|
6531
|
+
}
|
|
6532
|
+
}
|
|
6533
|
+
}
|
|
6534
|
+
}
|
|
6535
|
+
catch (error) {
|
|
6536
|
+
console.warn('[hmr-ws] CSS content-source broadcast failed:', error);
|
|
6537
|
+
}
|
|
6538
|
+
}
|
|
6608
6539
|
// Framework-specific hot update handling
|
|
6609
6540
|
if (ACTIVE_STRATEGY.flavor === 'angular') {
|
|
6610
6541
|
// For Angular, react to component TS or external template HTML changes under /src
|