@nativescript/vite 8.0.0-alpha.3 → 8.0.0-alpha.30

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 (295) hide show
  1. package/README.md +51 -11
  2. package/configuration/angular.d.ts +34 -1
  3. package/configuration/angular.js +369 -159
  4. package/configuration/angular.js.map +1 -1
  5. package/configuration/base.js +184 -14
  6. package/configuration/base.js.map +1 -1
  7. package/configuration/javascript.js +5 -72
  8. package/configuration/javascript.js.map +1 -1
  9. package/configuration/solid.js +27 -1
  10. package/configuration/solid.js.map +1 -1
  11. package/configuration/typescript.js +5 -75
  12. package/configuration/typescript.js.map +1 -1
  13. package/helpers/angular/angular-linker.d.ts +5 -6
  14. package/helpers/angular/angular-linker.js +36 -121
  15. package/helpers/angular/angular-linker.js.map +1 -1
  16. package/helpers/angular/inject-component-hmr-registration.d.ts +112 -0
  17. package/helpers/angular/inject-component-hmr-registration.js +291 -0
  18. package/helpers/angular/inject-component-hmr-registration.js.map +1 -0
  19. package/helpers/angular/inject-hmr-vite-ignore.d.ts +75 -0
  20. package/helpers/angular/inject-hmr-vite-ignore.js +221 -0
  21. package/helpers/angular/inject-hmr-vite-ignore.js.map +1 -0
  22. package/helpers/angular/inline-decorator-component-templates.js +1 -170
  23. package/helpers/angular/inline-decorator-component-templates.js.map +1 -1
  24. package/helpers/angular/js-lexer.d.ts +4 -0
  25. package/helpers/angular/js-lexer.js +182 -0
  26. package/helpers/angular/js-lexer.js.map +1 -0
  27. package/helpers/angular/shared-linker.d.ts +31 -3
  28. package/helpers/angular/shared-linker.js +67 -14
  29. package/helpers/angular/shared-linker.js.map +1 -1
  30. package/helpers/angular/synthesize-decorator-ctor-parameters.js +2 -170
  31. package/helpers/angular/synthesize-decorator-ctor-parameters.js.map +1 -1
  32. package/helpers/angular/synthesize-injectable-factories.js +1 -174
  33. package/helpers/angular/synthesize-injectable-factories.js.map +1 -1
  34. package/helpers/angular/util.d.ts +1 -0
  35. package/helpers/angular/util.js +88 -0
  36. package/helpers/angular/util.js.map +1 -1
  37. package/helpers/app-components.d.ts +2 -1
  38. package/helpers/app-components.js.map +1 -1
  39. package/helpers/app-css-state.d.ts +8 -0
  40. package/helpers/app-css-state.js +8 -0
  41. package/helpers/app-css-state.js.map +1 -0
  42. package/helpers/bundler-context.d.ts +11 -0
  43. package/helpers/bundler-context.js +71 -0
  44. package/helpers/bundler-context.js.map +1 -0
  45. package/helpers/config-as-json.js +10 -0
  46. package/helpers/config-as-json.js.map +1 -1
  47. package/helpers/dev-host.d.ts +341 -0
  48. package/helpers/dev-host.js +617 -0
  49. package/helpers/dev-host.js.map +1 -0
  50. package/helpers/esbuild-platform-resolver.js +4 -1
  51. package/helpers/esbuild-platform-resolver.js.map +1 -1
  52. package/helpers/global-defines.d.ts +51 -0
  53. package/helpers/global-defines.js +77 -0
  54. package/helpers/global-defines.js.map +1 -1
  55. package/helpers/hmr-scope.d.ts +26 -0
  56. package/helpers/hmr-scope.js +67 -0
  57. package/helpers/hmr-scope.js.map +1 -0
  58. package/helpers/init.js +0 -18
  59. package/helpers/init.js.map +1 -1
  60. package/helpers/logging.d.ts +1 -0
  61. package/helpers/logging.js +63 -3
  62. package/helpers/logging.js.map +1 -1
  63. package/helpers/main-entry.d.ts +2 -1
  64. package/helpers/main-entry.js +430 -47
  65. package/helpers/main-entry.js.map +1 -1
  66. package/helpers/nativeclass-esbuild-plugin.d.ts +2 -1
  67. package/helpers/nativeclass-esbuild-plugin.js.map +1 -1
  68. package/helpers/nativeclass-transform.js.map +1 -1
  69. package/helpers/nativeclass-transformer-plugin.d.ts +9 -2
  70. package/helpers/nativeclass-transformer-plugin.js +157 -14
  71. package/helpers/nativeclass-transformer-plugin.js.map +1 -1
  72. package/helpers/nativescript-package-resolver.js +8 -3
  73. package/helpers/nativescript-package-resolver.js.map +1 -1
  74. package/helpers/normalize-id.d.ts +42 -0
  75. package/helpers/normalize-id.js +60 -0
  76. package/helpers/normalize-id.js.map +1 -0
  77. package/helpers/ns-core-url.d.ts +88 -0
  78. package/helpers/ns-core-url.js +191 -0
  79. package/helpers/ns-core-url.js.map +1 -0
  80. package/helpers/package-platform-aliases.js +4 -3
  81. package/helpers/package-platform-aliases.js.map +1 -1
  82. package/helpers/platform-types.d.ts +2 -0
  83. package/helpers/platform-types.js +2 -0
  84. package/helpers/platform-types.js.map +1 -0
  85. package/helpers/prelink-angular.js +12 -33
  86. package/helpers/prelink-angular.js.map +1 -1
  87. package/helpers/project.d.ts +35 -0
  88. package/helpers/project.js +120 -2
  89. package/helpers/project.js.map +1 -1
  90. package/helpers/resolver.js +17 -2
  91. package/helpers/resolver.js.map +1 -1
  92. package/helpers/solid-jsx-deps.d.ts +15 -0
  93. package/helpers/solid-jsx-deps.js +178 -0
  94. package/helpers/solid-jsx-deps.js.map +1 -0
  95. package/helpers/ts-config-paths.d.ts +14 -0
  96. package/helpers/ts-config-paths.js +89 -8
  97. package/helpers/ts-config-paths.js.map +1 -1
  98. package/helpers/typescript-check.d.ts +2 -1
  99. package/helpers/typescript-check.js.map +1 -1
  100. package/helpers/workers.d.ts +20 -19
  101. package/helpers/workers.js +624 -4
  102. package/helpers/workers.js.map +1 -1
  103. package/hmr/client/css-handler.d.ts +1 -0
  104. package/hmr/client/css-handler.js +33 -20
  105. package/hmr/client/css-handler.js.map +1 -1
  106. package/hmr/client/css-update-overlay.d.ts +18 -0
  107. package/hmr/client/css-update-overlay.js +27 -0
  108. package/hmr/client/css-update-overlay.js.map +1 -0
  109. package/hmr/client/hmr-pending-overlay.d.ts +27 -0
  110. package/hmr/client/hmr-pending-overlay.js +50 -0
  111. package/hmr/client/hmr-pending-overlay.js.map +1 -0
  112. package/hmr/client/index.js +419 -15
  113. package/hmr/client/index.js.map +1 -1
  114. package/hmr/client/utils.d.ts +6 -1
  115. package/hmr/client/utils.js +184 -8
  116. package/hmr/client/utils.js.map +1 -1
  117. package/hmr/client/vue-sfc-update-overlay.d.ts +82 -0
  118. package/hmr/client/vue-sfc-update-overlay.js +133 -0
  119. package/hmr/client/vue-sfc-update-overlay.js.map +1 -0
  120. package/hmr/entry-runtime.d.ts +2 -1
  121. package/hmr/entry-runtime.js +252 -65
  122. package/hmr/entry-runtime.js.map +1 -1
  123. package/hmr/frameworks/angular/client/index.d.ts +1 -0
  124. package/hmr/frameworks/angular/client/index.js +778 -20
  125. package/hmr/frameworks/angular/client/index.js.map +1 -1
  126. package/hmr/frameworks/angular/server/linker.js +1 -4
  127. package/hmr/frameworks/angular/server/linker.js.map +1 -1
  128. package/hmr/frameworks/angular/server/strategy.js +13 -15
  129. package/hmr/frameworks/angular/server/strategy.js.map +1 -1
  130. package/hmr/frameworks/solid/server/strategy.js +3 -18
  131. package/hmr/frameworks/solid/server/strategy.js.map +1 -1
  132. package/hmr/frameworks/typescript/server/strategy.js +2 -15
  133. package/hmr/frameworks/typescript/server/strategy.js.map +1 -1
  134. package/hmr/frameworks/vue/client/index.js +30 -199
  135. package/hmr/frameworks/vue/client/index.js.map +1 -1
  136. package/hmr/helpers/ast-normalizer.js +52 -5
  137. package/hmr/helpers/ast-normalizer.js.map +1 -1
  138. package/hmr/helpers/cjs-named-exports.d.ts +23 -0
  139. package/hmr/helpers/cjs-named-exports.js +152 -0
  140. package/hmr/helpers/cjs-named-exports.js.map +1 -0
  141. package/hmr/helpers/package-exports.d.ts +16 -0
  142. package/hmr/helpers/package-exports.js +396 -0
  143. package/hmr/helpers/package-exports.js.map +1 -0
  144. package/hmr/server/angular-root-component.d.ts +79 -0
  145. package/hmr/server/angular-root-component.js +149 -0
  146. package/hmr/server/angular-root-component.js.map +1 -0
  147. package/hmr/server/constants.js +13 -4
  148. package/hmr/server/constants.js.map +1 -1
  149. package/hmr/server/core-sanitize.d.ts +90 -7
  150. package/hmr/server/core-sanitize.js +211 -56
  151. package/hmr/server/core-sanitize.js.map +1 -1
  152. package/hmr/server/framework-strategy.d.ts +9 -19
  153. package/hmr/server/hmr-module-graph.d.ts +37 -0
  154. package/hmr/server/hmr-module-graph.js +214 -0
  155. package/hmr/server/hmr-module-graph.js.map +1 -0
  156. package/hmr/server/import-map.js +60 -8
  157. package/hmr/server/import-map.js.map +1 -1
  158. package/hmr/server/index.js +1 -0
  159. package/hmr/server/index.js.map +1 -1
  160. package/hmr/server/ns-core-cjs-shape.d.ts +204 -0
  161. package/hmr/server/ns-core-cjs-shape.js +271 -0
  162. package/hmr/server/ns-core-cjs-shape.js.map +1 -0
  163. package/hmr/server/ns-rt-bridge.d.ts +51 -0
  164. package/hmr/server/ns-rt-bridge.js +131 -0
  165. package/hmr/server/ns-rt-bridge.js.map +1 -0
  166. package/hmr/server/ns-rt-route.d.ts +5 -0
  167. package/hmr/server/ns-rt-route.js +35 -0
  168. package/hmr/server/ns-rt-route.js.map +1 -0
  169. package/hmr/server/perf-instrumentation.d.ts +114 -0
  170. package/hmr/server/perf-instrumentation.js +195 -0
  171. package/hmr/server/perf-instrumentation.js.map +1 -0
  172. package/hmr/server/require-guard.d.ts +1 -0
  173. package/hmr/server/require-guard.js +12 -0
  174. package/hmr/server/require-guard.js.map +1 -0
  175. package/hmr/server/route-helpers.d.ts +7 -0
  176. package/hmr/server/route-helpers.js +13 -0
  177. package/hmr/server/route-helpers.js.map +1 -0
  178. package/hmr/server/server-origin.d.ts +12 -0
  179. package/hmr/server/server-origin.js +66 -0
  180. package/hmr/server/server-origin.js.map +1 -0
  181. package/hmr/server/shared-transform-request.js +12 -5
  182. package/hmr/server/shared-transform-request.js.map +1 -1
  183. package/hmr/server/vendor-bare-module-shims.d.ts +4 -0
  184. package/hmr/server/vendor-bare-module-shims.js +80 -0
  185. package/hmr/server/vendor-bare-module-shims.js.map +1 -0
  186. package/hmr/server/vite-plugin.js +60 -42
  187. package/hmr/server/vite-plugin.js.map +1 -1
  188. package/hmr/server/websocket-angular-entry.js +1 -1
  189. package/hmr/server/websocket-angular-entry.js.map +1 -1
  190. package/hmr/server/websocket-angular-hot-update.d.ts +17 -0
  191. package/hmr/server/websocket-angular-hot-update.js +176 -2
  192. package/hmr/server/websocket-angular-hot-update.js.map +1 -1
  193. package/hmr/server/websocket-core-bridge.d.ts +41 -6
  194. package/hmr/server/websocket-core-bridge.js +72 -75
  195. package/hmr/server/websocket-core-bridge.js.map +1 -1
  196. package/hmr/server/websocket-css-hot-update.d.ts +33 -0
  197. package/hmr/server/websocket-css-hot-update.js +65 -0
  198. package/hmr/server/websocket-css-hot-update.js.map +1 -0
  199. package/hmr/server/websocket-device-transform.d.ts +21 -0
  200. package/hmr/server/websocket-device-transform.js +1570 -0
  201. package/hmr/server/websocket-device-transform.js.map +1 -0
  202. package/hmr/server/websocket-graph-upsert.d.ts +15 -0
  203. package/hmr/server/websocket-graph-upsert.js +20 -0
  204. package/hmr/server/websocket-graph-upsert.js.map +1 -1
  205. package/hmr/server/websocket-hmr-pending.d.ts +43 -0
  206. package/hmr/server/websocket-hmr-pending.js +55 -0
  207. package/hmr/server/websocket-hmr-pending.js.map +1 -0
  208. package/hmr/server/websocket-hot-update.d.ts +51 -0
  209. package/hmr/server/websocket-hot-update.js +1160 -0
  210. package/hmr/server/websocket-hot-update.js.map +1 -0
  211. package/hmr/server/websocket-import-map-route.d.ts +15 -0
  212. package/hmr/server/websocket-import-map-route.js +44 -0
  213. package/hmr/server/websocket-import-map-route.js.map +1 -0
  214. package/hmr/server/websocket-module-bindings.js +3 -3
  215. package/hmr/server/websocket-module-bindings.js.map +1 -1
  216. package/hmr/server/websocket-module-specifiers.d.ts +66 -2
  217. package/hmr/server/websocket-module-specifiers.js +202 -19
  218. package/hmr/server/websocket-module-specifiers.js.map +1 -1
  219. package/hmr/server/websocket-ns-core.d.ts +21 -0
  220. package/hmr/server/websocket-ns-core.js +305 -0
  221. package/hmr/server/websocket-ns-core.js.map +1 -0
  222. package/hmr/server/websocket-ns-entry.d.ts +22 -0
  223. package/hmr/server/websocket-ns-entry.js +150 -0
  224. package/hmr/server/websocket-ns-entry.js.map +1 -0
  225. package/hmr/server/websocket-ns-m-paths.d.ts +3 -0
  226. package/hmr/server/websocket-ns-m-paths.js +92 -0
  227. package/hmr/server/websocket-ns-m-paths.js.map +1 -0
  228. package/hmr/server/websocket-ns-m-request.d.ts +45 -0
  229. package/hmr/server/websocket-ns-m-request.js +196 -0
  230. package/hmr/server/websocket-ns-m-request.js.map +1 -0
  231. package/hmr/server/websocket-ns-m.d.ts +34 -0
  232. package/hmr/server/websocket-ns-m.js +853 -0
  233. package/hmr/server/websocket-ns-m.js.map +1 -0
  234. package/hmr/server/websocket-served-module-helpers.d.ts +39 -0
  235. package/hmr/server/websocket-served-module-helpers.js +654 -0
  236. package/hmr/server/websocket-served-module-helpers.js.map +1 -0
  237. package/hmr/server/websocket-sfc.d.ts +24 -0
  238. package/hmr/server/websocket-sfc.js +1223 -0
  239. package/hmr/server/websocket-sfc.js.map +1 -0
  240. package/hmr/server/websocket-txn.d.ts +6 -0
  241. package/hmr/server/websocket-txn.js +39 -0
  242. package/hmr/server/websocket-txn.js.map +1 -0
  243. package/hmr/server/websocket-vendor-unifier.d.ts +10 -0
  244. package/hmr/server/websocket-vendor-unifier.js +45 -0
  245. package/hmr/server/websocket-vendor-unifier.js.map +1 -0
  246. package/hmr/server/websocket.d.ts +0 -30
  247. package/hmr/server/websocket.js +599 -6038
  248. package/hmr/server/websocket.js.map +1 -1
  249. package/hmr/shared/runtime/boot-placeholder-ui.d.ts +69 -0
  250. package/hmr/shared/runtime/boot-placeholder-ui.js +101 -0
  251. package/hmr/shared/runtime/boot-placeholder-ui.js.map +1 -0
  252. package/hmr/shared/runtime/boot-progress.d.ts +40 -0
  253. package/hmr/shared/runtime/boot-progress.js +128 -0
  254. package/hmr/shared/runtime/boot-progress.js.map +1 -0
  255. package/hmr/shared/runtime/boot-timeline.d.ts +18 -0
  256. package/hmr/shared/runtime/boot-timeline.js +52 -0
  257. package/hmr/shared/runtime/boot-timeline.js.map +1 -0
  258. package/hmr/shared/runtime/dev-overlay-snapshots.d.ts +31 -0
  259. package/hmr/shared/runtime/dev-overlay-snapshots.js +324 -0
  260. package/hmr/shared/runtime/dev-overlay-snapshots.js.map +1 -0
  261. package/hmr/shared/runtime/dev-overlay.d.ts +75 -26
  262. package/hmr/shared/runtime/dev-overlay.js +990 -260
  263. package/hmr/shared/runtime/dev-overlay.js.map +1 -1
  264. package/hmr/shared/runtime/module-provenance.js +1 -4
  265. package/hmr/shared/runtime/module-provenance.js.map +1 -1
  266. package/hmr/shared/runtime/root-placeholder-view.d.ts +19 -0
  267. package/hmr/shared/runtime/root-placeholder-view.js +310 -0
  268. package/hmr/shared/runtime/root-placeholder-view.js.map +1 -0
  269. package/hmr/shared/runtime/root-placeholder.js +352 -194
  270. package/hmr/shared/runtime/root-placeholder.js.map +1 -1
  271. package/hmr/shared/runtime/session-bootstrap.js +164 -1
  272. package/hmr/shared/runtime/session-bootstrap.js.map +1 -1
  273. package/hmr/shared/runtime/vendor-bootstrap.js +1 -9
  274. package/hmr/shared/runtime/vendor-bootstrap.js.map +1 -1
  275. package/hmr/shared/vendor/manifest-collect.d.ts +32 -0
  276. package/hmr/shared/vendor/manifest-collect.js +512 -0
  277. package/hmr/shared/vendor/manifest-collect.js.map +1 -0
  278. package/hmr/shared/vendor/manifest-loader.d.ts +2 -1
  279. package/hmr/shared/vendor/manifest-loader.js +3 -2
  280. package/hmr/shared/vendor/manifest-loader.js.map +1 -1
  281. package/hmr/shared/vendor/manifest.d.ts +1 -5
  282. package/hmr/shared/vendor/manifest.js +102 -739
  283. package/hmr/shared/vendor/manifest.js.map +1 -1
  284. package/hmr/shared/vendor/vendor-device-shim.d.ts +1 -0
  285. package/hmr/shared/vendor/vendor-device-shim.js +208 -0
  286. package/hmr/shared/vendor/vendor-device-shim.js.map +1 -0
  287. package/hmr/shared/vendor/vendor-esbuild-plugins.d.ts +16 -0
  288. package/hmr/shared/vendor/vendor-esbuild-plugins.js +203 -0
  289. package/hmr/shared/vendor/vendor-esbuild-plugins.js.map +1 -0
  290. package/index.d.ts +1 -0
  291. package/index.js +5 -0
  292. package/index.js.map +1 -1
  293. package/package.json +55 -11
  294. package/runtime/core-aliases-early.js +17 -41
  295. package/runtime/core-aliases-early.js.map +1 -1
@@ -5,8 +5,9 @@
5
5
  * Always resolve core classes and Application from the vendor realm or globalThis at runtime.
6
6
  * The HMR client is evaluated via HTTP ESM on device; static imports would create secondary instances.
7
7
  */
8
- import { setHMRWsUrl, getHMRWsUrl, pendingModuleFetches, deriveHttpOrigin, setHttpOriginForVite, moduleFetchCache, requestModuleFromServer, getHttpOriginForVite, normalizeSpec, hmrMetrics, graph, setGraphVersion, getGraphVersion, getCurrentApp, getRootFrame, setCurrentApp, setRootFrame, getCore } from './utils.js';
8
+ import { setHMRWsUrl, getHMRWsUrl, pendingModuleFetches, deriveHttpOrigin, setHttpOriginForVite, moduleFetchCache, requestModuleFromServer, getHttpOriginForVite, normalizeSpec, hmrMetrics, graph, setGraphVersion, getGraphVersion, getCurrentApp, getRootFrame, setCurrentApp, setRootFrame, getCore, hasExplicitEviction, invalidateModulesByUrls, buildEvictionUrls, emitHmrModeBannerOnce } from './utils.js';
9
9
  import { handleCssUpdates } from './css-handler.js';
10
+ import { buildCssApplyingDetail, buildCssAppliedDetail } from './css-update-overlay.js';
10
11
  const VERBOSE = typeof __NS_ENV_VERBOSE__ !== 'undefined' && __NS_ENV_VERBOSE__;
11
12
  function resolveTargetFlavor() {
12
13
  try {
@@ -101,6 +102,80 @@ function hideConnectionOverlay() {
101
102
  }
102
103
  catch { }
103
104
  }
105
+ function setUpdateOverlayStage(stage, info) {
106
+ try {
107
+ const api = getHmrOverlayApi();
108
+ if (api && typeof api.setUpdateStage === 'function') {
109
+ api.setUpdateStage(stage, info);
110
+ }
111
+ }
112
+ catch { }
113
+ }
114
+ // Store the listener registry on globalThis (rather than in a module-private
115
+ // closure) because in NativeScript the HMR client module and the user app
116
+ // modules can resolve to different module instances depending on how the
117
+ // dev runtime loads them (HTTP client URL vs. the bundled vendor realm).
118
+ // A module-local Set would not be shared across instances; the global one
119
+ // is.
120
+ function getNsSolidHmrListenerSet() {
121
+ const g = globalThis;
122
+ let set = g.__ns_solid_hmr_listener_set;
123
+ if (!set) {
124
+ set = new Set();
125
+ g.__ns_solid_hmr_listener_set = set;
126
+ }
127
+ return set;
128
+ }
129
+ function nsSolidHmrSubscribe(fn) {
130
+ const listeners = getNsSolidHmrListenerSet();
131
+ listeners.add(fn);
132
+ if (VERBOSE)
133
+ console.log('[hmr][solid] subscribe — listeners=', listeners.size);
134
+ return () => listeners.delete(fn);
135
+ }
136
+ function nsSolidHmrEmit(ev) {
137
+ const listeners = getNsSolidHmrListenerSet();
138
+ if (VERBOSE)
139
+ console.log('[hmr][solid] emit listeners=', listeners.size, 'changedFiles=', ev.changedFiles);
140
+ for (const fn of Array.from(listeners)) {
141
+ try {
142
+ fn(ev);
143
+ }
144
+ catch (err) {
145
+ if (VERBOSE)
146
+ console.warn('[hmr][solid] listener threw', err);
147
+ }
148
+ }
149
+ }
150
+ try {
151
+ const g = globalThis;
152
+ g.__ns_solid_hmr_subscribe = nsSolidHmrSubscribe;
153
+ // Eagerly create the listener set so the global exists at module load time.
154
+ getNsSolidHmrListenerSet();
155
+ if (VERBOSE)
156
+ console.log('[hmr][solid] HMR client loaded. global set=', typeof g.__ns_solid_hmr_subscribe, 'listenerSet=', typeof g.__ns_solid_hmr_listener_set);
157
+ }
158
+ catch (err) {
159
+ console.warn('[hmr][solid] could not install global __ns_solid_hmr_subscribe', err);
160
+ }
161
+ // Eagerly drive the HMR-applying overlay's 'received' frame as soon
162
+ // as the server emits `ns:hmr-pending`, BEFORE the framework-specific
163
+ // (`ns:angular-update` / `ns:css-updates`) payload arrives. The
164
+ // flavor-specific handler later walks through 'evicting' →
165
+ // 'reimporting' → 'rebooting' → 'complete'. Calling 'received' twice
166
+ // in the same cycle is safe: the overlay preserves
167
+ // `updateCycleStartedAt` when a 'received' frame replaces an existing
168
+ // 'received' frame so the minimum-visible window is still timed
169
+ // against the FIRST frame.
170
+ //
171
+ // Soft-fails when the overlay isn't installed (production builds,
172
+ // vitest, etc.) or when the user opted out via
173
+ // `__NS_HMR_PROGRESS_OVERLAY_ENABLED__ === false`.
174
+ import { applyHmrPendingFrame } from './hmr-pending-overlay.js';
175
+ import { driveVueSfcUpdateOverlay } from './vue-sfc-update-overlay.js';
176
+ function setHmrPendingOverlay(filePath) {
177
+ applyHmrPendingFrame(filePath, { getOverlay: getHmrOverlayApi });
178
+ }
104
179
  let connectionOverlayTimer = null;
105
180
  let connectionOverlayVisible = false;
106
181
  let hasOpenedHmrSocket = false;
@@ -675,7 +750,13 @@ function __nsNavigateUsingApp(comp, opts = {}) {
675
750
  const buildTarget = () => {
676
751
  const existingApp = getCurrentApp();
677
752
  const baseProvides = (existingApp && existingApp._context && existingApp._context.provides) || {};
678
- const app = AppFactory(normalizeComponent(comp, comp && (comp.__name || comp.name)));
753
+ // Forward `opts.props` as Vue's rootProps so `$navigateTo(Comp, { props: { } })`
754
+ // reaches the destination component. nativescript-vue's stock `$navigateTo`
755
+ // does the same via `createNativeView(target, options?.props, …)` →
756
+ // `renderer.createApp(component, props)`. Dropping props here would surface
757
+ // at the destination as `[Vue warn]: Missing required prop` and any
758
+ // required-prop component would render with `undefined` bindings.
759
+ const app = AppFactory(normalizeComponent(comp, comp && (comp.__name || comp.name)), opts && opts.props);
679
760
  switch (TARGET_FLAVOR) {
680
761
  case 'vue':
681
762
  ensurePiniaOnApp(app);
@@ -810,7 +891,42 @@ async function processQueue() {
810
891
  return;
811
892
  if (VERBOSE)
812
893
  console.log('[hmr][queue] processing changed ids', drained);
894
+ // Track wall-clock so the 'complete' frame can show a meaningful
895
+ // total. Only the Solid + TypeScript flavors drive the overlay
896
+ // from here; Angular has its own flow inside
897
+ // `frameworks/angular/client/index.ts`.
898
+ const tQueueStart = Date.now();
899
+ const driveSolidOverlay = TARGET_FLAVOR === 'solid';
900
+ // Explicit eviction step.
901
+ //
902
+ // On modern runtimes the URL canonicalizer collapses any
903
+ // `__ns_hmr__/<tag>/` segment back to a stable cache key, so
904
+ // without explicit eviction the upcoming `import(url)` would
905
+ // resolve via V8's `g_moduleRegistry` and return the cached
906
+ // stale module — making the queue drain a silent no-op for
907
+ // every save after the first.
908
+ //
909
+ // We hand the canonical eviction URLs to the runtime first;
910
+ // `invalidateModulesByUrls` is a no-op on older runtimes and
911
+ // `requestModuleFromServer` automatically falls back to the
912
+ // legacy `/ns/m/__ns_hmr__/v<N>/` URL versioning path in that
913
+ // case. node_modules and virtual specs are filtered out by
914
+ // `buildEvictionUrls` so vendor modules stay hot.
915
+ if (driveSolidOverlay) {
916
+ setUpdateOverlayStage('evicting', {
917
+ detail: drained.length === 1 ? `Invalidating ${drained[0]}` : `Invalidating ${drained.length} modules`,
918
+ });
919
+ }
920
+ const evictUrls = buildEvictionUrls(drained);
921
+ const evicted = invalidateModulesByUrls(evictUrls);
922
+ if (VERBOSE)
923
+ console.log(`[hmr][queue] eviction count=${evictUrls.length} ok=${evicted}`);
813
924
  // Evaluate changed modules best-effort; failures shouldn't completely break HMR.
925
+ if (driveSolidOverlay) {
926
+ setUpdateOverlayStage('reimporting', {
927
+ detail: drained.length === 1 ? `Re-importing ${drained[0]}` : `Re-importing ${drained.length} modules`,
928
+ });
929
+ }
814
930
  for (const id of drained) {
815
931
  try {
816
932
  const spec = normalizeSpec(id);
@@ -829,9 +945,34 @@ async function processQueue() {
829
945
  // After evaluating the batch, perform flavor-specific UI refresh.
830
946
  switch (TARGET_FLAVOR) {
831
947
  case 'vue':
832
- // Vue SFCs are handled via the registry update path; nothing to do here.
948
+ // Vue SFCs are handled via the registry update path
949
+ // (which drives its own overlay completion through
950
+ // `driveVueSfcUpdateOverlay`); nothing else to do
951
+ // for the view-tree refresh here.
952
+ //
953
+ // However, when a non-SFC file (e.g. a `.ts`
954
+ // utility module imported by an SFC) is the only
955
+ // changed entry, no `ns:vue-sfc-registry-update`
956
+ // will follow — and without an explicit 'complete'
957
+ // the overlay would stick on "Preparing update
958
+ // (5%)". Drive the closing frame here so the
959
+ // auto-hide timer can dismiss the toast in the
960
+ // pure-TS-change case. The detail surfaces the
961
+ // changed count so a user can correlate the
962
+ // overlay with the server-side `[hmr-ws][update]`
963
+ // log.
964
+ setUpdateOverlayStage('complete', {
965
+ detail: drained.length === 1 ? `Updated ${drained[0]} in ${Math.max(0, Date.now() - tQueueStart)}ms` : `Updated ${drained.length} modules in ${Math.max(0, Date.now() - tQueueStart)}ms`,
966
+ });
833
967
  break;
834
968
  case 'solid': {
969
+ // Boundaries discovered in this HMR cycle (tsx files reachable
970
+ // via the reverse import graph from any changed file, plus route
971
+ // files reachable from any tsx start point). Declared at the top
972
+ // of the case block so the emit step below can include the
973
+ // complete set in the listener event — framework integrations
974
+ // use it to map route boundaries → fresh component references.
975
+ const boundaries = new Set();
835
976
  // Solid .tsx components are self-accepting via solid-refresh's inline
836
977
  // patchRegistry — re-importing them is sufficient. For non-component
837
978
  // .ts utility modules, we must propagate up the import graph to find
@@ -850,8 +991,10 @@ async function processQueue() {
850
991
  arr.push(id);
851
992
  }
852
993
  }
853
- // BFS from each non-tsx changed module up to tsx/jsx boundaries
854
- const boundaries = new Set();
994
+ // Pass 1: BFS from each non-tsx changed module up to tsx/jsx
995
+ // boundaries. These get re-imported below so solid-refresh's
996
+ // inline patchRegistry runs and (best-effort) swaps the proxy
997
+ // signals for any components defined in those tsx boundaries.
855
998
  for (const id of drained) {
856
999
  if (/\.(tsx|jsx)$/i.test(id))
857
1000
  continue; // already self-accepting
@@ -875,6 +1018,51 @@ async function processQueue() {
875
1018
  }
876
1019
  }
877
1020
  }
1021
+ // Pass 2: walk further from any tsx starting point (a tsx file
1022
+ // in `drained` OR a tsx boundary discovered in pass 1) to find
1023
+ // route files (`/src/routes/*.{tsx,jsx}`) that transitively
1024
+ // import them. Re-importing a route file refreshes its
1025
+ // `Route.options.component` to the freshly-imported reference
1026
+ // and the existing boundary loop below patches the live router
1027
+ // with that fresh reference.
1028
+ //
1029
+ // This is the key fix for "edit home.tsx → save → no visual
1030
+ // update": the old BFS skipped tsx files in `drained` (assuming
1031
+ // solid-refresh's in-place proxy patch was sufficient), but in
1032
+ // the universal-renderer + nested-context configuration that
1033
+ // patch does not always propagate to the visible page tree.
1034
+ // Adding the route file as a boundary lets us patch
1035
+ // `route.options.component` directly to a fresh module export,
1036
+ // which the framework subscriber then passes through to the
1037
+ // page remount — making the cycle robust to the proxy patch
1038
+ // silently failing.
1039
+ const tsxStarts = new Set();
1040
+ for (const id of drained) {
1041
+ if (/\.(tsx|jsx)$/i.test(id))
1042
+ tsxStarts.add(id);
1043
+ }
1044
+ for (const b of boundaries)
1045
+ tsxStarts.add(b);
1046
+ const ROUTE_FILE_RE = /\/src\/routes\/.+\.(tsx|jsx)$/i;
1047
+ for (const start of tsxStarts) {
1048
+ const visited = new Set();
1049
+ const queue = [start];
1050
+ while (queue.length) {
1051
+ const cur = queue.shift();
1052
+ if (visited.has(cur))
1053
+ continue;
1054
+ visited.add(cur);
1055
+ if (cur !== start && ROUTE_FILE_RE.test(cur)) {
1056
+ boundaries.add(cur);
1057
+ }
1058
+ const importers = reverseIndex.get(cur);
1059
+ if (!importers)
1060
+ continue;
1061
+ for (const imp of importers) {
1062
+ queue.push(imp);
1063
+ }
1064
+ }
1065
+ }
878
1066
  // Re-import each boundary so solid-refresh patchRegistry fires.
879
1067
  // For route files (TanStack Router), capture the new Route export
880
1068
  // and patch the router's existing route with the fresh loader.
@@ -924,6 +1112,15 @@ async function processQueue() {
924
1112
  }
925
1113
  return null;
926
1114
  };
1115
+ // Evict the boundary set so re-importing each .tsx
1116
+ // component actually picks up the new transitive
1117
+ // dependency code; without this V8 returns the
1118
+ // cached boundary module unchanged.
1119
+ const boundaryIds = Array.from(boundaries);
1120
+ const solidEvictUrls = buildEvictionUrls(boundaryIds);
1121
+ const solidEvicted = invalidateModulesByUrls(solidEvictUrls);
1122
+ if (VERBOSE)
1123
+ console.log(`[hmr][solid] eviction count=${solidEvictUrls.length} ok=${solidEvicted}`);
927
1124
  for (const id of boundaries) {
928
1125
  if (seen.has(id))
929
1126
  continue;
@@ -935,22 +1132,28 @@ async function processQueue() {
935
1132
  if (VERBOSE)
936
1133
  console.log('[hmr][solid] propagated to boundary', { id, url });
937
1134
  const mod = await import(/* @vite-ignore */ url);
938
- // Patch TanStack Router route loaders
1135
+ // Patch TanStack Router route options for any module
1136
+ // that exports a `Route`. We patch BOTH the component
1137
+ // and the loader (when present); components-only routes
1138
+ // were previously skipped because the gate required a
1139
+ // loader, which left their `options.component` pointing
1140
+ // at the stale module's exports after HMR.
939
1141
  try {
940
1142
  const newRoute = mod?.Route;
941
- if (newRoute?.options?.loader) {
1143
+ if (newRoute?.options) {
942
1144
  const router = findRouter();
943
1145
  const fullPath = boundaryToFullPath(id);
944
1146
  if (VERBOSE)
945
- console.log('[hmr][solid][diag] route patch attempt', { id, fullPath, hasRouter: !!router, routesByIdKeys: router?.routesById ? Object.keys(router.routesById) : 'none' });
1147
+ console.log('[hmr][solid][diag] route patch attempt', { id, fullPath, hasRouter: !!router, hasLoader: !!newRoute.options.loader, hasComponent: !!newRoute.options.component });
946
1148
  const existingRoute = fullPath && router ? findRouteByFullPath(router, fullPath) : null;
947
1149
  if (existingRoute?.options) {
948
- existingRoute.options.loader = newRoute.options.loader;
1150
+ if (newRoute.options.loader)
1151
+ existingRoute.options.loader = newRoute.options.loader;
949
1152
  if (newRoute.options.component)
950
1153
  existingRoute.options.component = newRoute.options.component;
951
1154
  routesPatchCount++;
952
1155
  if (VERBOSE)
953
- console.log('[hmr][solid] patched route loader', existingRoute.id, 'fullPath=', fullPath);
1156
+ console.log('[hmr][solid] patched route', existingRoute.id, 'fullPath=', fullPath);
954
1157
  }
955
1158
  else if (VERBOSE) {
956
1159
  console.log('[hmr][solid] no matching route for fullPath', fullPath);
@@ -986,6 +1189,44 @@ async function processQueue() {
986
1189
  if (VERBOSE)
987
1190
  console.warn('[hmr][solid] propagation failed', e);
988
1191
  }
1192
+ // Notify any framework integrations (e.g.
1193
+ // `@nativescript/tanstack-router`) that a Solid HMR
1194
+ // cycle has completed. They use this signal to perform
1195
+ // framework-specific UI refresh (e.g. remount the active
1196
+ // router page) when solid-refresh's own reactive
1197
+ // propagation does not reach the visible tree under
1198
+ // the current renderer/context configuration.
1199
+ //
1200
+ // Boundaries include both the directly-changed tsx files
1201
+ // AND every tsx ancestor reachable via the reverse import
1202
+ // graph (route files in particular). The framework
1203
+ // listener uses the route-file boundaries to look up the
1204
+ // freshly-patched `route.options.component` and pass it
1205
+ // through to the page remount.
1206
+ try {
1207
+ const tsxChangedInDrained = drained.filter((id) => /\.(tsx|jsx)$/i.test(id));
1208
+ const allBoundaries = Array.from(new Set([...tsxChangedInDrained, ...boundaries]));
1209
+ nsSolidHmrEmit({
1210
+ kind: 'solid',
1211
+ changedFiles: drained.slice(),
1212
+ boundaries: allBoundaries,
1213
+ });
1214
+ }
1215
+ catch (err) {
1216
+ if (VERBOSE)
1217
+ console.warn('[hmr][solid] emit failed', err);
1218
+ }
1219
+ // Tell the overlay the cycle is done. solid-refresh's
1220
+ // inline patchRegistry has already flushed the new
1221
+ // component bodies into the live tree (the `case
1222
+ // 'solid'` block above re-imports each .tsx
1223
+ // boundary), so by the time we get here the user is
1224
+ // already looking at the new render. The 'complete'
1225
+ // frame surfaces the wall-clock total and triggers
1226
+ // the overlay's auto-hide.
1227
+ setUpdateOverlayStage('complete', {
1228
+ detail: `Total ${Math.max(0, Date.now() - tQueueStart)}ms`,
1229
+ });
989
1230
  break;
990
1231
  }
991
1232
  case 'typescript': {
@@ -1274,6 +1515,14 @@ function connectHmr() {
1274
1515
  showConnectionOverlayNow('synchronizing', 'Connected. Synchronizing the HMR graph.');
1275
1516
  }
1276
1517
  VERBOSE && console.log('[hmr-client] Connected to HMR WebSocket');
1518
+ // Print the active module reload mode once on first
1519
+ // successful connect so the user can correlate HMR latency
1520
+ // with runtime capability without grepping for protocol
1521
+ // details. The banner is verbose-gated.
1522
+ try {
1523
+ emitHmrModeBannerOnce();
1524
+ }
1525
+ catch { }
1277
1526
  };
1278
1527
  sock.onmessage = handleHmrMessage;
1279
1528
  sock.onerror = (error) => {
@@ -1333,6 +1582,17 @@ async function handleHmrMessage(ev) {
1333
1582
  catch { }
1334
1583
  }
1335
1584
  if (msg) {
1585
+ // `ns:hmr-pending` is a fire-and-forget UX hint emitted by the
1586
+ // server at the START of handleHotUpdate. We drive the
1587
+ // HMR-applying overlay's 'received' frame here (synchronously),
1588
+ // well before the authoritative payload (`ns:angular-update` /
1589
+ // `ns:css-updates`) lands. Skip running any other handlers —
1590
+ // the pending message has no module payload and intentionally
1591
+ // does not bump the graph version.
1592
+ if (msg.type === 'ns:hmr-pending' && typeof msg.path === 'string') {
1593
+ setHmrPendingOverlay(msg.path);
1594
+ return;
1595
+ }
1336
1596
  if (msg.type === 'ns:hmr-full-graph') {
1337
1597
  // Bump a monotonic nonce so HTTP ESM imports can always be cache-busted per update.
1338
1598
  try {
@@ -1402,6 +1662,14 @@ async function handleHmrMessage(ev) {
1402
1662
  });
1403
1663
  if (toReimport.length && VERBOSE)
1404
1664
  console.log('[hmr][full-graph] inferred changed modules; re-importing', toReimport);
1665
+ // Evict the inferred changed set before re-importing.
1666
+ // See `processQueue` for the architectural rationale; the
1667
+ // full-graph code path is the resync fallback (server chose
1668
+ // not to send a delta) and shares the same V8 cache pitfall.
1669
+ const fgEvictUrls = buildEvictionUrls(toReimport);
1670
+ const fgEvicted = invalidateModulesByUrls(fgEvictUrls);
1671
+ if (VERBOSE)
1672
+ console.log(`[hmr][full-graph] eviction count=${fgEvictUrls.length} ok=${fgEvicted}`);
1405
1673
  for (const id of toReimport) {
1406
1674
  try {
1407
1675
  const spec = normalizeSpec(id);
@@ -1475,6 +1743,104 @@ async function handleHmrMessage(ev) {
1475
1743
  return;
1476
1744
  }
1477
1745
  else {
1746
+ // Vite custom-event dispatch.
1747
+ //
1748
+ // `server.ws.send('event-name', payload)` from any Vite plugin lands
1749
+ // on the wire as `{ type: 'custom', event: 'event-name', data: payload }`.
1750
+ // On the web, Vite's stock client owns a `customListenersMap` that
1751
+ // fires every `import.meta.hot.on('event-name', cb)` callback. We
1752
+ // don't run Vite's stock client on device — the iOS runtime owns
1753
+ // the listener registry via `__NS_DISPATCH_HOT_EVENT__` (the
1754
+ // counterpart to `import.meta.hot.on` populated by user code +
1755
+ // compiled Angular components). Forwarding `type: 'custom'` here
1756
+ // is the only thing standing between server-emitted events and
1757
+ // the listeners they were meant for.
1758
+ //
1759
+ // `angular:component-update` is the canonical example. Analog's
1760
+ // plugin sends it on `.html` / component-style edits; the
1761
+ // compiled component `.mjs` registered a listener that
1762
+ // dynamic-imports `/@ng/component?c=<id>&t=<ts>` and calls
1763
+ // `ɵɵreplaceMetadata` on the live class — swapping the template
1764
+ // definition AND walking live `LView`s to recreate matching views
1765
+ // in-place. The page stays mounted and only the changed bits
1766
+ // re-render. We MUST `return` after dispatch so the reboot path
1767
+ // (`handleAngularHotUpdateMessage` → `__reboot_ng_modules__`)
1768
+ // never runs for these updates — that's the whole point of the
1769
+ // component-replacement pipeline.
1770
+ //
1771
+ // All other custom events are forwarded but NOT short-circuited
1772
+ // (Vite spec: custom events are additive — they don't replace
1773
+ // any framework-specific handling). The reboot path falls through
1774
+ // for `ns:angular-update` (the legacy/`.ts`-edit broadcast) and
1775
+ // for any framework not yet using the in-place replacement path.
1776
+ if (msg.type === 'custom' && typeof msg.event === 'string') {
1777
+ // Dispatch every Vite "custom" event through the runtime's
1778
+ // `__NS_DISPATCH_HOT_EVENT__` bridge so `import.meta.hot.on(event, cb)`
1779
+ // callbacks fire on the device. Critical contract: this is the
1780
+ // ONLY route by which Analog's `angular:component-update` reaches
1781
+ // the compiled component's `(d) => d.id === id && Component_HmrLoad(...)`
1782
+ // listener — without it, server-side broadcasts log green
1783
+ // (`(client) hmr update`) while the device sees nothing happen.
1784
+ //
1785
+ // Diagnostic policy: log "no dispatcher" loud (boot-time rt-bridge
1786
+ // failure), and listener exceptions loud (compiled HmrLoad
1787
+ // fetch/parse error). Successful dispatches are silent — the
1788
+ // runtime's `[import.meta.hot] dispatch summary` line carries
1789
+ // the per-event match-count diagnostic.
1790
+ try {
1791
+ const dispatch = globalThis.__NS_DISPATCH_HOT_EVENT__;
1792
+ if (typeof dispatch === 'function') {
1793
+ dispatch(msg.event, msg.data);
1794
+ }
1795
+ else {
1796
+ console.warn(`[hmr-client][custom] no __NS_DISPATCH_HOT_EVENT__ available for '${msg.event}'`);
1797
+ }
1798
+ }
1799
+ catch (err) {
1800
+ console.warn('[hmr-client][custom] dispatch threw for', msg.event, err);
1801
+ }
1802
+ if (msg.event === 'angular:component-update') {
1803
+ if (VERBOSE)
1804
+ console.log('[hmr-client][custom] dispatched angular:component-update — skipping reboot path');
1805
+ // Walk the apply-progress overlay through its
1806
+ // remaining stages for the in-place template-swap
1807
+ // path. The full reboot path
1808
+ // (`handleAngularHotUpdateMessage`) drives the
1809
+ // overlay itself ('received' → 'evicting' →
1810
+ // 'reimporting' → 'rebooting' → 'complete'); the
1811
+ // in-place path bypasses that handler entirely
1812
+ // because the work happens inside Angular's
1813
+ // `ɵɵreplaceMetadata` after the runtime forwards the
1814
+ // `angular:component-update` event to the compiled
1815
+ // component's listener. Without this update the
1816
+ // overlay would freeze at 5% ('received') even
1817
+ // though the visual swap completes a few frames
1818
+ // later — exactly the "Preparing update (5%)" stuck
1819
+ // frame we have been chasing.
1820
+ //
1821
+ // We transition straight to 'reimporting' to
1822
+ // communicate that metadata is being fetched (the
1823
+ // runtime listener fires `__ns_import('/@ng/component?c=...&t=...')`),
1824
+ // then schedule 'complete' on the next macrotask so
1825
+ // the auto-hide timer kicks in. The actual
1826
+ // template swap is fire-and-forget from this point;
1827
+ // the user sees the overlay close at the same time
1828
+ // as Angular re-renders the bound text/structure.
1829
+ try {
1830
+ const filePath = typeof msg.data?.id === 'string' ? decodeURIComponent(msg.data.id).split('@')[0] : undefined;
1831
+ const detail = filePath ? `Applying template update to ${filePath}` : 'Applying template update';
1832
+ setUpdateOverlayStage('reimporting', { detail });
1833
+ setTimeout(() => {
1834
+ try {
1835
+ setUpdateOverlayStage('complete', { detail: filePath ? `Updated ${filePath}` : 'Update applied' });
1836
+ }
1837
+ catch { }
1838
+ }, 16);
1839
+ }
1840
+ catch { }
1841
+ return;
1842
+ }
1843
+ }
1478
1844
  if (msg.type === 'ns:angular-update' && typeof msg.version === 'number') {
1479
1845
  setGraphVersion(Number(msg.version || getGraphVersion() || 0));
1480
1846
  }
@@ -1512,13 +1878,32 @@ async function handleHmrMessage(ev) {
1512
1878
  return;
1513
1879
  }
1514
1880
  if (msg.type === 'ns:css-updates' && Array.isArray(msg.updates)) {
1881
+ // Drive the HMR-applying overlay past the 'received' (5%) frame
1882
+ // that `ns:hmr-pending` set earlier in the cycle. Without this
1883
+ // the overlay sticks at "Preparing update" forever for CSS-only
1884
+ // edits because `handleCssUpdates` is a leaf — there's no
1885
+ // downstream module-evaluation path that would hit the queue's
1886
+ // 'complete' transition.
1887
+ const cssCount = msg.updates.length;
1888
+ try {
1889
+ setUpdateOverlayStage('reimporting', { detail: buildCssApplyingDetail(cssCount) });
1890
+ }
1891
+ catch { }
1515
1892
  try {
1516
1893
  const origin = msg.origin || getHttpOriginForVite() || deriveHttpOrigin(getHMRWsUrl());
1517
1894
  await handleCssUpdates(msg.updates, origin);
1895
+ try {
1896
+ setUpdateOverlayStage('complete', { detail: buildCssAppliedDetail(cssCount) });
1897
+ }
1898
+ catch { }
1518
1899
  return;
1519
1900
  }
1520
1901
  catch (e) {
1521
1902
  console.warn('[hmr-client] CSS updates handling failed:', e);
1903
+ try {
1904
+ setUpdateOverlayStage('complete', { detail: 'CSS update failed' });
1905
+ }
1906
+ catch { }
1522
1907
  return;
1523
1908
  }
1524
1909
  }
@@ -1529,10 +1914,22 @@ async function handleHmrMessage(ev) {
1529
1914
  if (msg.type === 'ns:vue-sfc-registry-update') {
1530
1915
  if (typeof msg.version === 'number')
1531
1916
  setGraphVersion(msg.version);
1532
- const comp = await handleVueSfcRegistryUpdate(msg, getGraphVersion());
1533
- if (comp) {
1534
- await performResetRoot(comp);
1535
- }
1917
+ // `ns:hmr-pending` already set the overlay to 'received' (5%).
1918
+ // Without the explicit stage walk below the overlay would stick
1919
+ // at "Preparing update" forever after a successful SFC swap —
1920
+ // the Vue path was missing the framework-specific completion
1921
+ // hooks that Angular drives via `handleAngularHotUpdateMessage`
1922
+ // and CSS drives inline above. `driveVueSfcUpdateOverlay` is a
1923
+ // thin orchestrator that walks 'evicting' → 'reimporting' →
1924
+ // 'rebooting' → 'complete' around the load + reset steps and
1925
+ // always lands on 'complete' (or a failure detail) so the
1926
+ // auto-hide timer can dismiss the toast.
1927
+ const sfcFilePath = typeof msg.path === 'string' ? msg.path : undefined;
1928
+ await driveVueSfcUpdateOverlay({
1929
+ filePath: sfcFilePath,
1930
+ loadComponent: () => handleVueSfcRegistryUpdate(msg, getGraphVersion()),
1931
+ applyComponent: (component) => performResetRoot(component),
1932
+ }, { getOverlay: getHmrOverlayApi });
1536
1933
  return;
1537
1934
  }
1538
1935
  }
@@ -1794,7 +2191,14 @@ async function performResetRoot(newComponent) {
1794
2191
  }
1795
2192
  catch { }
1796
2193
  const isAuthoritativeFrame = !!existingAppFrame && existingAppFrame !== placeholderFrame;
1797
- if (!hadPlaceholder && !isFrameRoot && isAuthoritativeFrame && typeof existingAppFrame.navigate === 'function') {
2194
+ // Vue: skip the in-place navigate path. After `app.mount(NSVRoot)` in getRootForVue the
2195
+ // new Page already has a parent (the freshly-constructed NSVRoot), so an attempt to navigate
2196
+ // the existing app Frame to that same Page completes silently without ever rebinding the
2197
+ // page to the Frame — the screen keeps showing the previous render. resetRootView with a
2198
+ // fresh Frame correctly reparents the Page and is the proven path that produces visible
2199
+ // in-place updates for SFC HMR cycles. Non-Vue flavors keep the legacy navigate fast path.
2200
+ const allowNavigateFastPath = TARGET_FLAVOR !== 'vue';
2201
+ if (allowNavigateFastPath && !hadPlaceholder && !isFrameRoot && isAuthoritativeFrame && typeof existingAppFrame.navigate === 'function') {
1798
2202
  try {
1799
2203
  const navEntry = {
1800
2204
  create: () => preparedRoot,