@nativescript/vite 8.0.0-alpha.1 → 8.0.0-alpha.11

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.
Files changed (220) hide show
  1. package/configuration/angular.d.ts +1 -1
  2. package/configuration/angular.js +486 -140
  3. package/configuration/angular.js.map +1 -1
  4. package/configuration/base.js +159 -29
  5. package/configuration/base.js.map +1 -1
  6. package/configuration/javascript.js +3 -3
  7. package/configuration/javascript.js.map +1 -1
  8. package/configuration/solid.js +27 -0
  9. package/configuration/solid.js.map +1 -1
  10. package/configuration/typescript.js +4 -4
  11. package/configuration/typescript.js.map +1 -1
  12. package/helpers/angular/angular-linker.js +38 -42
  13. package/helpers/angular/angular-linker.js.map +1 -1
  14. package/helpers/angular/inject-component-hmr-registration.d.ts +112 -0
  15. package/helpers/angular/inject-component-hmr-registration.js +359 -0
  16. package/helpers/angular/inject-component-hmr-registration.js.map +1 -0
  17. package/helpers/angular/inline-decorator-component-templates.d.ts +3 -0
  18. package/helpers/angular/inline-decorator-component-templates.js +400 -0
  19. package/helpers/angular/inline-decorator-component-templates.js.map +1 -0
  20. package/helpers/angular/shared-linker.d.ts +7 -0
  21. package/helpers/angular/shared-linker.js +37 -1
  22. package/helpers/angular/shared-linker.js.map +1 -1
  23. package/helpers/angular/synthesize-decorator-ctor-parameters.d.ts +1 -0
  24. package/helpers/angular/synthesize-decorator-ctor-parameters.js +256 -0
  25. package/helpers/angular/synthesize-decorator-ctor-parameters.js.map +1 -0
  26. package/helpers/angular/synthesize-injectable-factories.d.ts +3 -0
  27. package/helpers/angular/synthesize-injectable-factories.js +414 -0
  28. package/helpers/angular/synthesize-injectable-factories.js.map +1 -0
  29. package/helpers/angular/util.d.ts +1 -0
  30. package/helpers/angular/util.js +88 -0
  31. package/helpers/angular/util.js.map +1 -1
  32. package/helpers/commonjs-plugins.d.ts +5 -2
  33. package/helpers/commonjs-plugins.js +126 -0
  34. package/helpers/commonjs-plugins.js.map +1 -1
  35. package/helpers/config-as-json.js +10 -0
  36. package/helpers/config-as-json.js.map +1 -1
  37. package/helpers/esbuild-platform-resolver.js +5 -5
  38. package/helpers/esbuild-platform-resolver.js.map +1 -1
  39. package/helpers/external-configs.d.ts +9 -1
  40. package/helpers/external-configs.js +31 -6
  41. package/helpers/external-configs.js.map +1 -1
  42. package/helpers/global-defines.d.ts +51 -0
  43. package/helpers/global-defines.js +77 -0
  44. package/helpers/global-defines.js.map +1 -1
  45. package/helpers/import-meta-path.d.ts +4 -0
  46. package/helpers/import-meta-path.js +5 -0
  47. package/helpers/import-meta-path.js.map +1 -0
  48. package/helpers/import-specifier.d.ts +1 -0
  49. package/helpers/import-specifier.js +18 -0
  50. package/helpers/import-specifier.js.map +1 -0
  51. package/helpers/logging.d.ts +1 -0
  52. package/helpers/logging.js +63 -3
  53. package/helpers/logging.js.map +1 -1
  54. package/helpers/main-entry.d.ts +5 -2
  55. package/helpers/main-entry.js +375 -116
  56. package/helpers/main-entry.js.map +1 -1
  57. package/helpers/nativeclass-transform.js +8 -127
  58. package/helpers/nativeclass-transform.js.map +1 -1
  59. package/helpers/nativeclass-transformer-plugin.d.ts +19 -1
  60. package/helpers/nativeclass-transformer-plugin.js +318 -36
  61. package/helpers/nativeclass-transformer-plugin.js.map +1 -1
  62. package/helpers/ns-core-url.d.ts +83 -0
  63. package/helpers/ns-core-url.js +167 -0
  64. package/helpers/ns-core-url.js.map +1 -0
  65. package/helpers/prelink-angular.js +1 -4
  66. package/helpers/prelink-angular.js.map +1 -1
  67. package/helpers/project.d.ts +35 -0
  68. package/helpers/project.js +120 -2
  69. package/helpers/project.js.map +1 -1
  70. package/helpers/ts-config-paths.js +50 -2
  71. package/helpers/ts-config-paths.js.map +1 -1
  72. package/helpers/workers.d.ts +20 -19
  73. package/helpers/workers.js +620 -3
  74. package/helpers/workers.js.map +1 -1
  75. package/hmr/client/css-handler.js +60 -19
  76. package/hmr/client/css-handler.js.map +1 -1
  77. package/hmr/client/hmr-pending-overlay.d.ts +27 -0
  78. package/hmr/client/hmr-pending-overlay.js +50 -0
  79. package/hmr/client/hmr-pending-overlay.js.map +1 -0
  80. package/hmr/client/index.js +767 -24
  81. package/hmr/client/index.js.map +1 -1
  82. package/hmr/client/utils.d.ts +5 -0
  83. package/hmr/client/utils.js +283 -12
  84. package/hmr/client/utils.js.map +1 -1
  85. package/hmr/entry-runtime.d.ts +10 -0
  86. package/hmr/entry-runtime.js +330 -42
  87. package/hmr/entry-runtime.js.map +1 -1
  88. package/hmr/frameworks/angular/client/index.d.ts +3 -1
  89. package/hmr/frameworks/angular/client/index.js +821 -25
  90. package/hmr/frameworks/angular/client/index.js.map +1 -1
  91. package/hmr/frameworks/angular/server/linker.js +37 -6
  92. package/hmr/frameworks/angular/server/linker.js.map +1 -1
  93. package/hmr/frameworks/angular/server/strategy.js +30 -6
  94. package/hmr/frameworks/angular/server/strategy.js.map +1 -1
  95. package/hmr/frameworks/typescript/server/strategy.js +8 -2
  96. package/hmr/frameworks/typescript/server/strategy.js.map +1 -1
  97. package/hmr/frameworks/vue/client/index.js +18 -42
  98. package/hmr/frameworks/vue/client/index.js.map +1 -1
  99. package/hmr/helpers/ast-normalizer.js +22 -10
  100. package/hmr/helpers/ast-normalizer.js.map +1 -1
  101. package/hmr/helpers/cjs-named-exports.d.ts +23 -0
  102. package/hmr/helpers/cjs-named-exports.js +152 -0
  103. package/hmr/helpers/cjs-named-exports.js.map +1 -0
  104. package/hmr/server/constants.d.ts +1 -0
  105. package/hmr/server/constants.js +14 -3
  106. package/hmr/server/constants.js.map +1 -1
  107. package/hmr/server/core-sanitize.d.ts +49 -2
  108. package/hmr/server/core-sanitize.js +267 -24
  109. package/hmr/server/core-sanitize.js.map +1 -1
  110. package/hmr/server/import-map.d.ts +65 -0
  111. package/hmr/server/import-map.js +222 -0
  112. package/hmr/server/import-map.js.map +1 -0
  113. package/hmr/server/index.d.ts +2 -1
  114. package/hmr/server/index.js.map +1 -1
  115. package/hmr/server/ns-core-cjs-shape.d.ts +204 -0
  116. package/hmr/server/ns-core-cjs-shape.js +271 -0
  117. package/hmr/server/ns-core-cjs-shape.js.map +1 -0
  118. package/hmr/server/perf-instrumentation.d.ts +114 -0
  119. package/hmr/server/perf-instrumentation.js +195 -0
  120. package/hmr/server/perf-instrumentation.js.map +1 -0
  121. package/hmr/server/runtime-graph-filter.d.ts +5 -0
  122. package/hmr/server/runtime-graph-filter.js +21 -0
  123. package/hmr/server/runtime-graph-filter.js.map +1 -0
  124. package/hmr/server/shared-transform-request.d.ts +12 -0
  125. package/hmr/server/shared-transform-request.js +144 -0
  126. package/hmr/server/shared-transform-request.js.map +1 -0
  127. package/hmr/server/vite-plugin.d.ts +21 -1
  128. package/hmr/server/vite-plugin.js +461 -22
  129. package/hmr/server/vite-plugin.js.map +1 -1
  130. package/hmr/server/websocket-angular-entry.d.ts +2 -0
  131. package/hmr/server/websocket-angular-entry.js +68 -0
  132. package/hmr/server/websocket-angular-entry.js.map +1 -0
  133. package/hmr/server/websocket-angular-hot-update.d.ts +78 -0
  134. package/hmr/server/websocket-angular-hot-update.js +413 -0
  135. package/hmr/server/websocket-angular-hot-update.js.map +1 -0
  136. package/hmr/server/websocket-core-bridge.d.ts +21 -0
  137. package/hmr/server/websocket-core-bridge.js +357 -0
  138. package/hmr/server/websocket-core-bridge.js.map +1 -0
  139. package/hmr/server/websocket-graph-upsert.d.ts +21 -0
  140. package/hmr/server/websocket-graph-upsert.js +33 -0
  141. package/hmr/server/websocket-graph-upsert.js.map +1 -0
  142. package/hmr/server/websocket-hmr-pending.d.ts +43 -0
  143. package/hmr/server/websocket-hmr-pending.js +55 -0
  144. package/hmr/server/websocket-hmr-pending.js.map +1 -0
  145. package/hmr/server/websocket-module-bindings.d.ts +6 -0
  146. package/hmr/server/websocket-module-bindings.js +471 -0
  147. package/hmr/server/websocket-module-bindings.js.map +1 -0
  148. package/hmr/server/websocket-module-specifiers.d.ts +101 -0
  149. package/hmr/server/websocket-module-specifiers.js +820 -0
  150. package/hmr/server/websocket-module-specifiers.js.map +1 -0
  151. package/hmr/server/websocket-ns-m-finalize.d.ts +22 -0
  152. package/hmr/server/websocket-ns-m-finalize.js +88 -0
  153. package/hmr/server/websocket-ns-m-finalize.js.map +1 -0
  154. package/hmr/server/websocket-ns-m-paths.d.ts +3 -0
  155. package/hmr/server/websocket-ns-m-paths.js +92 -0
  156. package/hmr/server/websocket-ns-m-paths.js.map +1 -0
  157. package/hmr/server/websocket-ns-m-request.d.ts +45 -0
  158. package/hmr/server/websocket-ns-m-request.js +196 -0
  159. package/hmr/server/websocket-ns-m-request.js.map +1 -0
  160. package/hmr/server/websocket-runtime-compat.d.ts +19 -0
  161. package/hmr/server/websocket-runtime-compat.js +287 -0
  162. package/hmr/server/websocket-runtime-compat.js.map +1 -0
  163. package/hmr/server/websocket-served-module-helpers.d.ts +36 -0
  164. package/hmr/server/websocket-served-module-helpers.js +631 -0
  165. package/hmr/server/websocket-served-module-helpers.js.map +1 -0
  166. package/hmr/server/websocket-txn.d.ts +6 -0
  167. package/hmr/server/websocket-txn.js +45 -0
  168. package/hmr/server/websocket-txn.js.map +1 -0
  169. package/hmr/server/websocket-vendor-unifier.d.ts +10 -0
  170. package/hmr/server/websocket-vendor-unifier.js +51 -0
  171. package/hmr/server/websocket-vendor-unifier.js.map +1 -0
  172. package/hmr/server/websocket-vue-sfc.d.ts +27 -0
  173. package/hmr/server/websocket-vue-sfc.js +1069 -0
  174. package/hmr/server/websocket-vue-sfc.js.map +1 -0
  175. package/hmr/server/websocket.d.ts +26 -3
  176. package/hmr/server/websocket.js +2492 -798
  177. package/hmr/server/websocket.js.map +1 -1
  178. package/hmr/shared/package-classifier.d.ts +9 -0
  179. package/hmr/shared/package-classifier.js +58 -0
  180. package/hmr/shared/package-classifier.js.map +1 -0
  181. package/hmr/shared/runtime/boot-timeline.d.ts +17 -0
  182. package/hmr/shared/runtime/boot-timeline.js +51 -0
  183. package/hmr/shared/runtime/boot-timeline.js.map +1 -0
  184. package/hmr/shared/runtime/browser-runtime-contract.d.ts +64 -0
  185. package/hmr/shared/runtime/browser-runtime-contract.js +54 -0
  186. package/hmr/shared/runtime/browser-runtime-contract.js.map +1 -0
  187. package/hmr/shared/runtime/dev-overlay.d.ts +85 -0
  188. package/hmr/shared/runtime/dev-overlay.js +1236 -0
  189. package/hmr/shared/runtime/dev-overlay.js.map +1 -0
  190. package/hmr/shared/runtime/http-only-boot.d.ts +1 -0
  191. package/hmr/shared/runtime/http-only-boot.js +53 -6
  192. package/hmr/shared/runtime/http-only-boot.js.map +1 -1
  193. package/hmr/shared/runtime/module-provenance.d.ts +1 -0
  194. package/hmr/shared/runtime/module-provenance.js +63 -0
  195. package/hmr/shared/runtime/module-provenance.js.map +1 -0
  196. package/hmr/shared/runtime/platform-polyfills.d.ts +26 -0
  197. package/hmr/shared/runtime/platform-polyfills.js +122 -0
  198. package/hmr/shared/runtime/platform-polyfills.js.map +1 -0
  199. package/hmr/shared/runtime/root-placeholder.d.ts +1 -0
  200. package/hmr/shared/runtime/root-placeholder.js +552 -82
  201. package/hmr/shared/runtime/root-placeholder.js.map +1 -1
  202. package/hmr/shared/runtime/session-bootstrap.d.ts +1 -0
  203. package/hmr/shared/runtime/session-bootstrap.js +195 -0
  204. package/hmr/shared/runtime/session-bootstrap.js.map +1 -0
  205. package/hmr/shared/runtime/vendor-bootstrap.js +52 -15
  206. package/hmr/shared/runtime/vendor-bootstrap.js.map +1 -1
  207. package/hmr/shared/vendor/manifest.d.ts +37 -0
  208. package/hmr/shared/vendor/manifest.js +677 -57
  209. package/hmr/shared/vendor/manifest.js.map +1 -1
  210. package/hmr/shared/vendor/registry.js +104 -7
  211. package/hmr/shared/vendor/registry.js.map +1 -1
  212. package/index.d.ts +1 -0
  213. package/index.js +5 -0
  214. package/index.js.map +1 -1
  215. package/package.json +14 -2
  216. package/runtime/core-aliases-early.js +94 -67
  217. package/runtime/core-aliases-early.js.map +1 -1
  218. package/shims/solid-jsx-runtime.d.ts +7 -0
  219. package/shims/solid-jsx-runtime.js +17 -0
  220. package/shims/solid-jsx-runtime.js.map +1 -0
@@ -1,10 +1,13 @@
1
1
  import { getPackageJson, getProjectFilePath, getProjectRootPath } from './project.js';
2
2
  import fs from 'fs';
3
- import os from 'os';
4
3
  import path from 'path';
4
+ import { preprocessCSS } from 'vite';
5
+ import { parse as parseCssToAst } from 'css';
5
6
  import { getProjectFlavor } from './flavor.js';
6
7
  import { getProjectAppPath, getProjectAppRelativePath, getProjectAppVirtualPath } from './utils.js';
7
8
  import { getResolvedAppComponents } from './app-components.js';
9
+ import { toStaticImportSpecifier } from './import-specifier.js';
10
+ import { buildCoreUrl } from './ns-core-url.js';
8
11
  // Switched to runtime modules to avoid fragile string injection and enable TS checks
9
12
  const projectRoot = getProjectRootPath();
10
13
  const appRootDir = getProjectAppPath();
@@ -21,6 +24,7 @@ const mainEntryRelPosix = (() => {
21
24
  return getProjectAppVirtualPath('app.ts');
22
25
  }
23
26
  })();
27
+ const mainEntryImportSpecifier = toStaticImportSpecifier(projectRoot, mainEntry);
24
28
  const flavor = getProjectFlavor();
25
29
  // Optional polyfills support (non-HMR specific but dev friendly)
26
30
  // Resolve polyfills relative to the main entry directory so it works both for standalone projects and monorepos/workspaces where the workspace root and app root differ.
@@ -41,56 +45,349 @@ const polyfillsImportSpecifier = (() => {
41
45
  })();
42
46
  const VIRTUAL_ID = 'virtual:entry-with-polyfills';
43
47
  const RESOLVED = '\0' + VIRTUAL_ID;
48
+ const APP_CSS_VIRTUAL_ID = 'virtual:ns-app-css';
49
+ const APP_CSS_RESOLVED = '\0' + APP_CSS_VIRTUAL_ID;
50
+ // Virtual module that installs the XHR polyfill from @nativescript/core/xhr.
51
+ // Rolldown tree-shakes the polyfill-xhr.ts side-effect import from @nativescript/core/globals,
52
+ // so XMLHttpRequest never gets registered as a global. This dedicated module ensures the XHR
53
+ // polyfill is installed during module evaluation (before zone.js patches run).
54
+ const XHR_POLYFILL_VIRTUAL_ID = 'virtual:ns-xhr-polyfill';
55
+ const XHR_POLYFILL_RESOLVED = '\0' + XHR_POLYFILL_VIRTUAL_ID;
56
+ // Virtual module that seeds compile-time defines (`__APPLE__`, `__IOS__`,
57
+ // `__DEV__`, etc.) on `globalThis` BEFORE any other module evaluates.
58
+ //
59
+ // Why this exists. The per-module shim that `processCodeForDevice` injects
60
+ // at the top of every served module reads these values from `globalThis`:
61
+ // const __APPLE__ = globalThis.__APPLE__ !== undefined
62
+ // ? globalThis.__APPLE__
63
+ // : (__IOS__ || __VISIONOS__);
64
+ // `const` evaluates ONCE at module instantiation. So every module needs
65
+ // `globalThis.__APPLE__` to already be set when it instantiates — otherwise
66
+ // it locks in `false` for the lifetime of the module.
67
+ //
68
+ // In ESM, all `import` statements hoist to the top of the module's
69
+ // evaluation phase: imports run in DFS post-order BEFORE the importing
70
+ // module's body. If we put the seed assignments inline in the entry's
71
+ // body (e.g. `globalThis.__APPLE__ = true`), they run AFTER every module
72
+ // transitively imported via `bundle-entry-points` (which reaches the
73
+ // user's `main.ts` → `app.module.ts` → services → util files). Those
74
+ // utility modules then snapshot `globalThis.__APPLE__ = undefined` and
75
+ // fall through to the `false` branch — landing iOS code in the
76
+ // `else { /* Android */ }` branch and crashing on `Utils.android.*`.
77
+ //
78
+ // The fix is to import this virtual module FIRST in the entry. As a leaf
79
+ // in the dependency graph it evaluates before every sibling import, so
80
+ // its body assignments happen before any user module instantiates and
81
+ // reads `globalThis.__*`. This is the architecturally-correct way to
82
+ // make values available to other modules across the import graph in ESM.
83
+ const DEFINES_SEED_VIRTUAL_ID = 'virtual:ns-defines-seed';
84
+ const DEFINES_SEED_RESOLVED = '\0' + DEFINES_SEED_VIRTUAL_ID;
44
85
  export function mainEntryPlugin(opts) {
86
+ let resolvedConfig;
45
87
  return {
46
88
  name: 'main-entry',
89
+ configResolved(config) {
90
+ resolvedConfig = config;
91
+ },
47
92
  resolveId(id) {
48
93
  if (id === VIRTUAL_ID)
49
94
  return RESOLVED;
95
+ if (id === APP_CSS_VIRTUAL_ID)
96
+ return APP_CSS_RESOLVED;
97
+ if (id === XHR_POLYFILL_VIRTUAL_ID)
98
+ return XHR_POLYFILL_RESOLVED;
99
+ if (id === DEFINES_SEED_VIRTUAL_ID)
100
+ return DEFINES_SEED_RESOLVED;
50
101
  return null;
51
102
  },
52
- load(id) {
103
+ async load(id) {
104
+ // Compute the dev server origin for HMR mode. Under HMR we emit
105
+ // `@nativescript/core*` imports as FULL HTTP URLs so iOS's ESM loader
106
+ // can fetch them directly during bundle.mjs module instantiation —
107
+ // the import map isn't installed yet at that phase. For non-HMR
108
+ // builds, we keep bare specifiers so production bundlers inline core
109
+ // the normal way.
110
+ const getBootOrigin = () => {
111
+ if (!opts.hmrActive)
112
+ return null;
113
+ try {
114
+ const configuredHost = typeof resolvedConfig.server.host === 'string' && resolvedConfig.server.host ? resolvedConfig.server.host : 'localhost';
115
+ const bootHost = (process.env.NS_HMR_HOST || '') || configuredHost;
116
+ const bootProtocol = resolvedConfig.server.https || opts.useHttps ? 'https' : 'http';
117
+ const bootPort = Number(resolvedConfig.server.port || 5173);
118
+ return `${bootProtocol}://${bootHost}:${bootPort}`;
119
+ }
120
+ catch {
121
+ return null;
122
+ }
123
+ };
124
+ // Return a spec string for @nativescript/core or a subpath that is
125
+ // guaranteed to resolve at iOS module-instantiation time. Under HMR
126
+ // this is always a full HTTP URL into the /ns/core bridge (no
127
+ // import-map dependency). Under non-HMR it's the bare specifier for
128
+ // the bundler to handle.
129
+ //
130
+ // Under HMR, delegates to buildCoreUrl() — the ONE canonical URL
131
+ // generator. Every URL emitter in the build/runtime pipeline (this
132
+ // function, ns-core-external-urls, rewriteSpec, runtime import map)
133
+ // uses the same function so iOS's HTTP ESM cache sees byte-identical
134
+ // URLs.
135
+ const coreSpec = (subpath) => {
136
+ const origin = getBootOrigin();
137
+ if (origin) {
138
+ return buildCoreUrl(origin, subpath);
139
+ }
140
+ const sub = subpath ? String(subpath).replace(/^\/+/, '') : '';
141
+ return sub ? `@nativescript/core/${sub}` : '@nativescript/core';
142
+ };
143
+ // Virtual module that processes app.css through PostCSS/Tailwind and emits a
144
+ // JS module that BOTH applies the CSS as a side-effect AND exports the raw
145
+ // CSS string as default.
146
+ //
147
+ // Background: Vite's default `?inline` CSS handling collides with
148
+ // @analogjs/vite-plugin-angular's load hook in Vite 8 (it converts ?inline
149
+ // CSS to JS without setting moduleType:'js', so vite:css still tries to run
150
+ // PostCSS on the JS output). This virtual module sidesteps that.
151
+ //
152
+ // We still export the raw CSS string as default so the entry can seed
153
+ // `globalThis.__NS_HMR_APP_CSS__` for HMR's HTTP-core-realm replay path.
154
+ if (id === APP_CSS_RESOLVED) {
155
+ const appCssPath = path.resolve(projectRoot, getProjectAppRelativePath('app.css'));
156
+ const code = fs.readFileSync(appCssPath, 'utf-8');
157
+ const result = await preprocessCSS(code, appCssPath, resolvedConfig);
158
+ const ast = parseCssToAst(result.code, { silent: true });
159
+ // `css` emits `position` metadata on every AST node. NS doesn't
160
+ // use it, and stripping it ~halves the inlined JSON size — same
161
+ // thing webpack's css2json-loader does.
162
+ const astJson = JSON.stringify(ast, (key, value) => (key === 'position' ? undefined : value));
163
+ const lines = [`import { addTaggedAdditionalCSS } from ${JSON.stringify(coreSpec('ui/styling/style-scope'))};`, `addTaggedAdditionalCSS(${astJson}, 'app.css');`, `export default ${JSON.stringify(result.code)};`];
164
+ return {
165
+ code: lines.join('\n'),
166
+ moduleType: 'js',
167
+ };
168
+ }
169
+ // Virtual module that installs XHR polyfill. Its module body runs during import evaluation,
170
+ // guaranteeing XMLHttpRequest is on globalThis before zone.js or any other code accesses it.
171
+ if (id === XHR_POLYFILL_RESOLVED) {
172
+ return {
173
+ code: [`import * as xhrImpl from ${JSON.stringify(coreSpec('xhr'))};`, "var polyfills = ['XMLHttpRequest','FormData','Blob','File','FileReader'];", 'for (var i = 0; i < polyfills.length; i++) {', ' var n = polyfills[i];', ' if (!(n in globalThis) && xhrImpl[n]) globalThis[n] = xhrImpl[n];', '}'].join('\n'),
174
+ moduleType: 'js',
175
+ };
176
+ }
177
+ // Virtual module that seeds compile-time defines on globalThis.
178
+ // Imported FIRST in the entry so it evaluates as a leaf before
179
+ // any other module — including the `bundle-entry-points` chain
180
+ // that transitively reaches the user's app code. See the
181
+ // DEFINES_SEED_VIRTUAL_ID comment at the top of this file.
182
+ if (id === DEFINES_SEED_RESOLVED) {
183
+ const isApple = opts.platform === 'ios' || opts.platform === 'visionos';
184
+ const seedLines = [
185
+ `globalThis.__DEV__ = ${opts.isDevMode ? 'true' : 'false'};`,
186
+ `globalThis.__ANDROID__ = ${opts.platform === 'android' ? 'true' : 'false'};`,
187
+ `globalThis.__IOS__ = ${opts.platform === 'ios' ? 'true' : 'false'};`,
188
+ `globalThis.__VISIONOS__ = ${opts.platform === 'visionos' ? 'true' : 'false'};`,
189
+ `globalThis.__APPLE__ = ${isApple ? 'true' : 'false'};`,
190
+ 'globalThis.__COMMONJS__ = false;',
191
+ 'globalThis.__NS_WEBPACK__ = false;',
192
+ `globalThis.__NS_ENV_VERBOSE__ = ${opts.verbose ? 'true' : 'false'};`,
193
+ // Seed the runtime flavor so the HMR client (which is loaded from
194
+ // node_modules and therefore NOT processed by Vite's `define`
195
+ // substitution) can resolve `TARGET_FLAVOR` reliably. Without
196
+ // this, `resolveTargetFlavor()` in `hmr/client/index.ts` only
197
+ // detects 'angular' (via __reboot_ng_modules__) and 'vue' (via
198
+ // __VUE_HMR_RUNTIME__), and 'solid' / 'typescript' fall through
199
+ // to undefined — so any flavor-specific switch case in
200
+ // `processQueue` (Solid component boundary discovery, route-loader
201
+ // patching, overlay stage transitions) silently never fires.
202
+ `globalThis.__NS_TARGET_FLAVOR__ = ${JSON.stringify(flavor)};`,
203
+ 'globalThis.__UI_USE_XML_PARSER__ = true;',
204
+ 'globalThis.__UI_USE_EXTERNAL_RENDERER__ = false;',
205
+ "globalThis.__CSS_PARSER__ = 'css-tree';",
206
+ 'globalThis.__TEST__ = false;',
207
+ ];
208
+ return {
209
+ code: seedLines.join('\n') + '\n',
210
+ moduleType: 'js',
211
+ };
212
+ }
53
213
  if (id !== RESOLVED)
54
214
  return null;
215
+ let imports = '';
216
+ // Under HMR: import the defines-seed virtual module FIRST so its
217
+ // body — which sets `globalThis.__APPLE__`, `__IOS__`, `__DEV__`,
218
+ // etc. — evaluates as a leaf in the dependency graph BEFORE any
219
+ // other module instantiates. Per-module shims injected by
220
+ // `processCodeForDevice` read these from globalThis and snapshot
221
+ // them at instantiation time, so they MUST be set first.
222
+ //
223
+ // Under non-HMR: Vite's `define` config handles substitution
224
+ // statically at build time — no runtime seeding needed.
225
+ if (opts.hmrActive) {
226
+ imports += `import '${DEFINES_SEED_VIRTUAL_ID}';\n`;
227
+ }
55
228
  // consistent verbose flag to easily reference below
56
- let imports = "const __nsVerboseLog = typeof __NS_ENV_VERBOSE__ !== 'undefined' && __NS_ENV_VERBOSE__;\n";
57
- // Ensure any CommonJS-style tooling requires (e.g. from Babel or other
58
- // build-time libraries that may be accidentally bundled) do not attempt
59
- // to resolve Node built-ins like 'fs' or 'path' on device. These modules
60
- // are not used at runtime for NativeScript apps, so we safely return an
61
- // empty object from a global require shim when present.
62
- imports += "try { if (typeof globalThis !== 'undefined') { globalThis.require = function () { return {}; }; } } catch {}\n";
229
+ imports += "const __nsVerboseLog = typeof __NS_ENV_VERBOSE__ !== 'undefined' && __NS_ENV_VERBOSE__;\n";
230
+ // Ensure any CommonJS-style tooling requires (e.g. from Babel or
231
+ // other build-time libraries that may be accidentally bundled) do
232
+ // not attempt to resolve Node built-ins like 'fs' or 'path' on
233
+ // device. These modules are not used at runtime for NativeScript
234
+ // apps, so we safely return an empty object from a shim.
235
+ //
236
+ // IMPORTANT: Under HMR, vendor packages call the real NativeScript
237
+ // CommonJS require() with `@nativescript/core/<sub>` specifiers
238
+ // (e.g. `require('@nativescript/core/ui/core/view').View` in
239
+ // `@nativescript-community/gesturehandler`). If we overwrite
240
+ // globalThis.require with a blanket stub, every such call returns
241
+ // `{}` and any property access on the result (e.g. `.View`) is
242
+ // `undefined`, cascading into `TypeError: Cannot read properties
243
+ // of undefined (reading 'prototype')` inside `applyMixins` when
244
+ // vendor install() hooks run.
245
+ //
246
+ // Instead, install a DELEGATING shim:
247
+ // - If the specifier is a Node built-in (fs, path, os, …) or
248
+ // a webpack-only runtime hook (require.context), return a
249
+ // safe empty stub.
250
+ // - Otherwise, delegate to the preserved original
251
+ // `globalThis.require` (NativeScript's native CJS loader),
252
+ // which routes `@nativescript/core*` through the HTTP bridge
253
+ // or, for already-HTTP-loaded modules, through the
254
+ // `globalThis.__NS_CORE_MODULES__` registry populated by the
255
+ // `/ns/core` bridge preamble.
256
+ imports += "try { if (typeof globalThis !== 'undefined') {\n";
257
+ imports += " var __nsOrigRequire = typeof globalThis.require === 'function' ? globalThis.require : null;\n";
258
+ imports += ' var __nsNodeBuiltins = { fs: 1, path: 1, os: 1, url: 1, crypto: 1, util: 1, stream: 1, events: 1, buffer: 1, http: 1, https: 1, net: 1, tls: 1, dns: 1, child_process: 1, module: 1, zlib: 1, querystring: 1, assert: 1, constants: 1, vm: 1 };\n';
259
+ // Mirror helpers/ns-core-url.ts normalizeCoreSub() inline so the
260
+ // lookup against __NS_CORE_MODULES__ uses the same keys the
261
+ // /ns/core handler registers under.
262
+ imports += ' var __nsNormSub = function (s) {\n';
263
+ imports += " if (!s) return '';\n";
264
+ imports += " var t = String(s).split('?')[0].split('#')[0].trim();\n";
265
+ imports += " t = t.replace(/^\\/+/, '').replace(/\\/+$/, '');\n";
266
+ imports += " t = t.replace(/\\.(?:mjs|cjs|js)$/, '');\n";
267
+ imports += " if (t.length >= 6 && t.substring(t.length - 6) === '/index') t = t.substring(0, t.length - 6);\n";
268
+ imports += " if (!t || t === 'index') return '';\n";
269
+ imports += ' return t;\n';
270
+ imports += ' };\n';
271
+ // Invariant D: CJS/ESM interop shape helper.
272
+ //
273
+ // Install a global, idempotent shape function that converts
274
+ // ESM Module Namespace Objects (which have [[Prototype]] = null
275
+ // per spec §9.4.6) into plain Objects that inherit from
276
+ // Object.prototype. CJS consumers — especially zone.js's
277
+ // patchMethod() — call `hasOwnProperty`, `toString`, etc. on
278
+ // their require() result; a null-proto namespace throws
279
+ // "X is not a function" on the first such call.
280
+ //
281
+ // Properties:
282
+ // - Recursive: @nativescript/core re-exports Utils/Http/Trace
283
+ // as nested namespaces (`export * as Utils from './utils'`),
284
+ // each also null-proto. Shallow wrapping leaves those.
285
+ // - Identity-preserving via a WeakMap cache keyed on the
286
+ // underlying namespace. zone.js MUTATES its target (stashes
287
+ // delegate symbols, overwrites methods); a fresh copy per
288
+ // require() would lose those mutations on the next lookup.
289
+ // - Installed ONCE on globalThis so the /ns/core handler's
290
+ // registration footer, the vendor shim's createRequire, and
291
+ // any other consumer share the same cache and see
292
+ // mutation-consistent shapes.
293
+ imports += ' var __nsShapeCache = globalThis.__NS_CJS_SHAPE_CACHE__ || (globalThis.__NS_CJS_SHAPE_CACHE__ = new WeakMap());\n';
294
+ imports += ' var __nsShapeCjs = globalThis.__NS_CJS_SHAPE__ || (globalThis.__NS_CJS_SHAPE__ = function __nsShape(obj) {\n';
295
+ imports += " if (!obj || typeof obj !== 'object') return obj;\n";
296
+ imports += ' var proto = Object.getPrototypeOf(obj);\n';
297
+ imports += ' var isNsModule = false;\n';
298
+ imports += " try { isNsModule = obj[Symbol.toStringTag] === 'Module'; } catch (e) {}\n";
299
+ imports += ' if (proto !== null && !isNsModule) return obj;\n';
300
+ imports += ' if (__nsShapeCache.has(obj)) return __nsShapeCache.get(obj);\n';
301
+ imports += ' var out = {};\n';
302
+ imports += ' __nsShapeCache.set(obj, out);\n';
303
+ imports += ' try {\n';
304
+ imports += ' var keys = Object.keys(obj);\n';
305
+ imports += ' for (var i = 0; i < keys.length; i++) {\n';
306
+ imports += ' var k = keys[i];\n';
307
+ imports += ' try { out[k] = __nsShape(obj[k]); } catch (e) {}\n';
308
+ imports += ' }\n';
309
+ imports += ' } catch (e) {}\n';
310
+ imports += ' return out;\n';
311
+ imports += ' });\n';
312
+ imports += ' var _nsReq = function (id) {\n';
313
+ imports += ' try {\n';
314
+ imports += " var n = String(id || '');\n";
315
+ imports += " var stripped = n.indexOf('node:') === 0 ? n.slice(5) : n;\n";
316
+ imports += ' if (__nsNodeBuiltins[stripped]) return {};\n';
317
+ imports += " if (n === '@nativescript/core' || n.indexOf('@nativescript/core/') === 0) {\n";
318
+ imports += ' var table = globalThis.__NS_CORE_MODULES__;\n';
319
+ imports += ' if (table) {\n';
320
+ // Table entries are ALREADY shaped (the /ns/core footer stores
321
+ // the shape, not the raw namespace). But we pass through
322
+ // __nsShapeCjs anyway — it's a no-op on already-shaped values
323
+ // (fast path: `proto !== null && !isNsModule` returns obj as-is)
324
+ // and guards against future changes to how the registry is
325
+ // populated (e.g., by direct assignment from test code).
326
+ imports += ' if (table[n]) return __nsShapeCjs(table[n]);\n';
327
+ imports += " var rawSub = n === '@nativescript/core' ? '' : n.slice('@nativescript/core/'.length);\n";
328
+ imports += ' var normSub = __nsNormSub(rawSub);\n';
329
+ imports += " var bareKey = normSub ? '@nativescript/core/' + normSub : '@nativescript/core';\n";
330
+ imports += ' if (table[bareKey]) return __nsShapeCjs(table[bareKey]);\n';
331
+ imports += ' if (table[normSub]) return __nsShapeCjs(table[normSub]);\n';
332
+ imports += ' }\n';
333
+ imports += ' }\n';
334
+ // Fallback to native require (NativeScript CJS loader via HTTP
335
+ // bridge). Shape the result too — the native loader may return
336
+ // a raw ESM namespace for core subpaths served before the /ns/core
337
+ // footer runs.
338
+ imports += ' if (__nsOrigRequire) return __nsShapeCjs(__nsOrigRequire(id));\n';
339
+ imports += ' } catch (e) {}\n';
340
+ imports += ' return {};\n';
341
+ imports += ' };\n';
342
+ imports += ' _nsReq.context = function () { var _c = { keys: function () { return []; } }; _c.__esModule = true; return _c; };\n';
343
+ imports += ' if (__nsOrigRequire) { try { _nsReq.resolve = __nsOrigRequire.resolve ? __nsOrigRequire.resolve.bind(__nsOrigRequire) : function (id) { return id; }; } catch (e) {} }\n';
344
+ imports += ' globalThis.require = _nsReq;\n';
345
+ imports += ' globalThis.__nsOrigRequire = __nsOrigRequire;\n';
346
+ imports += '} } catch {}\n';
63
347
  // Banner diagnostics for visibility at runtime
64
348
  if (opts.verbose) {
65
349
  imports += `console.info('[ns-entry] begin', { platform: ${JSON.stringify(opts.platform)}, dev: ${JSON.stringify(opts.isDevMode)}, hmr: ${JSON.stringify(opts.hmrActive)}, verbose: ${JSON.stringify(opts.verbose)}, mainEntry: ${JSON.stringify(mainEntry)}, mainRel: ${JSON.stringify(mainEntryRelPosix)}, time: new Date().toISOString() });\n`;
66
350
  }
67
351
  if (opts.hmrActive) {
68
- // Seed platform globals on the primary bundle realm using the same
69
- // CLI-derived platform that drives global-defines.ts. This ensures
70
- // HMR-delivered HTTP ESM modules can reliably read platform flags
71
- imports += `globalThis.__DEV__ = ${opts.isDevMode ? 'true' : 'false'};\n`;
72
- imports += `globalThis.__ANDROID__ = ${opts.platform === 'android' ? 'true' : 'false'};\n`;
73
- imports += `globalThis.__IOS__ = ${opts.platform === 'ios' ? 'true' : 'false'};\n`;
74
- imports += `globalThis.__VISIONOS__ = ${opts.platform === 'visionos' ? 'true' : 'false'};\n`;
75
- imports += `globalThis.__APPLE__ = ${opts.platform === 'ios' || opts.platform === 'visionos' ? 'true' : 'false'};\n`;
76
- // ---- Vendor manifest bootstrap ----
77
- // Use single self-contained vendor module to avoid extra imports affecting chunking
78
- imports += "import vendorManifest, { __nsVendorModuleMap } from '@nativescript/vendor';\n";
79
- imports += "import { installVendorBootstrap } from '@nativescript/vite/hmr/shared/runtime/vendor-bootstrap.js';\n";
80
- if (opts.verbose) {
81
- imports += `console.info('[ns-entry] vendor manifest imported', { keys: Object.keys(vendorManifest||{}).length, hasMap: typeof __nsVendorModuleMap === 'object' });\n`;
82
- }
83
- imports += 'installVendorBootstrap(vendorManifest, __nsVendorModuleMap, __nsVerboseLog);\n';
84
- if (opts.verbose) {
85
- imports += `console.info('[ns-entry] vendor bootstrap installed');\n`;
86
- }
352
+ // NOTE: globalThis defines (`__APPLE__`, `__IOS__`, `__DEV__`,
353
+ // etc.) are seeded by the `virtual:ns-defines-seed` import at
354
+ // the very top of this entry see the import on line ~192.
355
+ // They MUST run as a leaf module ahead of any other graph
356
+ // node, so we can't seed them inline here (ESM imports hoist
357
+ // past inline body code, so any module reachable through
358
+ // `bundle-entry-points` would otherwise see undefined).
359
+ imports += "import { installModuleProvenanceRecorder } from '@nativescript/vite/hmr/shared/runtime/module-provenance.js';\n";
360
+ imports += 'installModuleProvenanceRecorder(__nsVerboseLog);\n';
87
361
  }
88
362
  // ---- Core runtime globals (always-needed) ----
89
- // Load globals early
90
- imports += "import '@nativescript/core/globals/index';\n";
363
+ // Install XHR polyfill FIRST — its virtual module body runs during import evaluation,
364
+ // before any subsequent import (like zone.js) can reference XMLHttpRequest.
365
+ imports += `import '${XHR_POLYFILL_VIRTUAL_ID}';\n`;
366
+ // Load globals early. Under HMR we use a full HTTP URL so iOS's
367
+ // ESM loader can fetch it directly at module-instantiation time —
368
+ // the import map isn't installed yet at that phase.
369
+ imports += `import ${JSON.stringify(coreSpec('globals/index'))};\n`;
91
370
  if (opts.verbose) {
92
371
  imports += `console.info('[ns-entry] core globals loaded');\n`;
93
372
  }
373
+ // Seed the real NativeScript Application singleton before any early HMR/placeholder
374
+ // code runs. Dynamic discovery is too late for iOS placeholder startup.
375
+ imports += `import { Application as __nsEarlyApplication } from ${JSON.stringify(coreSpec('application'))};\n`;
376
+ imports += `try { if (__nsEarlyApplication && (typeof __nsEarlyApplication.run === 'function' || typeof __nsEarlyApplication.on === 'function' || typeof __nsEarlyApplication.resetRootView === 'function')) { globalThis.Application = __nsEarlyApplication; } } catch {}\n`;
377
+ if (opts.verbose) {
378
+ imports += `console.info('[ns-entry] early Application seeded', { hasRun: typeof globalThis.Application?.run === 'function', hasOn: typeof globalThis.Application?.on === 'function', hasResetRootView: typeof globalThis.Application?.resetRootView === 'function' });\n`;
379
+ }
380
+ // In dev mode for Angular apps, ensure @angular/compiler (JIT) is loaded.
381
+ // With experimentalDecorators:true, TypeScript emits __decorate patterns.
382
+ // On watch-mode rebuilds the Angular compiler may not re-emit ɵfac for
383
+ // cached files, so the JIT compiler must be available as a fallback.
384
+ if (opts.isDevMode && flavor === 'angular') {
385
+ imports += "import { publishFacade as __nsPublishAngularCompilerFacade } from '@angular/compiler';\n";
386
+ imports += '__nsPublishAngularCompilerFacade(globalThis);\n';
387
+ if (opts.verbose) {
388
+ imports += `console.info('[ns-entry] @angular/compiler (JIT) loaded for dev mode');\n`;
389
+ }
390
+ }
94
391
  /**
95
392
  * Ensure the canonical @nativescript/core classes are available on globalThis
96
393
  * before any other framework modules execute (like bundle-entry-points) to avoid duplicate realms
@@ -111,13 +408,21 @@ export function mainEntryPlugin(opts) {
111
408
  }
112
409
  }
113
410
  // Load NS bundle entry points after early hook
114
- imports += "import '@nativescript/core/bundle-entry-points';\n";
411
+ imports += `import ${JSON.stringify(coreSpec('bundle-entry-points'))};\n`;
115
412
  if (opts.verbose) {
116
413
  imports += `console.info('[ns-entry] bundle-entry-points loaded');\n`;
117
414
  }
118
415
  if (flavor === 'typescript') {
119
416
  // Statically import bundler context synchronously before app code
120
417
  imports += "import 'virtual:ns-bundler-context';\n";
418
+ if (opts.hmrActive) {
419
+ // Snapshot original module registry functions for HMR diagnostics
420
+ imports += `(function() {
421
+ globalThis.__NS_ORIG_GET_REGISTERED_MODULES__ = globalThis.getRegisteredModules;
422
+ globalThis.__NS_ORIG_MODULE_EXISTS__ = globalThis.moduleExists;
423
+ globalThis.__NS_ORIG_LOAD_MODULE__ = globalThis.loadModule;
424
+ })();\n`;
425
+ }
121
426
  }
122
427
  // ---- Custom App Components (Activity/Application) ----
123
428
  // These must be loaded early so the JS class is registered before Android instantiates them
@@ -127,7 +432,7 @@ export function mainEntryPlugin(opts) {
127
432
  for (const component of appComponents) {
128
433
  // The appComponentsPlugin bundles these as separate .mjs entry points
129
434
  // We must import the output file, not the source, since it's a separate entry
130
- imports += `import "~/${component.outputName}.mjs";\n`;
435
+ imports += `import ${JSON.stringify(`~/${component.outputName}.mjs`)};\n`;
131
436
  if (opts.verbose) {
132
437
  imports += `console.info('[ns-entry] app component loaded: ${component.outputName}');\n`;
133
438
  }
@@ -138,54 +443,17 @@ export function mainEntryPlugin(opts) {
138
443
  }
139
444
  }
140
445
  // ---- Platform-specific always-needed modules ----
141
- // Track if we need to defer Android activity import (non-HMR only)
142
446
  let needsAndroidActivityDefer = false;
143
447
  if (opts.platform === 'android') {
144
- if (opts.hmrActive) {
145
- /**
146
- * Ensure the Java Activity class exists by executing the vendor-packed
147
- * activity registration module via the vendor registry (not ESM import).
148
- * This avoids any on-disk vendor.mjs export mismatches and guarantees the
149
- * class is registered before Android tries to instantiate it.
150
- */
151
- imports += `
152
- (function __nsEnsureAndroidActivityForHMR(){
153
- try {
154
- const g = globalThis;
155
- const req = (g.__nsVendorRequire || g.__nsRequire);
156
- if (!req) {
157
- ${opts.verbose ? "console.warn('[ns-entry] vendor require not available yet; activity registration may be deferred');" : ''}
158
- return;
159
- }
160
- const candidates = [
161
- '@nativescript/core/ui/frame/activity.android',
162
- '@nativescript/core/ui/frame/activity.android.js'
163
- ];
164
- for (const id of candidates) {
165
- try {
166
- req(id);
167
- ${opts.verbose ? "console.info('[ns-entry] android activity registered via vendor', id);" : ''}
168
- break;
169
- } catch {}
170
- }
171
- } catch (e) {
172
- try { console.error('[ns-entry] failed to require android activity from vendor', e); } catch {}
173
- }
174
- })();\n`;
175
- }
176
- else {
177
- /**
178
- * Non-HMR: Defer activity lifecycle wiring until native Application is ready
179
- * to avoid "application is null" errors at production boot.
180
- * We set a flag here and emit the actual code after the static Application import
181
- * to avoid mixing dynamic and static imports of @nativescript/core.
182
- */
183
- needsAndroidActivityDefer = true;
184
- }
448
+ /**
449
+ * Defer activity lifecycle wiring until native Application is ready
450
+ * to avoid "application is null" errors during startup.
451
+ */
452
+ needsAndroidActivityDefer = true;
185
453
  }
186
454
  // ---- Optional polyfills ----
187
455
  if (polyfillsExists) {
188
- imports += `import '${polyfillsImportSpecifier}';\n`;
456
+ imports += `import ${JSON.stringify(polyfillsImportSpecifier)};\n`;
189
457
  if (opts.verbose) {
190
458
  imports += `console.info('[ns-entry] polyfills imported from', ${JSON.stringify(polyfillsImportSpecifier)});\n`;
191
459
  }
@@ -200,9 +468,6 @@ export function mainEntryPlugin(opts) {
200
468
  if (opts.verbose) {
201
469
  imports += "console.info('[ns-entry] websockets polyfill imported');\n";
202
470
  }
203
- // Load HMR client for WebSocket connection to Vite dev server before HTTP-only boot attempts.
204
- imports += "import 'virtual:ns-hmr-client';\n";
205
- imports += "console.info('@nativescript/vite HMR client loaded.');\n";
206
471
  }
207
472
  // ---- Global CSS injection (always-needed if file exists) ----
208
473
  const appCssPath = path.resolve(projectRoot, getProjectAppRelativePath('app.css'));
@@ -210,16 +475,24 @@ export function mainEntryPlugin(opts) {
210
475
  // Import Application statically if needed for CSS or Android activity defer
211
476
  if (hasAppCss || needsAndroidActivityDefer) {
212
477
  if (hasAppCss) {
213
- imports += `// Import and apply global CSS before app bootstrap\n`;
214
- imports += `import appCssContent from './${appRootDir}/app.css?inline';\n`;
215
- }
216
- imports += `import { Application } from '@nativescript/core';\n`;
217
- if (hasAppCss) {
218
- imports += `if (appCssContent) { try { Application.addCss(appCssContent); } catch (error) { console.error('Error applying CSS:', error); } }\n`;
478
+ // The virtual module's body calls
479
+ // `addTaggedAdditionalCSS(ast, 'app.css')` as an import-time
480
+ // side-effect, so the CSS lands in NS's selector tables before
481
+ // any view is created. The default export is the raw CSS
482
+ // string, kept so HMR can seed `__NS_HMR_APP_CSS__` for the
483
+ // HTTP-core-realm replay path.
484
+ imports += `// Apply global CSS before app bootstrap (AST applied as a side-effect of this import)\n`;
485
+ imports += `import appCssContent from '${APP_CSS_VIRTUAL_ID}';\n`;
486
+ if (opts.hmrActive) {
487
+ imports += `try { globalThis.__NS_HMR_APP_CSS__ = appCssContent; } catch {}\n`;
488
+ }
219
489
  if (opts.verbose) {
220
- imports += `console.info('[ns-entry] app.css applied');\n`;
490
+ imports += `console.info('[ns-entry] app.css applied as AST');\n`;
221
491
  }
222
492
  }
493
+ if (needsAndroidActivityDefer) {
494
+ imports += `import { Application } from ${JSON.stringify(coreSpec())};\n`;
495
+ }
223
496
  }
224
497
  // ---- Deferred Android activity import (non-HMR only) ----
225
498
  // Uses the statically imported Application to avoid mixing dynamic and static imports
@@ -242,48 +515,34 @@ export function mainEntryPlugin(opts) {
242
515
  }
243
516
  // ---- Application main entry ----
244
517
  if (opts.hmrActive) {
245
- // HTTP-only dev boot: try to import the entire app over HTTP; if not reachable, keep retrying.
518
+ // Deterministic dev boot: fetch one session descriptor and let the runtime
519
+ // import the session client + app entry over HTTP.
246
520
  if (opts.verbose) {
247
- imports += `console.info('[ns-entry] including HTTP-only boot', { platform: ${JSON.stringify(opts.platform)}, mainRel: ${JSON.stringify(mainEntryRelPosix)} });\n`;
521
+ imports += `console.info('[ns-entry] including deterministic dev session bootstrap', { platform: ${JSON.stringify(opts.platform)}, mainRel: ${JSON.stringify(mainEntryRelPosix)} });\n`;
248
522
  }
249
- const guessLanHost = () => {
250
- try {
251
- const nets = os.networkInterfaces();
252
- for (const name of Object.keys(nets)) {
253
- const addrs = nets[name] || [];
254
- for (const a of addrs) {
255
- if (!a)
256
- continue;
257
- const family = a.family;
258
- const internal = !!a.internal;
259
- const address = String(a.address || '');
260
- if (internal)
261
- continue;
262
- if ((family === 'IPv4' || family === 4) && address && address !== '127.0.0.1')
263
- return address;
264
- }
265
- }
266
- }
267
- catch { }
268
- return undefined;
269
- };
270
- // Prefer LAN IP so physical devices work by default; emulator will still be tried as a fallback.
271
- const defaultHost = opts.platform === 'android' ? guessLanHost() || '10.0.2.2' : guessLanHost() || 'localhost';
272
- imports += "import { startHttpOnlyBoot } from '@nativescript/vite/hmr/shared/runtime/http-only-boot.js';\n";
273
- imports += `startHttpOnlyBoot(${JSON.stringify(opts.platform)}, ${JSON.stringify(mainEntryRelPosix)}, ${JSON.stringify((process.env.NS_HMR_HOST || '')) || JSON.stringify('')} || ${JSON.stringify(defaultHost)}, __nsVerboseLog);\n`;
523
+ const configuredHost = typeof resolvedConfig.server.host === 'string' && resolvedConfig.server.host ? resolvedConfig.server.host : 'localhost';
524
+ const bootHost = (process.env.NS_HMR_HOST || '') || configuredHost;
525
+ const bootProtocol = resolvedConfig.server.https || opts.useHttps ? 'https' : 'http';
526
+ const bootPort = Number(resolvedConfig.server.port || 5173);
527
+ const sessionUrl = bootProtocol + '://' + bootHost + ':' + String(bootPort) + '/__ns_dev__/session';
528
+ imports += "import { startBrowserRuntimeSession } from '@nativescript/vite/hmr/shared/runtime/session-bootstrap.js';\n";
529
+ imports += `startBrowserRuntimeSession(${JSON.stringify(sessionUrl)}, __nsVerboseLog).catch((error) => {\n`;
530
+ imports += ` try { globalThis.__NS_ENTRY_ERROR__ = { phase: 'deterministic-dev-session', message: String(error && (error.message || error)), stack: error && error.stack ? String(error.stack) : '' }; } catch {}\n`;
531
+ imports += ` console.error('[ns-entry] deterministic dev session bootstrap failed', error && error.stack ? error.stack : error);\n`;
532
+ imports += `});\n`;
274
533
  if (opts.verbose) {
275
- imports += `console.info('[ns-entry] HTTP-only boot code appended');\n`;
534
+ imports += `console.info('[ns-entry] deterministic dev session bootstrap appended');\n`;
276
535
  }
277
536
  }
278
537
  else {
279
538
  if (opts.verbose) {
280
- imports += `console.info('[ns-entry] Importing main entry', '${mainEntry}');\n`;
539
+ imports += `console.info('[ns-entry] Importing main entry', ${JSON.stringify(mainEntryImportSpecifier)});\n`;
281
540
  }
282
- imports += `import '${mainEntry}';\n`;
541
+ imports += `import ${JSON.stringify(mainEntryImportSpecifier)};\n`;
283
542
  }
284
543
  if (opts.isDevMode) {
285
544
  // debug tools support
286
- imports += "import '@nativescript/core/inspector_modules';\n";
545
+ imports += `import ${JSON.stringify(coreSpec('inspector_modules'))};\n`;
287
546
  if (opts.verbose) {
288
547
  imports += "console.info('[ns-entry] inspector modules imported');\n";
289
548
  }