@nativescript/vite 8.0.0-alpha.2 → 8.0.0-alpha.21

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 (209) hide show
  1. package/configuration/angular.d.ts +34 -1
  2. package/configuration/angular.js +380 -34
  3. package/configuration/angular.js.map +1 -1
  4. package/configuration/base.js +171 -7
  5. package/configuration/base.js.map +1 -1
  6. package/configuration/solid.js +27 -1
  7. package/configuration/solid.js.map +1 -1
  8. package/configuration/typescript.js +1 -1
  9. package/configuration/typescript.js.map +1 -1
  10. package/helpers/angular/angular-linker.js +3 -12
  11. package/helpers/angular/angular-linker.js.map +1 -1
  12. package/helpers/angular/inject-component-hmr-registration.d.ts +112 -0
  13. package/helpers/angular/inject-component-hmr-registration.js +359 -0
  14. package/helpers/angular/inject-component-hmr-registration.js.map +1 -0
  15. package/helpers/angular/inject-hmr-vite-ignore.d.ts +75 -0
  16. package/helpers/angular/inject-hmr-vite-ignore.js +288 -0
  17. package/helpers/angular/inject-hmr-vite-ignore.js.map +1 -0
  18. package/helpers/angular/util.d.ts +1 -0
  19. package/helpers/angular/util.js +88 -0
  20. package/helpers/angular/util.js.map +1 -1
  21. package/helpers/commonjs-plugins.d.ts +5 -2
  22. package/helpers/commonjs-plugins.js +126 -0
  23. package/helpers/commonjs-plugins.js.map +1 -1
  24. package/helpers/config-as-json.js +10 -0
  25. package/helpers/config-as-json.js.map +1 -1
  26. package/helpers/dev-host.d.ts +274 -0
  27. package/helpers/dev-host.js +491 -0
  28. package/helpers/dev-host.js.map +1 -0
  29. package/helpers/global-defines.d.ts +51 -0
  30. package/helpers/global-defines.js +77 -0
  31. package/helpers/global-defines.js.map +1 -1
  32. package/helpers/logging.d.ts +1 -0
  33. package/helpers/logging.js +63 -3
  34. package/helpers/logging.js.map +1 -1
  35. package/helpers/main-entry.d.ts +3 -1
  36. package/helpers/main-entry.js +450 -125
  37. package/helpers/main-entry.js.map +1 -1
  38. package/helpers/nativeclass-transformer-plugin.d.ts +9 -2
  39. package/helpers/nativeclass-transformer-plugin.js +157 -14
  40. package/helpers/nativeclass-transformer-plugin.js.map +1 -1
  41. package/helpers/ns-core-url.d.ts +88 -0
  42. package/helpers/ns-core-url.js +191 -0
  43. package/helpers/ns-core-url.js.map +1 -0
  44. package/helpers/prelink-angular.js +1 -4
  45. package/helpers/prelink-angular.js.map +1 -1
  46. package/helpers/project.d.ts +35 -0
  47. package/helpers/project.js +120 -2
  48. package/helpers/project.js.map +1 -1
  49. package/helpers/resolver.js +9 -1
  50. package/helpers/resolver.js.map +1 -1
  51. package/helpers/solid-jsx-deps.d.ts +15 -0
  52. package/helpers/solid-jsx-deps.js +178 -0
  53. package/helpers/solid-jsx-deps.js.map +1 -0
  54. package/helpers/ts-config-paths.js +50 -2
  55. package/helpers/ts-config-paths.js.map +1 -1
  56. package/helpers/workers.d.ts +20 -19
  57. package/helpers/workers.js +620 -3
  58. package/helpers/workers.js.map +1 -1
  59. package/hmr/client/css-handler.d.ts +1 -0
  60. package/hmr/client/css-handler.js +34 -5
  61. package/hmr/client/css-handler.js.map +1 -1
  62. package/hmr/client/css-update-overlay.d.ts +18 -0
  63. package/hmr/client/css-update-overlay.js +27 -0
  64. package/hmr/client/css-update-overlay.js.map +1 -0
  65. package/hmr/client/hmr-pending-overlay.d.ts +27 -0
  66. package/hmr/client/hmr-pending-overlay.js +50 -0
  67. package/hmr/client/hmr-pending-overlay.js.map +1 -0
  68. package/hmr/client/index.js +491 -34
  69. package/hmr/client/index.js.map +1 -1
  70. package/hmr/client/utils.d.ts +5 -0
  71. package/hmr/client/utils.js +283 -12
  72. package/hmr/client/utils.js.map +1 -1
  73. package/hmr/client/vue-sfc-update-overlay.d.ts +82 -0
  74. package/hmr/client/vue-sfc-update-overlay.js +133 -0
  75. package/hmr/client/vue-sfc-update-overlay.js.map +1 -0
  76. package/hmr/entry-runtime.d.ts +2 -1
  77. package/hmr/entry-runtime.js +253 -66
  78. package/hmr/entry-runtime.js.map +1 -1
  79. package/hmr/frameworks/angular/client/index.d.ts +3 -1
  80. package/hmr/frameworks/angular/client/index.js +802 -10
  81. package/hmr/frameworks/angular/client/index.js.map +1 -1
  82. package/hmr/frameworks/angular/server/linker.js +1 -4
  83. package/hmr/frameworks/angular/server/linker.js.map +1 -1
  84. package/hmr/frameworks/angular/server/strategy.js +30 -6
  85. package/hmr/frameworks/angular/server/strategy.js.map +1 -1
  86. package/hmr/frameworks/typescript/server/strategy.js +8 -2
  87. package/hmr/frameworks/typescript/server/strategy.js.map +1 -1
  88. package/hmr/frameworks/vue/client/index.js +30 -45
  89. package/hmr/frameworks/vue/client/index.js.map +1 -1
  90. package/hmr/helpers/ast-normalizer.js +52 -5
  91. package/hmr/helpers/ast-normalizer.js.map +1 -1
  92. package/hmr/helpers/cjs-named-exports.d.ts +23 -0
  93. package/hmr/helpers/cjs-named-exports.js +152 -0
  94. package/hmr/helpers/cjs-named-exports.js.map +1 -0
  95. package/hmr/helpers/package-exports.d.ts +16 -0
  96. package/hmr/helpers/package-exports.js +396 -0
  97. package/hmr/helpers/package-exports.js.map +1 -0
  98. package/hmr/server/constants.js +13 -4
  99. package/hmr/server/constants.js.map +1 -1
  100. package/hmr/server/core-sanitize.d.ts +93 -8
  101. package/hmr/server/core-sanitize.js +222 -49
  102. package/hmr/server/core-sanitize.js.map +1 -1
  103. package/hmr/server/import-map.js +80 -22
  104. package/hmr/server/import-map.js.map +1 -1
  105. package/hmr/server/index.d.ts +2 -1
  106. package/hmr/server/index.js.map +1 -1
  107. package/hmr/server/ns-core-cjs-shape.d.ts +204 -0
  108. package/hmr/server/ns-core-cjs-shape.js +271 -0
  109. package/hmr/server/ns-core-cjs-shape.js.map +1 -0
  110. package/hmr/server/ns-rt-bridge.d.ts +51 -0
  111. package/hmr/server/ns-rt-bridge.js +131 -0
  112. package/hmr/server/ns-rt-bridge.js.map +1 -0
  113. package/hmr/server/perf-instrumentation.d.ts +114 -0
  114. package/hmr/server/perf-instrumentation.js +195 -0
  115. package/hmr/server/perf-instrumentation.js.map +1 -0
  116. package/hmr/server/runtime-graph-filter.d.ts +5 -0
  117. package/hmr/server/runtime-graph-filter.js +21 -0
  118. package/hmr/server/runtime-graph-filter.js.map +1 -0
  119. package/hmr/server/shared-transform-request.d.ts +12 -0
  120. package/hmr/server/shared-transform-request.js +144 -0
  121. package/hmr/server/shared-transform-request.js.map +1 -0
  122. package/hmr/server/vite-plugin.d.ts +21 -1
  123. package/hmr/server/vite-plugin.js +497 -58
  124. package/hmr/server/vite-plugin.js.map +1 -1
  125. package/hmr/server/websocket-angular-entry.d.ts +2 -0
  126. package/hmr/server/websocket-angular-entry.js +68 -0
  127. package/hmr/server/websocket-angular-entry.js.map +1 -0
  128. package/hmr/server/websocket-angular-hot-update.d.ts +78 -0
  129. package/hmr/server/websocket-angular-hot-update.js +413 -0
  130. package/hmr/server/websocket-angular-hot-update.js.map +1 -0
  131. package/hmr/server/websocket-core-bridge.d.ts +58 -0
  132. package/hmr/server/websocket-core-bridge.js +368 -0
  133. package/hmr/server/websocket-core-bridge.js.map +1 -0
  134. package/hmr/server/websocket-css-hot-update.d.ts +33 -0
  135. package/hmr/server/websocket-css-hot-update.js +65 -0
  136. package/hmr/server/websocket-css-hot-update.js.map +1 -0
  137. package/hmr/server/websocket-graph-upsert.d.ts +21 -0
  138. package/hmr/server/websocket-graph-upsert.js +33 -0
  139. package/hmr/server/websocket-graph-upsert.js.map +1 -0
  140. package/hmr/server/websocket-hmr-pending.d.ts +43 -0
  141. package/hmr/server/websocket-hmr-pending.js +55 -0
  142. package/hmr/server/websocket-hmr-pending.js.map +1 -0
  143. package/hmr/server/websocket-module-bindings.d.ts +6 -0
  144. package/hmr/server/websocket-module-bindings.js +471 -0
  145. package/hmr/server/websocket-module-bindings.js.map +1 -0
  146. package/hmr/server/websocket-module-specifiers.d.ts +101 -0
  147. package/hmr/server/websocket-module-specifiers.js +820 -0
  148. package/hmr/server/websocket-module-specifiers.js.map +1 -0
  149. package/hmr/server/websocket-ns-m-finalize.d.ts +22 -0
  150. package/hmr/server/websocket-ns-m-finalize.js +88 -0
  151. package/hmr/server/websocket-ns-m-finalize.js.map +1 -0
  152. package/hmr/server/websocket-ns-m-paths.d.ts +3 -0
  153. package/hmr/server/websocket-ns-m-paths.js +92 -0
  154. package/hmr/server/websocket-ns-m-paths.js.map +1 -0
  155. package/hmr/server/websocket-ns-m-request.d.ts +45 -0
  156. package/hmr/server/websocket-ns-m-request.js +196 -0
  157. package/hmr/server/websocket-ns-m-request.js.map +1 -0
  158. package/hmr/server/websocket-served-module-helpers.d.ts +36 -0
  159. package/hmr/server/websocket-served-module-helpers.js +644 -0
  160. package/hmr/server/websocket-served-module-helpers.js.map +1 -0
  161. package/hmr/server/websocket-txn.d.ts +6 -0
  162. package/hmr/server/websocket-txn.js +45 -0
  163. package/hmr/server/websocket-txn.js.map +1 -0
  164. package/hmr/server/websocket-vendor-unifier.d.ts +10 -0
  165. package/hmr/server/websocket-vendor-unifier.js +51 -0
  166. package/hmr/server/websocket-vendor-unifier.js.map +1 -0
  167. package/hmr/server/websocket-vue-sfc.d.ts +26 -0
  168. package/hmr/server/websocket-vue-sfc.js +1053 -0
  169. package/hmr/server/websocket-vue-sfc.js.map +1 -0
  170. package/hmr/server/websocket.d.ts +58 -75
  171. package/hmr/server/websocket.js +2232 -1802
  172. package/hmr/server/websocket.js.map +1 -1
  173. package/hmr/shared/package-classifier.d.ts +9 -0
  174. package/hmr/shared/package-classifier.js +58 -0
  175. package/hmr/shared/package-classifier.js.map +1 -0
  176. package/hmr/shared/runtime/boot-placeholder-ui.d.ts +69 -0
  177. package/hmr/shared/runtime/boot-placeholder-ui.js +101 -0
  178. package/hmr/shared/runtime/boot-placeholder-ui.js.map +1 -0
  179. package/hmr/shared/runtime/boot-progress.d.ts +40 -0
  180. package/hmr/shared/runtime/boot-progress.js +128 -0
  181. package/hmr/shared/runtime/boot-progress.js.map +1 -0
  182. package/hmr/shared/runtime/boot-timeline.d.ts +18 -0
  183. package/hmr/shared/runtime/boot-timeline.js +52 -0
  184. package/hmr/shared/runtime/boot-timeline.js.map +1 -0
  185. package/hmr/shared/runtime/browser-runtime-contract.d.ts +64 -0
  186. package/hmr/shared/runtime/browser-runtime-contract.js +54 -0
  187. package/hmr/shared/runtime/browser-runtime-contract.js.map +1 -0
  188. package/hmr/shared/runtime/dev-overlay.d.ts +78 -3
  189. package/hmr/shared/runtime/dev-overlay.js +1094 -26
  190. package/hmr/shared/runtime/dev-overlay.js.map +1 -1
  191. package/hmr/shared/runtime/module-provenance.js +1 -4
  192. package/hmr/shared/runtime/module-provenance.js.map +1 -1
  193. package/hmr/shared/runtime/root-placeholder.d.ts +1 -0
  194. package/hmr/shared/runtime/root-placeholder.js +1019 -151
  195. package/hmr/shared/runtime/root-placeholder.js.map +1 -1
  196. package/hmr/shared/runtime/session-bootstrap.d.ts +1 -0
  197. package/hmr/shared/runtime/session-bootstrap.js +309 -0
  198. package/hmr/shared/runtime/session-bootstrap.js.map +1 -0
  199. package/hmr/shared/runtime/vendor-bootstrap.js +1 -9
  200. package/hmr/shared/runtime/vendor-bootstrap.js.map +1 -1
  201. package/hmr/shared/vendor/manifest.d.ts +32 -0
  202. package/hmr/shared/vendor/manifest.js +411 -46
  203. package/hmr/shared/vendor/manifest.js.map +1 -1
  204. package/index.d.ts +1 -0
  205. package/index.js +5 -0
  206. package/index.js.map +1 -1
  207. package/package.json +9 -1
  208. package/runtime/core-aliases-early.js +94 -67
  209. package/runtime/core-aliases-early.js.map +1 -1
@@ -1,3 +1,553 @@
1
+ import { BOOT_PLACEHOLDER_MOTION, computeBootProgressFillScale, formatBootDetailLine, formatBootPrimaryLine, getBootPlaceholderPalette } from './boot-placeholder-ui.js';
2
+ import { setHmrBootStage } from './dev-overlay.js';
3
+ function isPlaceholderView(view, placeholderRoot) {
4
+ if (!view) {
5
+ return false;
6
+ }
7
+ if (placeholderRoot && view === placeholderRoot) {
8
+ return true;
9
+ }
10
+ try {
11
+ if (view.__ns_dev_placeholder) {
12
+ return true;
13
+ }
14
+ }
15
+ catch { }
16
+ return false;
17
+ }
18
+ function getCommittedRootView(application, placeholderRoot) {
19
+ const probe = (app) => {
20
+ try {
21
+ const root = app?.getRootView?.() || null;
22
+ if (!root)
23
+ return null;
24
+ if (!isPlaceholderView(root, placeholderRoot))
25
+ return root;
26
+ const currentPage = root.currentPage || root._currentEntry?.resolvedPage || null;
27
+ if (currentPage && !isPlaceholderView(currentPage, placeholderRoot))
28
+ return root;
29
+ }
30
+ catch { }
31
+ return null;
32
+ };
33
+ const primary = probe(application);
34
+ if (primary)
35
+ return primary;
36
+ // Vite HMR realm split: Angular's `Application.resetRootView` may have
37
+ // committed the real root on a different Application instance than the
38
+ // one the placeholder/early hook patched. Scan every Application we
39
+ // know about so we can detect the commit regardless of which twin
40
+ // Angular actually wrote to.
41
+ try {
42
+ const g = globalThis;
43
+ const known = g['__NS_DEV_KNOWN_APPLICATIONS__'] || [];
44
+ for (const app of known) {
45
+ if (!app || app === application)
46
+ continue;
47
+ const r = probe(app);
48
+ if (r)
49
+ return r;
50
+ }
51
+ }
52
+ catch { }
53
+ return null;
54
+ }
55
+ function getPlaceholderWaitDiagnosticSnapshot(g, application, placeholderRoot) {
56
+ const snapshot = {
57
+ bootComplete: !!g.__NS_HMR_BOOT_COMPLETE__,
58
+ hasPlaceholderRoot: !!placeholderRoot,
59
+ hasPlaceholderFlag: !!g.__NS_DEV_PLACEHOLDER_ROOT_EARLY__,
60
+ hasAngularAppRef: !!g.__NS_ANGULAR_APP_REF__,
61
+ hasAngularReboot: typeof g.__reboot_ng_modules__ === 'function',
62
+ };
63
+ try {
64
+ snapshot.applicationType = application?.constructor?.name;
65
+ snapshot.hasLaunched = typeof application?.hasLaunched === 'function' ? !!application.hasLaunched() : undefined;
66
+ snapshot.rootViewType = application?.getRootView?.()?.constructor?.name;
67
+ }
68
+ catch { }
69
+ try {
70
+ const Frame = g.Frame;
71
+ const topmost = Frame?.topmost?.() || null;
72
+ snapshot.topmostFrameType = topmost?.constructor?.name;
73
+ snapshot.topmostPageType = topmost?.currentPage?.constructor?.name || topmost?._currentEntry?.resolvedPage?.constructor?.name;
74
+ }
75
+ catch { }
76
+ return snapshot;
77
+ }
78
+ function restoreOriginalApplicationRun(g) {
79
+ const originalRun = g['__NS_DEV_ORIGINAL_APP_RUN__'];
80
+ if (typeof originalRun !== 'function') {
81
+ return;
82
+ }
83
+ const application = g['__NS_DEV_PLACEHOLDER_APPLICATION__'] || g.Application;
84
+ try {
85
+ if (application) {
86
+ application.run = originalRun;
87
+ }
88
+ }
89
+ catch { }
90
+ try {
91
+ if (g.Application && g.Application !== application) {
92
+ g.Application.run = originalRun;
93
+ }
94
+ }
95
+ catch { }
96
+ try {
97
+ const proto = application ? Object.getPrototypeOf(application) : null;
98
+ if (proto && typeof proto.run === 'function' && proto.run !== originalRun) {
99
+ proto.run = originalRun;
100
+ }
101
+ }
102
+ catch { }
103
+ delete g['__NS_DEV_ORIGINAL_APP_RUN__'];
104
+ }
105
+ function clearPlaceholderGlobals(g) {
106
+ delete g['__NS_DEV_PLACEHOLDER_ROOT_VIEW__'];
107
+ delete g['__NS_DEV_PLACEHOLDER_ROOT_EARLY__'];
108
+ delete g['__NS_DEV_BOOT_STATUS_LABEL__'];
109
+ delete g['__NS_DEV_BOOT_DETAIL_LABEL__'];
110
+ delete g['__NS_DEV_BOOT_PROGRESS_FILL__'];
111
+ delete g['__NS_DEV_BOOT_PROGRESS_LAST_SCALE__'];
112
+ delete g['__NS_DEV_BOOT_ACTIVITY_INDICATOR__'];
113
+ delete g['__NS_DEV_PLACEHOLDER_LAUNCH_HANDLER__'];
114
+ delete g['__NS_DEV_PLACEHOLDER_APPLICATION__'];
115
+ const timer = g['__NS_DEV_PLACEHOLDER_RESTORE_TIMER__'];
116
+ if (timer) {
117
+ try {
118
+ clearTimeout(timer);
119
+ }
120
+ catch { }
121
+ }
122
+ delete g['__NS_DEV_PLACEHOLDER_RESTORE_TIMER__'];
123
+ }
124
+ // Official NativeScript wordmark, dark slate on transparent. Hosted
125
+ // remotely so we don't have to ship the asset with @nativescript/vite;
126
+ // fetched once per cold boot, NS's Image element handles caching.
127
+ const NATIVESCRIPT_LOGO_URL = 'https://raw.githubusercontent.com/NativeScript/artwork/main/logo/export/NativeScript_Logo_Dark_Transparent.png';
128
+ const BRAND_MARK_SIZE = 44;
129
+ function makeColor(Color, value) {
130
+ if (!Color)
131
+ return value;
132
+ try {
133
+ return new Color(value);
134
+ }
135
+ catch {
136
+ return value;
137
+ }
138
+ }
139
+ // iOS layer-level shadow. Soft + offset down so the card reads as
140
+ // "slightly lifted off the page" without a heavy, dated drop.
141
+ function applyIosCardShadow(card, shadowHex, ColorCtor) {
142
+ const ios = card.ios;
143
+ const layer = ios?.layer;
144
+ if (!layer)
145
+ return;
146
+ if (ColorCtor) {
147
+ const shadowColor = new ColorCtor(shadowHex);
148
+ const uiColor = shadowColor.ios;
149
+ if (uiColor && typeof uiColor.CGColor !== 'undefined') {
150
+ layer.shadowColor = uiColor.CGColor;
151
+ }
152
+ }
153
+ layer.shadowOpacity = 0.18;
154
+ layer.shadowRadius = 16;
155
+ layer.shadowOffset = { width: 0, height: 6 };
156
+ layer.masksToBounds = false;
157
+ }
158
+ // Pre-load setup: keep the card invisible + slightly down-scaled so
159
+ // it doesn't flash at full opacity before the loaded handler can
160
+ // kick off the entrance animation. Called once at construction.
161
+ function primeCardForEntrance(card) {
162
+ if (!card)
163
+ return;
164
+ try {
165
+ card.opacity = 0;
166
+ card.scaleX = BOOT_PLACEHOLDER_MOTION.entranceFromScale;
167
+ card.scaleY = BOOT_PLACEHOLDER_MOTION.entranceFromScale;
168
+ }
169
+ catch { }
170
+ }
171
+ // One-shot fade + scale on attach. Triggered from `loaded` so we run
172
+ // after the view has been measured and committed to the visual tree.
173
+ // Primed via `primeCardForEntrance` to avoid a pre-animation flash.
174
+ function animateCardIn(card) {
175
+ if (!card || typeof card.animate !== 'function')
176
+ return;
177
+ try {
178
+ card
179
+ .animate({
180
+ opacity: 1,
181
+ scale: { x: 1, y: 1 },
182
+ duration: BOOT_PLACEHOLDER_MOTION.entranceDurationMs,
183
+ curve: 'easeOut',
184
+ })
185
+ .catch(() => {
186
+ try {
187
+ card.opacity = 1;
188
+ card.scaleX = 1;
189
+ card.scaleY = 1;
190
+ }
191
+ catch { }
192
+ });
193
+ }
194
+ catch { }
195
+ }
196
+ // Slow opacity pulse on the brand mark to give the otherwise-static
197
+ // card a heartbeat. Loops until boot completes (the `__NS_HMR_BOOT_COMPLETE__`
198
+ // gate) or the view is detached (animate rejects and the .catch swallows it).
199
+ function pulseBrandMark(badge) {
200
+ if (!badge || typeof badge.animate !== 'function')
201
+ return;
202
+ const g = globalThis;
203
+ if (g.__NS_HMR_BOOT_COMPLETE__)
204
+ return;
205
+ try {
206
+ badge
207
+ .animate({
208
+ opacity: BOOT_PLACEHOLDER_MOTION.brandPulseMinOpacity,
209
+ duration: BOOT_PLACEHOLDER_MOTION.brandPulseDurationMs,
210
+ curve: 'easeInOut',
211
+ })
212
+ .then(() => badge.animate({
213
+ opacity: 1,
214
+ duration: BOOT_PLACEHOLDER_MOTION.brandPulseDurationMs,
215
+ curve: 'easeInOut',
216
+ }))
217
+ .then(() => pulseBrandMark(badge))
218
+ .catch(() => { });
219
+ }
220
+ catch { }
221
+ }
222
+ function buildPlaceholderPage(ctors) {
223
+ const { Page, Label, ActivityIndicator, StackLayout, GridLayout, ContentView, Image, Color } = ctors;
224
+ const palette = getBootPlaceholderPalette('info');
225
+ const page = new Page();
226
+ page.actionBarHidden = true;
227
+ try {
228
+ page.backgroundColor = makeColor(Color, palette.pageBackground);
229
+ }
230
+ catch { }
231
+ const titleLabel = new Label();
232
+ titleLabel.text = 'NativeScript Vite preparing dev session...';
233
+ titleLabel.textAlignment = 'center';
234
+ titleLabel.textWrap = true;
235
+ titleLabel.fontSize = 18;
236
+ titleLabel.fontWeight = '700';
237
+ try {
238
+ titleLabel.color = makeColor(Color, palette.titleText);
239
+ }
240
+ catch { }
241
+ titleLabel.marginTop = 18;
242
+ const statusLabel = new Label();
243
+ statusLabel.text = 'Preparing the HTTP HMR bootstrap (4%)';
244
+ statusLabel.textAlignment = 'center';
245
+ statusLabel.textWrap = true;
246
+ statusLabel.fontSize = 13;
247
+ try {
248
+ statusLabel.color = makeColor(Color, palette.phaseText);
249
+ }
250
+ catch { }
251
+ statusLabel.marginTop = 10;
252
+ const detailLabel = new Label();
253
+ detailLabel.text = '';
254
+ detailLabel.textAlignment = 'center';
255
+ detailLabel.textWrap = true;
256
+ detailLabel.fontSize = 11;
257
+ try {
258
+ detailLabel.color = makeColor(Color, palette.detailText);
259
+ }
260
+ catch { }
261
+ detailLabel.marginTop = 12;
262
+ const activityIndicator = ActivityIndicator
263
+ ? (() => {
264
+ const indicator = new ActivityIndicator();
265
+ indicator.busy = true;
266
+ indicator.marginTop = 14;
267
+ indicator.width = 22;
268
+ indicator.height = 22;
269
+ indicator.horizontalAlignment = 'center';
270
+ try {
271
+ indicator.color = makeColor(Color, palette.activityIndicator);
272
+ }
273
+ catch { }
274
+ return indicator;
275
+ })()
276
+ : null;
277
+ let progressFill = null;
278
+ let progressTrack = null;
279
+ if (GridLayout && ContentView) {
280
+ try {
281
+ progressTrack = new GridLayout();
282
+ progressTrack.height = 6;
283
+ progressTrack.marginTop = 16;
284
+ progressTrack.marginLeft = 4;
285
+ progressTrack.marginRight = 4;
286
+ try {
287
+ progressTrack.backgroundColor = makeColor(Color, palette.progressTrack);
288
+ }
289
+ catch { }
290
+ try {
291
+ progressTrack.borderRadius = 3;
292
+ }
293
+ catch { }
294
+ progressTrack.horizontalAlignment = 'stretch';
295
+ progressFill = new ContentView();
296
+ progressFill.height = 6;
297
+ progressFill.horizontalAlignment = 'stretch';
298
+ progressFill.verticalAlignment = 'middle';
299
+ try {
300
+ progressFill.backgroundColor = makeColor(Color, palette.progressFill);
301
+ }
302
+ catch { }
303
+ try {
304
+ progressFill.borderRadius = 3;
305
+ }
306
+ catch { }
307
+ // Anchor the scale transform at the left edge so the fill
308
+ // grows rightward like a real progress bar. Starting scale
309
+ // matches `computeBootProgressFillScale(0)` = 0.01 — visible
310
+ // sliver of accent that telegraphs "we're starting".
311
+ try {
312
+ progressFill.originX = 0;
313
+ }
314
+ catch { }
315
+ progressFill.scaleX = computeBootProgressFillScale(0);
316
+ progressTrack.addChild(progressFill);
317
+ }
318
+ catch {
319
+ progressTrack = null;
320
+ progressFill = null;
321
+ }
322
+ }
323
+ const brandMark = new Image();
324
+ brandMark.src = NATIVESCRIPT_LOGO_URL;
325
+ brandMark.stretch = 'aspectFit';
326
+ brandMark.width = BRAND_MARK_SIZE;
327
+ brandMark.height = BRAND_MARK_SIZE;
328
+ brandMark.horizontalAlignment = 'center';
329
+ brandMark.on?.('loaded', () => pulseBrandMark(brandMark));
330
+ let card = null;
331
+ if (StackLayout) {
332
+ try {
333
+ card = new StackLayout();
334
+ card.padding = '24 28 22 28';
335
+ try {
336
+ card.backgroundColor = makeColor(Color, palette.cardBackground);
337
+ }
338
+ catch { }
339
+ try {
340
+ card.borderRadius = 18;
341
+ }
342
+ catch { }
343
+ card.width = 320;
344
+ card.horizontalAlignment = 'center';
345
+ if (brandMark)
346
+ card.addChild(brandMark);
347
+ card.addChild(titleLabel);
348
+ card.addChild(statusLabel);
349
+ if (progressTrack)
350
+ card.addChild(progressTrack);
351
+ card.addChild(detailLabel);
352
+ if (activityIndicator)
353
+ card.addChild(activityIndicator);
354
+ primeCardForEntrance(card);
355
+ card.on?.('loaded', () => {
356
+ try {
357
+ const ios = card.ios;
358
+ if (ios && ios.layer) {
359
+ ios.layer.cornerRadius = 18;
360
+ ios.layer.masksToBounds = false;
361
+ }
362
+ }
363
+ catch { }
364
+ applyIosCardShadow(card, palette.cardShadow, Color);
365
+ animateCardIn(card);
366
+ });
367
+ }
368
+ catch {
369
+ card = null;
370
+ }
371
+ }
372
+ if (card && GridLayout) {
373
+ try {
374
+ const root = new GridLayout();
375
+ root.horizontalAlignment = 'stretch';
376
+ root.verticalAlignment = 'stretch';
377
+ try {
378
+ root.backgroundColor = makeColor(Color, palette.pageBackground);
379
+ }
380
+ catch { }
381
+ card.verticalAlignment = 'middle';
382
+ card.horizontalAlignment = 'center';
383
+ root.addChild(card);
384
+ page.content = root;
385
+ }
386
+ catch {
387
+ page.content = card;
388
+ }
389
+ }
390
+ else if (card) {
391
+ card.verticalAlignment = 'middle';
392
+ page.content = card;
393
+ }
394
+ else if (StackLayout) {
395
+ // StackLayout exists but card creation failed — fall back to the
396
+ // minimal three-child layout the older placeholder used so the
397
+ // dev-overlay's fallback `findBootStatusLabel` walk still works.
398
+ try {
399
+ const root = new StackLayout();
400
+ root.padding = 24;
401
+ root.verticalAlignment = 'middle';
402
+ root.horizontalAlignment = 'center';
403
+ root.addChild(titleLabel);
404
+ root.addChild(statusLabel);
405
+ if (activityIndicator)
406
+ root.addChild(activityIndicator);
407
+ page.content = root;
408
+ }
409
+ catch {
410
+ titleLabel.verticalAlignment = 'middle';
411
+ titleLabel.horizontalAlignment = 'center';
412
+ titleLabel.width = 280;
413
+ titleLabel.padding = 12;
414
+ page.content = titleLabel;
415
+ }
416
+ }
417
+ else {
418
+ titleLabel.verticalAlignment = 'middle';
419
+ titleLabel.horizontalAlignment = 'center';
420
+ titleLabel.width = 280;
421
+ titleLabel.padding = 12;
422
+ page.content = titleLabel;
423
+ }
424
+ return {
425
+ page,
426
+ statusLabel,
427
+ detailLabel: card ? detailLabel : null,
428
+ progressFill,
429
+ activityIndicator,
430
+ };
431
+ }
432
+ export function tryFinalizeBootPlaceholder(reason, verbose) {
433
+ const g = globalThis;
434
+ const placeholderRoot = g['__NS_DEV_PLACEHOLDER_ROOT_VIEW__'] || null;
435
+ const hadPlaceholder = !!placeholderRoot || !!g['__NS_DEV_PLACEHOLDER_ROOT_EARLY__'] || !!g['__NS_DEV_BOOT_STATUS_LABEL__'] || !!g['__NS_DEV_BOOT_ACTIVITY_INDICATOR__'];
436
+ const application = g['__NS_DEV_PLACEHOLDER_APPLICATION__'] || g.Application;
437
+ const committedRoot = getCommittedRootView(application, placeholderRoot);
438
+ if (!committedRoot) {
439
+ // Throttled verbose-gated diagnostic. Used to be unconditional
440
+ // (with a `__NS_PLACEHOLDER_DIAG_SILENT__` opt-out) while we
441
+ // were debugging the Android "Waiting for the app root view"
442
+ // stall — now that Layer 1-9 fixes have landed, surface this
443
+ // only when the user opted into `verbose` in their HMR config.
444
+ // Still throttled to 1 Hz to avoid spamming the verbose log on
445
+ // long stalls.
446
+ try {
447
+ if (verbose) {
448
+ const now = Date.now();
449
+ const last = g.__NS_PLACEHOLDER_DIAG_LAST_FINALIZE__ || 0;
450
+ if (now - last > 1000) {
451
+ g.__NS_PLACEHOLDER_DIAG_LAST_FINALIZE__ = now;
452
+ const describe = (app) => {
453
+ try {
454
+ const r = app?.getRootView?.();
455
+ const cp = r?.currentPage || r?._currentEntry?.resolvedPage;
456
+ return {
457
+ appType: app?.constructor?.name || typeof app,
458
+ appIdentity: app === application ? 'primary' : 'alt',
459
+ rootType: r?.constructor?.name || 'null',
460
+ rootIsPlaceholder: !!r && (r === placeholderRoot || r.__ns_dev_placeholder === true),
461
+ currentPageType: cp?.constructor?.name,
462
+ };
463
+ }
464
+ catch {
465
+ return { appType: 'error' };
466
+ }
467
+ };
468
+ const known = (g['__NS_DEV_KNOWN_APPLICATIONS__'] || []);
469
+ console.warn('[ns-placeholder][diag] tryFinalize: no committed root', {
470
+ reason,
471
+ hadPlaceholder,
472
+ placeholderRootType: placeholderRoot?.constructor?.name,
473
+ primary: describe(application),
474
+ knownApplications: known.length,
475
+ alts: known.filter((a) => a && a !== application).map(describe),
476
+ });
477
+ }
478
+ }
479
+ }
480
+ catch { }
481
+ return false;
482
+ }
483
+ let detachedPlaceholder = false;
484
+ if (hadPlaceholder) {
485
+ try {
486
+ const launchHandler = g['__NS_DEV_PLACEHOLDER_LAUNCH_HANDLER__'];
487
+ if (application && typeof application.off === 'function' && launchHandler) {
488
+ application.off(application.launchEvent, launchHandler);
489
+ }
490
+ }
491
+ catch { }
492
+ restoreOriginalApplicationRun(g);
493
+ clearPlaceholderGlobals(g);
494
+ detachedPlaceholder = true;
495
+ }
496
+ try {
497
+ g.__NS_HMR_BOOT_COMPLETE__ = true;
498
+ }
499
+ catch { }
500
+ if (detachedPlaceholder) {
501
+ setHmrBootStage('app-root-committed', {
502
+ detail: 'The real app root replaced the boot placeholder.',
503
+ });
504
+ }
505
+ if (verbose) {
506
+ console.info('[ns-placeholder] real app root committed', {
507
+ reason,
508
+ rootType: committedRoot?.constructor?.name || typeof committedRoot,
509
+ detachedPlaceholder,
510
+ });
511
+ }
512
+ return true;
513
+ }
514
+ function scheduleBootPlaceholderFinalize(reason, verbose) {
515
+ const g = globalThis;
516
+ if (g['__NS_DEV_PLACEHOLDER_RESTORE_TIMER__']) {
517
+ return;
518
+ }
519
+ const startedAt = Date.now();
520
+ const maxWaitMs = 20000;
521
+ let attempts = 0;
522
+ const tick = () => {
523
+ delete g['__NS_DEV_PLACEHOLDER_RESTORE_TIMER__'];
524
+ if (tryFinalizeBootPlaceholder(reason, verbose)) {
525
+ return;
526
+ }
527
+ attempts += 1;
528
+ if (Date.now() - startedAt >= maxWaitMs) {
529
+ // Verbose-gated — used to be unconditional with a
530
+ // `__NS_PLACEHOLDER_DIAG_SILENT__` opt-out while we were
531
+ // debugging the Android stall. Now that the stall is
532
+ // resolved, users investigating a new stall should enable
533
+ // `verbose` in their HMR config to see this warning.
534
+ try {
535
+ if (verbose) {
536
+ console.warn('[ns-placeholder][diag] waiting for real root commit TIMED OUT', {
537
+ reason,
538
+ attempts,
539
+ waitMs: Date.now() - startedAt,
540
+ state: getPlaceholderWaitDiagnosticSnapshot(g, g['__NS_DEV_PLACEHOLDER_APPLICATION__'] || g.Application, g['__NS_DEV_PLACEHOLDER_ROOT_VIEW__'] || null),
541
+ });
542
+ }
543
+ }
544
+ catch { }
545
+ return;
546
+ }
547
+ g['__NS_DEV_PLACEHOLDER_RESTORE_TIMER__'] = setTimeout(tick, attempts === 1 ? 0 : 100);
548
+ };
549
+ tick();
550
+ }
1
551
  // Root placeholder installer used during dev HMR until HTTP ESM loads.
2
552
  //
3
553
  // Architecture:
@@ -14,107 +564,323 @@ export function installRootPlaceholder(verbose) {
14
564
  if (g['__NS_DEV_PLACEHOLDER_ROOT_EARLY__'])
15
565
  return;
16
566
  g['__NS_DEV_PLACEHOLDER_ROOT_EARLY__'] = true;
567
+ g['__NS_DEV_RESTORE_PLACEHOLDER__'] = (reason) => {
568
+ if (!tryFinalizeBootPlaceholder(reason, verbose)) {
569
+ scheduleBootPlaceholderFinalize(reason, verbose);
570
+ }
571
+ };
17
572
  try {
573
+ const resolveModule = (moduleIds) => {
574
+ for (const moduleId of moduleIds) {
575
+ try {
576
+ if (typeof g.moduleExists === 'function' && g.moduleExists(moduleId) && typeof g.loadModule === 'function') {
577
+ const mod = g.loadModule(moduleId);
578
+ if (mod)
579
+ return { value: (mod.default ?? mod) || mod, via: 'loadModule', moduleId };
580
+ }
581
+ }
582
+ catch { }
583
+ try {
584
+ const reg = g.__nsVendorRegistry;
585
+ if (reg?.has?.(moduleId)) {
586
+ const mod = reg.get(moduleId);
587
+ if (mod)
588
+ return { value: (mod.default ?? mod) || mod, via: '__nsVendorRegistry', moduleId };
589
+ }
590
+ }
591
+ catch { }
592
+ try {
593
+ const req = g.__nsVendorRequire || g.__nsRequire || g.require;
594
+ if (typeof req === 'function') {
595
+ const mod = req(moduleId);
596
+ if (mod)
597
+ return { value: (mod.default ?? mod) || mod, via: 'require', moduleId };
598
+ }
599
+ }
600
+ catch { }
601
+ try {
602
+ const nr = g.__nativeRequire;
603
+ if (typeof nr === 'function') {
604
+ const mod = nr(moduleId, '/');
605
+ if (mod)
606
+ return { value: (mod.default ?? mod) || mod, via: '__nativeRequire', moduleId };
607
+ }
608
+ }
609
+ catch { }
610
+ }
611
+ return undefined;
612
+ };
18
613
  const getCore = (name) => {
19
- try {
20
- const reg = g.__nsVendorRegistry;
21
- const req = reg?.get ? g.__nsVendorRequire || g.__nsRequire || g.require : g.__nsRequire || g.require;
22
- let mod = null;
23
- if (reg && reg.has('@nativescript/core'))
24
- mod = reg.get('@nativescript/core');
25
- else if (typeof req === 'function') {
26
- try {
27
- mod = req('@nativescript/core');
614
+ if (name === 'Application' && g.Application && (typeof g.Application.run === 'function' || typeof g.Application.on === 'function' || typeof g.Application.resetRootView === 'function')) {
615
+ return { value: g.Application, source: 'globalThis.Application' };
616
+ }
617
+ const pickApplicationApi = (candidate, source) => {
618
+ if (!candidate)
619
+ return null;
620
+ const candidates = [
621
+ { value: candidate, source },
622
+ { value: candidate.Application, source: `${source}#Application` },
623
+ { value: candidate.app, source: `${source}#app` },
624
+ { value: candidate.application, source: `${source}#application` },
625
+ ];
626
+ for (const entry of candidates) {
627
+ if (entry.value && (typeof entry.value.run === 'function' || typeof entry.value.on === 'function' || typeof entry.value.resetRootView === 'function')) {
628
+ return entry;
28
629
  }
29
- catch { }
30
630
  }
31
- const ns = (mod && (mod.default ?? mod)) || mod;
32
- if (name === 'Application' && ns && (ns.Application || ns))
33
- return ns.Application || ns;
34
- if (ns && ns[name])
35
- return ns[name];
631
+ return null;
632
+ };
633
+ if (name === 'Application') {
634
+ const applicationModule = resolveModule(['@nativescript/core/application']);
635
+ const pickedFromAppModule = pickApplicationApi(applicationModule?.value, applicationModule ? `${applicationModule.via}:${applicationModule.moduleId}` : '@nativescript/core/application');
636
+ if (pickedFromAppModule)
637
+ return pickedFromAppModule;
36
638
  }
37
- catch { }
639
+ const primary = resolveModule(['@nativescript/core']);
640
+ if (name === 'Application' && primary?.value) {
641
+ const pickedFromPrimary = pickApplicationApi(primary.value, `${primary.via}:${primary.moduleId}`);
642
+ if (pickedFromPrimary)
643
+ return pickedFromPrimary;
644
+ }
645
+ if (primary?.value && primary.value[name])
646
+ return { value: primary.value[name], source: `${primary.via}:${primary.moduleId}` };
647
+ const ui = resolveModule(['@nativescript/core/ui']);
648
+ if (ui?.value && ui.value[name])
649
+ return { value: ui.value[name], source: `${ui.via}:${ui.moduleId}` };
650
+ return { value: undefined, source: 'unresolved' };
651
+ };
652
+ const applicationResolved = getCore('Application');
653
+ const frameResolved = getCore('Frame');
654
+ const pageResolved = getCore('Page');
655
+ const labelResolved = getCore('Label');
656
+ const activityResolved = getCore('ActivityIndicator');
657
+ const Application = applicationResolved.value;
658
+ const Frame = frameResolved.value;
659
+ const Page = pageResolved.value;
660
+ const Label = labelResolved.value;
661
+ const ActivityIndicator = activityResolved.value;
662
+ if (!Application) {
663
+ if (verbose) {
664
+ console.warn('[ns-placeholder] Application unavailable', {
665
+ resolution: {
666
+ Application: applicationResolved.source,
667
+ Frame: frameResolved.source,
668
+ Page: pageResolved.source,
669
+ Label: labelResolved.source,
670
+ },
671
+ moduleApis: {
672
+ moduleExists: typeof g.moduleExists === 'function',
673
+ loadModule: typeof g.loadModule === 'function',
674
+ uiModuleRegistered: typeof g.moduleExists === 'function' ? !!g.moduleExists('@nativescript/core/ui') : false,
675
+ },
676
+ });
677
+ }
678
+ return;
679
+ }
680
+ g['__NS_DEV_PLACEHOLDER_APPLICATION__'] = Application;
681
+ const isAndroid = !!(g.__ANDROID__ || typeof g.android !== 'undefined');
682
+ // Patch `Application.resetRootView` on BOTH platforms so the placeholder
683
+ // finalize callback (`__NS_DEV_RESTORE_PLACEHOLDER__`) fires every time
684
+ // the framework swaps the root view.
685
+ //
686
+ // History: this used to be gated behind `!isAndroid` on the assumption
687
+ // that `core-aliases-early.ts` already installs an Android-specific
688
+ // `resetRootView` wrapper. That early hook is unreliable in HTTP HMR
689
+ // boot — it runs before `@nativescript/core/bundle-entry-points`, so
690
+ // `g.Application` is undefined when it runs and the wrapper is silently
691
+ // skipped. By the time `installRootPlaceholder` reaches this point,
692
+ // `getCore('Application')` has resolved a real Application (the
693
+ // placeholder UI is already showing, which proves it), so wrapping here
694
+ // works on Android too. We also coordinate with the early hook's flag
695
+ // (`__NS_DEV_PATCHED_RESET_ROOT__`) so we never double-wrap if it did
696
+ // install successfully.
697
+ const earlyAndroidWrapped = !!g['__NS_DEV_PATCHED_RESET_ROOT__'];
698
+ // Verbose-gated. Previously this was unconditional with a
699
+ // `__NS_PLACEHOLDER_DIAG_SILENT__` opt-out — needed while we
700
+ // were debugging the Android "Waiting for the app root view"
701
+ // stall. Now that Layer 1-9 fixes have landed, the diag stream
702
+ // (resetRootView wraps, launch-handler entries, placeholder
703
+ // install state) is only useful when investigating a new
704
+ // stall, so it follows the user's `verbose` opt-in.
705
+ const diag = verbose
706
+ ? (...args) => {
707
+ try {
708
+ console.warn('[ns-placeholder][diag]', ...args);
709
+ }
710
+ catch { }
711
+ }
712
+ : () => { };
713
+ diag('install entry', {
714
+ platform: isAndroid ? 'android' : 'ios',
715
+ applicationSource: applicationResolved.source,
716
+ applicationType: Application?.constructor?.name,
717
+ hasReset: typeof Application.resetRootView === 'function',
718
+ alreadyPatchedEarly: earlyAndroidWrapped,
719
+ alreadyPatchedView: !!g['__NS_DEV_PATCHED_RESET_ROOT_VIEW__'],
720
+ globalApplicationSame: g.Application === Application,
721
+ vendorApplicationSame: (() => {
722
+ try {
723
+ const v = g.__nsVendorRegistry?.get?.('@nativescript/core');
724
+ return v?.Application === Application || v?.default?.Application === Application;
725
+ }
726
+ catch {
727
+ return null;
728
+ }
729
+ })(),
730
+ });
731
+ // Always patch every Application instance we can find. The early
732
+ // Android hook in `core-aliases-early.ts` only patches `g.Application`
733
+ // (the bundled realm's Application) and its prototype — but on Vite
734
+ // HMR there can be a SECOND Application loaded by the HTTP realm
735
+ // (`vendor-registry @nativescript/core`) that Angular's `import { Application }`
736
+ // actually resolves to. If we don't patch that twin too, Angular's
737
+ // `Application.resetRootView({ create: () => doc })` lands on an
738
+ // unpatched object, the placeholder finalize callback is never
739
+ // invoked, and the boot stalls at "Waiting for the app root view".
740
+ const makePatched = (origReset, label) => function __ns_dev_patched_reset_root_view(entry) {
741
+ diag(`patched resetRootView called (${label})`, {
742
+ hasEntry: !!entry,
743
+ entryKind: entry?.create ? 'create-fn' : entry?.moduleName ? 'module-name' : typeof entry,
744
+ });
745
+ const result = origReset(entry);
746
+ try {
747
+ const restore = g['__NS_DEV_RESTORE_PLACEHOLDER__'];
748
+ if (typeof restore === 'function') {
749
+ restore(`Application.resetRootView (${label})`);
750
+ }
751
+ }
752
+ catch (e) {
753
+ diag('patched resetRootView restore threw', String(e && (e.message || e)));
754
+ }
755
+ return result;
756
+ };
757
+ const wrapOnce = (target, label) => {
38
758
  try {
39
- const nr = g.__nativeRequire;
40
- if (typeof nr === 'function') {
759
+ if (!target || typeof target.resetRootView !== 'function')
760
+ return false;
761
+ if (target.resetRootView.__ns_dev_placeholder_wrap === true)
762
+ return false;
763
+ const orig = target.resetRootView.bind(target);
764
+ const wrapped = makePatched(orig, label);
765
+ wrapped.__ns_dev_placeholder_wrap = true;
766
+ target.resetRootView = wrapped;
767
+ return true;
768
+ }
769
+ catch {
770
+ return false;
771
+ }
772
+ };
773
+ const wrappedLocal = wrapOnce(Application, 'local');
774
+ const wrappedGlobal = g.Application && g.Application !== Application ? wrapOnce(g.Application, 'global') : false;
775
+ const wrappedProto = (() => {
776
+ try {
777
+ const proto = Object.getPrototypeOf(Application);
778
+ return wrapOnce(proto, 'proto');
779
+ }
780
+ catch {
781
+ return false;
782
+ }
783
+ })();
784
+ // Vendor-realm Application coverage. Even when `earlyAndroidWrapped`
785
+ // is true, the early hook only touched `g.Application` + its proto;
786
+ // the vendor's Application is a separate object with its own
787
+ // `resetRootView` that the early hook never sees.
788
+ let wrappedVendor = false;
789
+ let wrappedVendorAppModule = false;
790
+ try {
791
+ const reg = g.__nsVendorRegistry;
792
+ if (reg && typeof reg.get === 'function') {
793
+ const vendorCore = reg.get('@nativescript/core');
794
+ const vendorApp = vendorCore?.Application || vendorCore?.default?.Application;
795
+ if (vendorApp && vendorApp !== Application) {
796
+ wrappedVendor = wrapOnce(vendorApp, 'vendor-core');
41
797
  try {
42
- const mod = nr('@nativescript/core', '/');
43
- const ns = (mod && (mod.default ?? mod)) || mod;
44
- if (name === 'Application' && ns && (ns.Application || ns))
45
- return ns.Application || ns;
46
- if (ns && ns[name])
47
- return ns[name];
798
+ const vp = Object.getPrototypeOf(vendorApp);
799
+ if (vp && vp !== Object.getPrototypeOf(Application)) {
800
+ wrapOnce(vp, 'vendor-core-proto');
801
+ }
48
802
  }
49
803
  catch { }
50
804
  }
805
+ const vendorAppMod = reg.get('@nativescript/core/application');
806
+ const vendorAppOnly = vendorAppMod?.Application || vendorAppMod?.default?.Application;
807
+ if (vendorAppOnly && vendorAppOnly !== Application && vendorAppOnly !== vendorApp) {
808
+ wrappedVendorAppModule = wrapOnce(vendorAppOnly, 'vendor-application');
809
+ }
810
+ }
811
+ }
812
+ catch { }
813
+ // Track every Application instance we know about so
814
+ // `tryFinalizeBootPlaceholder` can poll the real root view on the
815
+ // instance Angular actually committed to.
816
+ try {
817
+ const apps = (g['__NS_DEV_KNOWN_APPLICATIONS__'] || (g['__NS_DEV_KNOWN_APPLICATIONS__'] = []));
818
+ const push = (a) => {
819
+ if (a && apps.indexOf(a) === -1)
820
+ apps.push(a);
821
+ };
822
+ push(Application);
823
+ push(g.Application);
824
+ try {
825
+ const reg = g.__nsVendorRegistry;
826
+ if (reg && typeof reg.get === 'function') {
827
+ const vendorCore = reg.get('@nativescript/core');
828
+ push(vendorCore?.Application);
829
+ push(vendorCore?.default?.Application);
830
+ const vendorAppMod = reg.get('@nativescript/core/application');
831
+ push(vendorAppMod?.Application);
832
+ push(vendorAppMod?.default?.Application);
833
+ }
51
834
  }
52
835
  catch { }
53
- return undefined;
54
- };
55
- const Application = getCore('Application');
56
- const Frame = getCore('Frame');
57
- const Page = getCore('Page');
58
- const Label = getCore('Label');
59
- const ActivityIndicator = getCore('ActivityIndicator');
60
- if (!Application || !Frame || !Page || !Label) {
61
- if (verbose)
62
- console.warn('[ns-placeholder] core classes unavailable');
63
- return;
836
+ }
837
+ catch { }
838
+ g['__NS_DEV_PATCHED_RESET_ROOT_VIEW__'] = true;
839
+ g['__NS_DEV_PATCHED_RESET_ROOT__'] = true;
840
+ diag('patched Application.resetRootView', {
841
+ platform: isAndroid ? 'android' : 'ios',
842
+ wrappedLocal,
843
+ wrappedGlobal,
844
+ wrappedProto,
845
+ wrappedVendor,
846
+ wrappedVendorAppModule,
847
+ knownApplications: (g['__NS_DEV_KNOWN_APPLICATIONS__'] || []).length,
848
+ });
849
+ const canCreatePlaceholderRoot = !!Frame && !!Page && !!Label;
850
+ if (!canCreatePlaceholderRoot && verbose) {
851
+ console.warn('[ns-placeholder] visual placeholder unavailable; starting lifecycle without placeholder root', {
852
+ resolution: {
853
+ Application: applicationResolved.source,
854
+ Frame: frameResolved.source,
855
+ Page: pageResolved.source,
856
+ Label: labelResolved.source,
857
+ ActivityIndicator: activityResolved.source,
858
+ },
859
+ moduleApis: {
860
+ moduleExists: typeof g.moduleExists === 'function',
861
+ loadModule: typeof g.loadModule === 'function',
862
+ uiModuleRegistered: typeof g.moduleExists === 'function' ? !!g.moduleExists('@nativescript/core/ui') : false,
863
+ },
864
+ });
64
865
  }
65
866
  let handlerFired = false;
66
867
  // launchEvent handler: provides a placeholder root, then patches Application.run
67
868
  const __ns_launch_handler = (args) => {
869
+ diag('launch handler fired', {
870
+ hasArgs: !!args,
871
+ hasExistingRoot: !!args?.root,
872
+ existingRootType: args?.root?.constructor?.name,
873
+ hasLaunched: typeof Application.hasLaunched === 'function' ? !!Application.hasLaunched() : undefined,
874
+ started: !!Application.started,
875
+ });
68
876
  try {
69
877
  const prev = args?.root;
70
- if (!prev && Frame && Page && Label) {
71
- const StackLayout = getCore('StackLayout');
72
- const page = new Page();
73
- page.actionBarHidden = true;
74
- const titleLabel = new Label();
75
- titleLabel.text = 'Starting NativeScript + Vite dev server…';
76
- titleLabel.textAlignment = 'center';
77
- titleLabel.textWrap = true;
78
- titleLabel.fontSize = 20;
79
- const statusLabel = new Label();
80
- statusLabel.text = 'Preparing the HTTP HMR bootstrap (4%)';
81
- statusLabel.textAlignment = 'center';
82
- statusLabel.textWrap = true;
83
- statusLabel.fontSize = 14;
84
- statusLabel.marginTop = 12;
85
- const activityIndicator = ActivityIndicator
86
- ? (() => {
87
- const indicator = new ActivityIndicator();
88
- indicator.busy = true;
89
- indicator.marginTop = 16;
90
- indicator.width = 28;
91
- indicator.height = 28;
92
- indicator.horizontalAlignment = 'center';
93
- return indicator;
94
- })()
95
- : null;
96
- if (StackLayout) {
97
- const root = new StackLayout();
98
- root.padding = 24;
99
- root.verticalAlignment = 'middle';
100
- root.horizontalAlignment = 'center';
101
- root.addChild(titleLabel);
102
- root.addChild(statusLabel);
103
- if (activityIndicator) {
104
- root.addChild(activityIndicator);
105
- }
106
- page.content = root;
107
- }
108
- else {
109
- // Fallback: just show the title label centered
110
- titleLabel.verticalAlignment = 'middle';
111
- titleLabel.horizontalAlignment = 'center';
112
- titleLabel.width = 280;
113
- titleLabel.padding = 12;
114
- page.content = titleLabel;
115
- }
116
- // Store refs so the overlay API can update the status label
878
+ if (!prev && canCreatePlaceholderRoot && Frame && Page && Label) {
879
+ const built = buildPlaceholderPage({ Page, Label, ActivityIndicator, StackLayout: getCore('StackLayout').value, GridLayout: getCore('GridLayout').value, ContentView: getCore('ContentView').value, Image: getCore('Image').value, Color: getCore('Color').value, verbose });
880
+ const { page, statusLabel, detailLabel, progressFill, activityIndicator } = built;
117
881
  g['__NS_DEV_BOOT_STATUS_LABEL__'] = statusLabel;
882
+ g['__NS_DEV_BOOT_DETAIL_LABEL__'] = detailLabel;
883
+ g['__NS_DEV_BOOT_PROGRESS_FILL__'] = progressFill;
118
884
  g['__NS_DEV_BOOT_ACTIVITY_INDICATOR__'] = activityIndicator;
119
885
  const frame = new Frame();
120
886
  frame.navigate({ create: () => page, clearHistory: true, animated: false });
@@ -124,6 +890,14 @@ export function installRootPlaceholder(verbose) {
124
890
  g['__NS_DEV_PLACEHOLDER_ROOT_VIEW__'] = frame;
125
891
  }
126
892
  catch { }
893
+ if (verbose) {
894
+ console.info('[ns-placeholder] assigned placeholder root', {
895
+ frameType: frame?.constructor?.name,
896
+ pageType: page?.constructor?.name,
897
+ hasProgressFill: !!progressFill,
898
+ hasActivityIndicator: !!activityIndicator,
899
+ });
900
+ }
127
901
  if (args)
128
902
  args.root = frame;
129
903
  }
@@ -144,76 +918,121 @@ export function installRootPlaceholder(verbose) {
144
918
  if (Application && typeof Application.run === 'function') {
145
919
  const _originalRun = Application.run.bind(Application);
146
920
  g['__NS_DEV_ORIGINAL_APP_RUN__'] = _originalRun;
921
+ // HMR ordering invariant: the patched `Application.run` MUST yield
922
+ // back to the synchronous caller before any iOS view-lifecycle event
923
+ // fires on the new root view.
924
+ //
925
+ // Concrete bug this guards against: nativescript-vue's `app.start()` is
926
+ // const componentInstance = app.mount(createAppRoot(), false, false);
927
+ // startApp(componentInstance); // → Application.run({ create: … })
928
+ // setRootApp(app); // — sets the module-private `rootApp`
929
+ // In a non-HMR build `Application.run` is `UIApplicationMain`, which
930
+ // returns control to the iOS runloop and lets `setRootApp(app)` execute
931
+ // before any `loaded`/`traitCollectionDidChange` callbacks fire. Under
932
+ // HMR `Application.run` is replaced with synchronous `resetRootView`,
933
+ // which attaches the root to the window *inside* this call — iOS then
934
+ // synchronously fires `loaded` on the new view tree, a TabView handler
935
+ // calls `nativescript-vue`'s `createNativeView`, that reads
936
+ // `rootApp._context`, and crashes with
937
+ // TypeError: Cannot read properties of null (reading '_context')
938
+ // because `setRootApp(app)` hasn't run yet.
939
+ //
940
+ // `setRootApp` is module-private inside the vendor bundle, so the bridge
941
+ // cannot call it directly. Deferring the synchronous root attachment to a
942
+ // microtask restores the production timing: every consumer that called
943
+ // `Application.run(entry)` completes its tail (including private state
944
+ // setters like `setRootApp`) before iOS triggers lifecycle on the new
945
+ // root. The microtask runs before any I/O or DOM-tick boundary, so the UI
946
+ // still appears in the same iOS runloop turn — no user-visible delay.
147
947
  const __ns_dev_patched_run = function __ns_dev_patched_run(entry) {
948
+ diag('patched Application.run called', {
949
+ hasEntry: !!entry,
950
+ entryKind: entry?.create ? 'create-fn' : entry?.moduleName ? 'module-name' : typeof entry,
951
+ });
952
+ // Detach the launch handler synchronously: by the time the caller
953
+ // returned from `Application.run()`, the framework owns root-view
954
+ // management, and we must not re-enter the placeholder path on a
955
+ // subsequent launch tick.
148
956
  try {
149
- // Clean up: remove launchEvent handler and placeholder references
150
- try {
151
- if (Application && Application.off) {
152
- Application.off(Application.launchEvent, __ns_launch_handler);
153
- }
957
+ if (Application && Application.off) {
958
+ Application.off(Application.launchEvent, __ns_launch_handler);
154
959
  }
155
- catch { }
156
- delete g['__NS_DEV_PLACEHOLDER_ROOT_VIEW__'];
157
- delete g['__NS_DEV_PLACEHOLDER_ROOT_EARLY__'];
158
- // When entry is undefined/null, the calling framework (e.g. Angular)
159
- // manages root views itself via launch events and resetRootView().
160
- // Don't attempt resetRootView(undefined) which throws "Main entry is missing".
161
- if (!entry) {
162
- if (verbose)
163
- console.info('[ns-placeholder] patched run() called with no entry; framework manages root view');
164
- return;
165
- }
166
- const isModuleNameEntry = entry && entry.moduleName && !entry.create;
167
- if (isModuleNameEntry) {
168
- if (typeof Application.resetRootView === 'function') {
169
- Application.resetRootView(entry);
960
+ }
961
+ catch { }
962
+ // Frameworks (notably Angular) call `Application.run()` with no
963
+ // entry they own the root via launch events and `resetRootView()`
964
+ // directly. Bailing here keeps `resetRootView(undefined)` from
965
+ // throwing "Main entry is missing".
966
+ if (!entry) {
967
+ diag('patched run() called with no entry; framework manages root view');
968
+ return;
969
+ }
970
+ // Snapshot for the deferred body so a later mutation by the caller
971
+ // can't observe a half-finished closure.
972
+ const __ns_deferred_entry = entry;
973
+ const __ns_deferred_reset = () => {
974
+ try {
975
+ const isModuleNameEntry = __ns_deferred_entry && __ns_deferred_entry.moduleName && !__ns_deferred_entry.create;
976
+ if (isModuleNameEntry) {
977
+ if (typeof Application.resetRootView === 'function') {
978
+ Application.resetRootView(__ns_deferred_entry);
979
+ }
170
980
  }
171
- }
172
- else {
173
- // Framework path: two-phase boot with dominative document
174
- Application._rootView = null;
175
- try {
176
- const domModule = g.__nsVendorRegistry?.get?.('dominative') ||
177
- (typeof require === 'function'
178
- ? (() => {
179
- try {
180
- return require('dominative');
181
- }
182
- catch {
183
- return null;
184
- }
185
- })()
186
- : null);
187
- const doc = domModule?.document;
188
- if (doc && typeof Application.resetRootView === 'function') {
189
- Application.resetRootView({ create: () => doc });
190
- if (entry && typeof entry.create === 'function') {
191
- entry.create();
981
+ else {
982
+ // Framework path: two-phase boot with dominative document
983
+ Application._rootView = null;
984
+ try {
985
+ const domModule = g.__nsVendorRegistry?.get?.('dominative') ||
986
+ (typeof require === 'function'
987
+ ? (() => {
988
+ try {
989
+ return require('dominative');
990
+ }
991
+ catch {
992
+ return null;
993
+ }
994
+ })()
995
+ : null);
996
+ const doc = domModule?.document;
997
+ if (doc && typeof Application.resetRootView === 'function') {
998
+ Application.resetRootView({ create: () => doc });
999
+ if (__ns_deferred_entry && typeof __ns_deferred_entry.create === 'function') {
1000
+ __ns_deferred_entry.create();
1001
+ }
192
1002
  }
193
- }
194
- else {
195
- if (typeof Application.resetRootView === 'function') {
196
- Application.resetRootView(entry);
1003
+ else {
1004
+ if (typeof Application.resetRootView === 'function') {
1005
+ Application.resetRootView(__ns_deferred_entry);
1006
+ }
197
1007
  }
198
1008
  }
199
- }
200
- catch (e2) {
201
- if (verbose)
202
- console.warn('[ns-placeholder] two-phase boot failed:', e2?.message || e2);
203
- try {
204
- if (typeof Application.resetRootView === 'function') {
205
- Application.resetRootView(entry);
1009
+ catch (e2) {
1010
+ if (verbose)
1011
+ console.warn('[ns-placeholder] two-phase boot failed:', e2?.message || e2);
1012
+ try {
1013
+ if (typeof Application.resetRootView === 'function') {
1014
+ Application.resetRootView(__ns_deferred_entry);
1015
+ }
206
1016
  }
1017
+ catch { }
207
1018
  }
208
- catch { }
209
1019
  }
210
1020
  }
211
- }
212
- catch (e) {
213
- console.warn('[ns-placeholder] patched run() error:', e);
214
- }
1021
+ catch (e) {
1022
+ console.warn('[ns-placeholder] deferred patched run() error:', e);
1023
+ }
1024
+ };
1025
+ // Microtask-defer. `Promise.resolve().then(...)` lands the callback
1026
+ // in the same iOS runloop turn — no perceptible delay — but only
1027
+ // after the synchronous call stack that invoked `Application.run`
1028
+ // has fully unwound, so `nativescript-vue`'s post-`startApp` code
1029
+ // (`setRootApp(app);`) has executed before any view lifecycle fires.
1030
+ Promise.resolve().then(__ns_deferred_reset);
215
1031
  };
216
1032
  Application.run = __ns_dev_patched_run;
1033
+ if (verbose) {
1034
+ console.info('[ns-placeholder] patched Application.run');
1035
+ }
217
1036
  if (g.Application && g.Application !== Application) {
218
1037
  g.Application.run = __ns_dev_patched_run;
219
1038
  }
@@ -229,6 +1048,7 @@ export function installRootPlaceholder(verbose) {
229
1048
  catch { }
230
1049
  }
231
1050
  };
1051
+ g['__NS_DEV_PLACEHOLDER_LAUNCH_HANDLER__'] = __ns_launch_handler;
232
1052
  try {
233
1053
  if (Application && Application.on) {
234
1054
  Application.on(Application.launchEvent, __ns_launch_handler);
@@ -237,20 +1057,68 @@ export function installRootPlaceholder(verbose) {
237
1057
  catch { }
238
1058
  // Determine boot path
239
1059
  try {
240
- if (Application && typeof Application.run === 'function') {
241
- const nativeApp = Application.nativeApp;
242
- const iosNativeApp = Application.ios?.nativeApp;
243
- if (nativeApp || iosNativeApp) {
244
- // App already running (v9 runtime) — skip Application.run() to avoid
245
- // runAsEmbeddedApp's modal presentViewController.
246
- try {
247
- __ns_launch_handler();
248
- }
249
- catch { }
1060
+ const appAny = Application;
1061
+ const methodState = {
1062
+ hasRun: typeof appAny?.run === 'function',
1063
+ hasOn: typeof appAny?.on === 'function',
1064
+ hasOff: typeof appAny?.off === 'function',
1065
+ hasHasLaunched: typeof appAny?.hasLaunched === 'function',
1066
+ hasGetRootView: typeof appAny?.getRootView === 'function',
1067
+ hasResetRootView: typeof appAny?.resetRootView === 'function',
1068
+ hasRunAsMainApp: typeof appAny?.runAsMainApp === 'function',
1069
+ type: appAny?.constructor?.name,
1070
+ };
1071
+ if (verbose) {
1072
+ console.info('[ns-placeholder] application methods', methodState);
1073
+ console.info('[ns-placeholder] application source', applicationResolved.source);
1074
+ }
1075
+ if (!appAny || typeof appAny.run !== 'function') {
1076
+ console.warn('[ns-placeholder] Application.run unavailable', {
1077
+ ...methodState,
1078
+ source: applicationResolved.source,
1079
+ });
1080
+ return;
1081
+ }
1082
+ const hasLaunched = typeof appAny.hasLaunched === 'function' ? !!appAny.hasLaunched() : false;
1083
+ const hasRootView = typeof appAny.getRootView === 'function' ? !!appAny.getRootView() : false;
1084
+ const started = !!appAny.started;
1085
+ const nativeApp = appAny.nativeApp;
1086
+ const iosNativeApp = appAny.ios?.nativeApp;
1087
+ const canRunAsMainApp = typeof appAny.runAsMainApp === 'function';
1088
+ if (verbose) {
1089
+ console.info('[ns-placeholder] boot state', {
1090
+ hasLaunched,
1091
+ hasRootView,
1092
+ started,
1093
+ nativeApp: !!nativeApp,
1094
+ iosNativeApp: !!iosNativeApp,
1095
+ canRunAsMainApp,
1096
+ hasResetRootView: typeof appAny.resetRootView === 'function',
1097
+ });
1098
+ }
1099
+ if (hasLaunched || hasRootView) {
1100
+ // App lifecycle is already active. Skip starting it again and only install
1101
+ // the placeholder root/patching behavior for the existing instance.
1102
+ if (verbose) {
1103
+ console.info('[ns-placeholder] boot branch: existing lifecycle');
1104
+ }
1105
+ try {
1106
+ __ns_launch_handler();
250
1107
  }
251
- else {
252
- Application.run();
1108
+ catch { }
1109
+ }
1110
+ else if (canRunAsMainApp) {
1111
+ if (verbose) {
1112
+ console.info('[ns-placeholder] boot branch: runAsMainApp');
1113
+ }
1114
+ appAny.started = true;
1115
+ appAny.runAsMainApp();
1116
+ }
1117
+ else {
1118
+ if (verbose) {
1119
+ console.info('[ns-placeholder] boot branch: Application.run');
253
1120
  }
1121
+ appAny.run();
254
1122
  }
255
1123
  }
256
1124
  catch (e) {