@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.
- package/README.md +51 -11
- package/configuration/angular.d.ts +34 -1
- package/configuration/angular.js +369 -159
- package/configuration/angular.js.map +1 -1
- package/configuration/base.js +184 -14
- package/configuration/base.js.map +1 -1
- package/configuration/javascript.js +5 -72
- package/configuration/javascript.js.map +1 -1
- package/configuration/solid.js +27 -1
- package/configuration/solid.js.map +1 -1
- package/configuration/typescript.js +5 -75
- package/configuration/typescript.js.map +1 -1
- package/helpers/angular/angular-linker.d.ts +5 -6
- package/helpers/angular/angular-linker.js +36 -121
- package/helpers/angular/angular-linker.js.map +1 -1
- package/helpers/angular/inject-component-hmr-registration.d.ts +112 -0
- package/helpers/angular/inject-component-hmr-registration.js +291 -0
- package/helpers/angular/inject-component-hmr-registration.js.map +1 -0
- package/helpers/angular/inject-hmr-vite-ignore.d.ts +75 -0
- package/helpers/angular/inject-hmr-vite-ignore.js +221 -0
- package/helpers/angular/inject-hmr-vite-ignore.js.map +1 -0
- package/helpers/angular/inline-decorator-component-templates.js +1 -170
- package/helpers/angular/inline-decorator-component-templates.js.map +1 -1
- package/helpers/angular/js-lexer.d.ts +4 -0
- package/helpers/angular/js-lexer.js +182 -0
- package/helpers/angular/js-lexer.js.map +1 -0
- package/helpers/angular/shared-linker.d.ts +31 -3
- package/helpers/angular/shared-linker.js +67 -14
- package/helpers/angular/shared-linker.js.map +1 -1
- package/helpers/angular/synthesize-decorator-ctor-parameters.js +2 -170
- package/helpers/angular/synthesize-decorator-ctor-parameters.js.map +1 -1
- package/helpers/angular/synthesize-injectable-factories.js +1 -174
- package/helpers/angular/synthesize-injectable-factories.js.map +1 -1
- package/helpers/angular/util.d.ts +1 -0
- package/helpers/angular/util.js +88 -0
- package/helpers/angular/util.js.map +1 -1
- package/helpers/app-components.d.ts +2 -1
- package/helpers/app-components.js.map +1 -1
- package/helpers/app-css-state.d.ts +8 -0
- package/helpers/app-css-state.js +8 -0
- package/helpers/app-css-state.js.map +1 -0
- package/helpers/bundler-context.d.ts +11 -0
- package/helpers/bundler-context.js +71 -0
- package/helpers/bundler-context.js.map +1 -0
- package/helpers/config-as-json.js +10 -0
- package/helpers/config-as-json.js.map +1 -1
- package/helpers/dev-host.d.ts +341 -0
- package/helpers/dev-host.js +617 -0
- package/helpers/dev-host.js.map +1 -0
- package/helpers/esbuild-platform-resolver.js +4 -1
- package/helpers/esbuild-platform-resolver.js.map +1 -1
- package/helpers/global-defines.d.ts +51 -0
- package/helpers/global-defines.js +77 -0
- package/helpers/global-defines.js.map +1 -1
- package/helpers/hmr-scope.d.ts +26 -0
- package/helpers/hmr-scope.js +67 -0
- package/helpers/hmr-scope.js.map +1 -0
- package/helpers/init.js +0 -18
- package/helpers/init.js.map +1 -1
- package/helpers/logging.d.ts +1 -0
- package/helpers/logging.js +63 -3
- package/helpers/logging.js.map +1 -1
- package/helpers/main-entry.d.ts +2 -1
- package/helpers/main-entry.js +430 -47
- package/helpers/main-entry.js.map +1 -1
- package/helpers/nativeclass-esbuild-plugin.d.ts +2 -1
- package/helpers/nativeclass-esbuild-plugin.js.map +1 -1
- package/helpers/nativeclass-transform.js.map +1 -1
- package/helpers/nativeclass-transformer-plugin.d.ts +9 -2
- package/helpers/nativeclass-transformer-plugin.js +157 -14
- package/helpers/nativeclass-transformer-plugin.js.map +1 -1
- package/helpers/nativescript-package-resolver.js +8 -3
- package/helpers/nativescript-package-resolver.js.map +1 -1
- package/helpers/normalize-id.d.ts +42 -0
- package/helpers/normalize-id.js +60 -0
- package/helpers/normalize-id.js.map +1 -0
- package/helpers/ns-core-url.d.ts +88 -0
- package/helpers/ns-core-url.js +191 -0
- package/helpers/ns-core-url.js.map +1 -0
- package/helpers/package-platform-aliases.js +4 -3
- package/helpers/package-platform-aliases.js.map +1 -1
- package/helpers/platform-types.d.ts +2 -0
- package/helpers/platform-types.js +2 -0
- package/helpers/platform-types.js.map +1 -0
- package/helpers/prelink-angular.js +12 -33
- package/helpers/prelink-angular.js.map +1 -1
- package/helpers/project.d.ts +35 -0
- package/helpers/project.js +120 -2
- package/helpers/project.js.map +1 -1
- package/helpers/resolver.js +17 -2
- package/helpers/resolver.js.map +1 -1
- package/helpers/solid-jsx-deps.d.ts +15 -0
- package/helpers/solid-jsx-deps.js +178 -0
- package/helpers/solid-jsx-deps.js.map +1 -0
- package/helpers/ts-config-paths.d.ts +14 -0
- package/helpers/ts-config-paths.js +89 -8
- package/helpers/ts-config-paths.js.map +1 -1
- package/helpers/typescript-check.d.ts +2 -1
- package/helpers/typescript-check.js.map +1 -1
- package/helpers/workers.d.ts +20 -19
- package/helpers/workers.js +624 -4
- package/helpers/workers.js.map +1 -1
- package/hmr/client/css-handler.d.ts +1 -0
- package/hmr/client/css-handler.js +33 -20
- package/hmr/client/css-handler.js.map +1 -1
- package/hmr/client/css-update-overlay.d.ts +18 -0
- package/hmr/client/css-update-overlay.js +27 -0
- package/hmr/client/css-update-overlay.js.map +1 -0
- package/hmr/client/hmr-pending-overlay.d.ts +27 -0
- package/hmr/client/hmr-pending-overlay.js +50 -0
- package/hmr/client/hmr-pending-overlay.js.map +1 -0
- package/hmr/client/index.js +419 -15
- package/hmr/client/index.js.map +1 -1
- package/hmr/client/utils.d.ts +6 -1
- package/hmr/client/utils.js +184 -8
- package/hmr/client/utils.js.map +1 -1
- package/hmr/client/vue-sfc-update-overlay.d.ts +82 -0
- package/hmr/client/vue-sfc-update-overlay.js +133 -0
- package/hmr/client/vue-sfc-update-overlay.js.map +1 -0
- package/hmr/entry-runtime.d.ts +2 -1
- package/hmr/entry-runtime.js +252 -65
- package/hmr/entry-runtime.js.map +1 -1
- package/hmr/frameworks/angular/client/index.d.ts +1 -0
- package/hmr/frameworks/angular/client/index.js +778 -20
- package/hmr/frameworks/angular/client/index.js.map +1 -1
- package/hmr/frameworks/angular/server/linker.js +1 -4
- package/hmr/frameworks/angular/server/linker.js.map +1 -1
- package/hmr/frameworks/angular/server/strategy.js +13 -15
- package/hmr/frameworks/angular/server/strategy.js.map +1 -1
- package/hmr/frameworks/solid/server/strategy.js +3 -18
- package/hmr/frameworks/solid/server/strategy.js.map +1 -1
- package/hmr/frameworks/typescript/server/strategy.js +2 -15
- package/hmr/frameworks/typescript/server/strategy.js.map +1 -1
- package/hmr/frameworks/vue/client/index.js +30 -199
- package/hmr/frameworks/vue/client/index.js.map +1 -1
- package/hmr/helpers/ast-normalizer.js +52 -5
- package/hmr/helpers/ast-normalizer.js.map +1 -1
- package/hmr/helpers/cjs-named-exports.d.ts +23 -0
- package/hmr/helpers/cjs-named-exports.js +152 -0
- package/hmr/helpers/cjs-named-exports.js.map +1 -0
- package/hmr/helpers/package-exports.d.ts +16 -0
- package/hmr/helpers/package-exports.js +396 -0
- package/hmr/helpers/package-exports.js.map +1 -0
- package/hmr/server/angular-root-component.d.ts +79 -0
- package/hmr/server/angular-root-component.js +149 -0
- package/hmr/server/angular-root-component.js.map +1 -0
- package/hmr/server/constants.js +13 -4
- package/hmr/server/constants.js.map +1 -1
- package/hmr/server/core-sanitize.d.ts +90 -7
- package/hmr/server/core-sanitize.js +211 -56
- package/hmr/server/core-sanitize.js.map +1 -1
- package/hmr/server/framework-strategy.d.ts +9 -19
- package/hmr/server/hmr-module-graph.d.ts +37 -0
- package/hmr/server/hmr-module-graph.js +214 -0
- package/hmr/server/hmr-module-graph.js.map +1 -0
- package/hmr/server/import-map.js +60 -8
- package/hmr/server/import-map.js.map +1 -1
- package/hmr/server/index.js +1 -0
- package/hmr/server/index.js.map +1 -1
- package/hmr/server/ns-core-cjs-shape.d.ts +204 -0
- package/hmr/server/ns-core-cjs-shape.js +271 -0
- package/hmr/server/ns-core-cjs-shape.js.map +1 -0
- package/hmr/server/ns-rt-bridge.d.ts +51 -0
- package/hmr/server/ns-rt-bridge.js +131 -0
- package/hmr/server/ns-rt-bridge.js.map +1 -0
- package/hmr/server/ns-rt-route.d.ts +5 -0
- package/hmr/server/ns-rt-route.js +35 -0
- package/hmr/server/ns-rt-route.js.map +1 -0
- package/hmr/server/perf-instrumentation.d.ts +114 -0
- package/hmr/server/perf-instrumentation.js +195 -0
- package/hmr/server/perf-instrumentation.js.map +1 -0
- package/hmr/server/require-guard.d.ts +1 -0
- package/hmr/server/require-guard.js +12 -0
- package/hmr/server/require-guard.js.map +1 -0
- package/hmr/server/route-helpers.d.ts +7 -0
- package/hmr/server/route-helpers.js +13 -0
- package/hmr/server/route-helpers.js.map +1 -0
- package/hmr/server/server-origin.d.ts +12 -0
- package/hmr/server/server-origin.js +66 -0
- package/hmr/server/server-origin.js.map +1 -0
- package/hmr/server/shared-transform-request.js +12 -5
- package/hmr/server/shared-transform-request.js.map +1 -1
- package/hmr/server/vendor-bare-module-shims.d.ts +4 -0
- package/hmr/server/vendor-bare-module-shims.js +80 -0
- package/hmr/server/vendor-bare-module-shims.js.map +1 -0
- package/hmr/server/vite-plugin.js +60 -42
- package/hmr/server/vite-plugin.js.map +1 -1
- package/hmr/server/websocket-angular-entry.js +1 -1
- package/hmr/server/websocket-angular-entry.js.map +1 -1
- package/hmr/server/websocket-angular-hot-update.d.ts +17 -0
- package/hmr/server/websocket-angular-hot-update.js +176 -2
- package/hmr/server/websocket-angular-hot-update.js.map +1 -1
- package/hmr/server/websocket-core-bridge.d.ts +41 -6
- package/hmr/server/websocket-core-bridge.js +72 -75
- package/hmr/server/websocket-core-bridge.js.map +1 -1
- package/hmr/server/websocket-css-hot-update.d.ts +33 -0
- package/hmr/server/websocket-css-hot-update.js +65 -0
- package/hmr/server/websocket-css-hot-update.js.map +1 -0
- package/hmr/server/websocket-device-transform.d.ts +21 -0
- package/hmr/server/websocket-device-transform.js +1570 -0
- package/hmr/server/websocket-device-transform.js.map +1 -0
- package/hmr/server/websocket-graph-upsert.d.ts +15 -0
- package/hmr/server/websocket-graph-upsert.js +20 -0
- package/hmr/server/websocket-graph-upsert.js.map +1 -1
- package/hmr/server/websocket-hmr-pending.d.ts +43 -0
- package/hmr/server/websocket-hmr-pending.js +55 -0
- package/hmr/server/websocket-hmr-pending.js.map +1 -0
- package/hmr/server/websocket-hot-update.d.ts +51 -0
- package/hmr/server/websocket-hot-update.js +1160 -0
- package/hmr/server/websocket-hot-update.js.map +1 -0
- package/hmr/server/websocket-import-map-route.d.ts +15 -0
- package/hmr/server/websocket-import-map-route.js +44 -0
- package/hmr/server/websocket-import-map-route.js.map +1 -0
- package/hmr/server/websocket-module-bindings.js +3 -3
- package/hmr/server/websocket-module-bindings.js.map +1 -1
- package/hmr/server/websocket-module-specifiers.d.ts +66 -2
- package/hmr/server/websocket-module-specifiers.js +202 -19
- package/hmr/server/websocket-module-specifiers.js.map +1 -1
- package/hmr/server/websocket-ns-core.d.ts +21 -0
- package/hmr/server/websocket-ns-core.js +305 -0
- package/hmr/server/websocket-ns-core.js.map +1 -0
- package/hmr/server/websocket-ns-entry.d.ts +22 -0
- package/hmr/server/websocket-ns-entry.js +150 -0
- package/hmr/server/websocket-ns-entry.js.map +1 -0
- package/hmr/server/websocket-ns-m-paths.d.ts +3 -0
- package/hmr/server/websocket-ns-m-paths.js +92 -0
- package/hmr/server/websocket-ns-m-paths.js.map +1 -0
- package/hmr/server/websocket-ns-m-request.d.ts +45 -0
- package/hmr/server/websocket-ns-m-request.js +196 -0
- package/hmr/server/websocket-ns-m-request.js.map +1 -0
- package/hmr/server/websocket-ns-m.d.ts +34 -0
- package/hmr/server/websocket-ns-m.js +853 -0
- package/hmr/server/websocket-ns-m.js.map +1 -0
- package/hmr/server/websocket-served-module-helpers.d.ts +39 -0
- package/hmr/server/websocket-served-module-helpers.js +654 -0
- package/hmr/server/websocket-served-module-helpers.js.map +1 -0
- package/hmr/server/websocket-sfc.d.ts +24 -0
- package/hmr/server/websocket-sfc.js +1223 -0
- package/hmr/server/websocket-sfc.js.map +1 -0
- package/hmr/server/websocket-txn.d.ts +6 -0
- package/hmr/server/websocket-txn.js +39 -0
- package/hmr/server/websocket-txn.js.map +1 -0
- package/hmr/server/websocket-vendor-unifier.d.ts +10 -0
- package/hmr/server/websocket-vendor-unifier.js +45 -0
- package/hmr/server/websocket-vendor-unifier.js.map +1 -0
- package/hmr/server/websocket.d.ts +0 -30
- package/hmr/server/websocket.js +599 -6038
- package/hmr/server/websocket.js.map +1 -1
- package/hmr/shared/runtime/boot-placeholder-ui.d.ts +69 -0
- package/hmr/shared/runtime/boot-placeholder-ui.js +101 -0
- package/hmr/shared/runtime/boot-placeholder-ui.js.map +1 -0
- package/hmr/shared/runtime/boot-progress.d.ts +40 -0
- package/hmr/shared/runtime/boot-progress.js +128 -0
- package/hmr/shared/runtime/boot-progress.js.map +1 -0
- package/hmr/shared/runtime/boot-timeline.d.ts +18 -0
- package/hmr/shared/runtime/boot-timeline.js +52 -0
- package/hmr/shared/runtime/boot-timeline.js.map +1 -0
- package/hmr/shared/runtime/dev-overlay-snapshots.d.ts +31 -0
- package/hmr/shared/runtime/dev-overlay-snapshots.js +324 -0
- package/hmr/shared/runtime/dev-overlay-snapshots.js.map +1 -0
- package/hmr/shared/runtime/dev-overlay.d.ts +75 -26
- package/hmr/shared/runtime/dev-overlay.js +990 -260
- package/hmr/shared/runtime/dev-overlay.js.map +1 -1
- package/hmr/shared/runtime/module-provenance.js +1 -4
- package/hmr/shared/runtime/module-provenance.js.map +1 -1
- package/hmr/shared/runtime/root-placeholder-view.d.ts +19 -0
- package/hmr/shared/runtime/root-placeholder-view.js +310 -0
- package/hmr/shared/runtime/root-placeholder-view.js.map +1 -0
- package/hmr/shared/runtime/root-placeholder.js +352 -194
- package/hmr/shared/runtime/root-placeholder.js.map +1 -1
- package/hmr/shared/runtime/session-bootstrap.js +164 -1
- package/hmr/shared/runtime/session-bootstrap.js.map +1 -1
- package/hmr/shared/runtime/vendor-bootstrap.js +1 -9
- package/hmr/shared/runtime/vendor-bootstrap.js.map +1 -1
- package/hmr/shared/vendor/manifest-collect.d.ts +32 -0
- package/hmr/shared/vendor/manifest-collect.js +512 -0
- package/hmr/shared/vendor/manifest-collect.js.map +1 -0
- package/hmr/shared/vendor/manifest-loader.d.ts +2 -1
- package/hmr/shared/vendor/manifest-loader.js +3 -2
- package/hmr/shared/vendor/manifest-loader.js.map +1 -1
- package/hmr/shared/vendor/manifest.d.ts +1 -5
- package/hmr/shared/vendor/manifest.js +102 -739
- package/hmr/shared/vendor/manifest.js.map +1 -1
- package/hmr/shared/vendor/vendor-device-shim.d.ts +1 -0
- package/hmr/shared/vendor/vendor-device-shim.js +208 -0
- package/hmr/shared/vendor/vendor-device-shim.js.map +1 -0
- package/hmr/shared/vendor/vendor-esbuild-plugins.d.ts +16 -0
- package/hmr/shared/vendor/vendor-esbuild-plugins.js +203 -0
- package/hmr/shared/vendor/vendor-esbuild-plugins.js.map +1 -0
- package/index.d.ts +1 -0
- package/index.js +5 -0
- package/index.js.map +1 -1
- package/package.json +55 -11
- package/runtime/core-aliases-early.js +17 -41
- package/runtime/core-aliases-early.js.map +1 -1
package/hmr/client/index.js
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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
|
|
854
|
-
|
|
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
|
|
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
|
|
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,
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
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
|
-
|
|
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,
|