@nativescript/vite 8.0.0-alpha.3 → 8.0.0-alpha.31
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 +373 -163
- 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/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/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/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/framework-client-strategy.d.ts +73 -0
- package/hmr/client/framework-client-strategy.js +19 -0
- package/hmr/client/framework-client-strategy.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 +459 -164
- 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/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/build/angular-linker.d.ts +12 -0
- package/hmr/frameworks/angular/build/angular-linker.js +109 -0
- package/hmr/frameworks/angular/build/angular-linker.js.map +1 -0
- package/hmr/frameworks/angular/build/inject-component-hmr-registration.d.ts +112 -0
- package/hmr/frameworks/angular/build/inject-component-hmr-registration.js +291 -0
- package/hmr/frameworks/angular/build/inject-component-hmr-registration.js.map +1 -0
- package/hmr/frameworks/angular/build/inject-hmr-vite-ignore.d.ts +75 -0
- package/hmr/frameworks/angular/build/inject-hmr-vite-ignore.js +221 -0
- package/hmr/frameworks/angular/build/inject-hmr-vite-ignore.js.map +1 -0
- package/{helpers/angular → hmr/frameworks/angular/build}/inline-decorator-component-templates.js +1 -170
- package/hmr/frameworks/angular/build/inline-decorator-component-templates.js.map +1 -0
- package/hmr/frameworks/angular/build/js-lexer.d.ts +4 -0
- package/{helpers/angular/synthesize-decorator-ctor-parameters.js → hmr/frameworks/angular/build/js-lexer.js} +22 -96
- package/hmr/frameworks/angular/build/js-lexer.js.map +1 -0
- package/hmr/frameworks/angular/build/shared-linker.d.ts +39 -0
- package/hmr/frameworks/angular/build/shared-linker.js +128 -0
- package/hmr/frameworks/angular/build/shared-linker.js.map +1 -0
- package/hmr/frameworks/angular/build/synthesize-decorator-ctor-parameters.js +88 -0
- package/hmr/frameworks/angular/build/synthesize-decorator-ctor-parameters.js.map +1 -0
- package/{helpers/angular → hmr/frameworks/angular/build}/synthesize-injectable-factories.js +1 -174
- package/hmr/frameworks/angular/build/synthesize-injectable-factories.js.map +1 -0
- package/{helpers/angular → hmr/frameworks/angular/build}/util.d.ts +1 -0
- package/hmr/frameworks/angular/build/util.js +155 -0
- package/hmr/frameworks/angular/build/util.js.map +1 -0
- 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/client/strategy.d.ts +9 -0
- package/hmr/frameworks/angular/client/strategy.js +19 -0
- package/hmr/frameworks/angular/client/strategy.js.map +1 -0
- package/hmr/frameworks/angular/server/angular-root-component.d.ts +79 -0
- package/hmr/frameworks/angular/server/angular-root-component.js +149 -0
- package/hmr/frameworks/angular/server/angular-root-component.js.map +1 -0
- 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 +448 -12
- package/hmr/frameworks/angular/server/strategy.js.map +1 -1
- package/hmr/{server → frameworks/angular/server}/websocket-angular-entry.js +2 -2
- package/hmr/frameworks/angular/server/websocket-angular-entry.js.map +1 -0
- package/hmr/{server → frameworks/angular/server}/websocket-angular-hot-update.d.ts +17 -11
- package/hmr/frameworks/angular/server/websocket-angular-hot-update.js +336 -0
- package/hmr/frameworks/angular/server/websocket-angular-hot-update.js.map +1 -0
- package/hmr/frameworks/solid/build/solid-jsx-deps.d.ts +15 -0
- package/hmr/frameworks/solid/build/solid-jsx-deps.js +178 -0
- package/hmr/frameworks/solid/build/solid-jsx-deps.js.map +1 -0
- package/hmr/frameworks/solid/server/strategy.js +360 -16
- package/hmr/frameworks/solid/server/strategy.js.map +1 -1
- package/hmr/frameworks/typescript/server/strategy.js +28 -14
- 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/frameworks/vue/client/strategy.d.ts +7 -0
- package/hmr/frameworks/vue/client/strategy.js +83 -0
- package/hmr/frameworks/vue/client/strategy.js.map +1 -0
- package/hmr/frameworks/vue/client/vue-sfc-update-overlay.d.ts +82 -0
- package/hmr/frameworks/vue/client/vue-sfc-update-overlay.js +133 -0
- package/hmr/frameworks/vue/client/vue-sfc-update-overlay.js.map +1 -0
- package/hmr/frameworks/vue/server/sfc-route-assemble.d.ts +7 -0
- package/hmr/frameworks/vue/server/sfc-route-assemble.js +706 -0
- package/hmr/frameworks/vue/server/sfc-route-assemble.js.map +1 -0
- package/hmr/frameworks/vue/server/sfc-route-meta.d.ts +7 -0
- package/hmr/frameworks/vue/server/sfc-route-meta.js +80 -0
- package/hmr/frameworks/vue/server/sfc-route-meta.js.map +1 -0
- package/hmr/frameworks/vue/server/sfc-route-serve.d.ts +8 -0
- package/hmr/frameworks/vue/server/sfc-route-serve.js +457 -0
- package/hmr/frameworks/vue/server/sfc-route-serve.js.map +1 -0
- package/hmr/frameworks/vue/server/sfc-route-shared.d.ts +19 -0
- package/hmr/frameworks/vue/server/sfc-route-shared.js +14 -0
- package/hmr/frameworks/vue/server/sfc-route-shared.js.map +1 -0
- package/hmr/frameworks/vue/server/strategy.js +244 -0
- package/hmr/frameworks/vue/server/strategy.js.map +1 -1
- package/hmr/frameworks/vue/server/websocket-sfc.d.ts +15 -0
- package/hmr/frameworks/vue/server/websocket-sfc.js +20 -0
- package/hmr/frameworks/vue/server/websocket-sfc.js.map +1 -0
- 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/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/device-transform-helpers.d.ts +24 -0
- package/hmr/server/device-transform-helpers.js +327 -0
- package/hmr/server/device-transform-helpers.js.map +1 -0
- package/hmr/server/framework-strategy.d.ts +95 -11
- 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.d.ts +11 -2
- package/hmr/server/import-map.js +59 -40
- package/hmr/server/import-map.js.map +1 -1
- package/hmr/server/index.js +7 -16
- 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/process-code-for-device.d.ts +15 -0
- package/hmr/server/process-code-for-device.js +654 -0
- package/hmr/server/process-code-for-device.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/rewrite-imports.d.ts +2 -0
- package/hmr/server/rewrite-imports.js +604 -0
- package/hmr/server/rewrite-imports.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/transform-cache-invalidation.d.ts +11 -0
- package/hmr/server/transform-cache-invalidation.js +84 -0
- package/hmr/server/transform-cache-invalidation.js.map +1 -0
- 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-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 +3 -0
- package/hmr/server/websocket-device-transform.js +7 -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 +37 -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 +77 -0
- package/hmr/server/websocket-hot-update.js +330 -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 +46 -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 +306 -0
- package/hmr/server/websocket-ns-core.js.map +1 -0
- package/hmr/server/websocket-ns-entry.d.ts +21 -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 +33 -0
- package/hmr/server/websocket-ns-m.js +748 -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-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 +9 -0
- package/hmr/server/websocket-vendor-unifier.js +46 -0
- package/hmr/server/websocket-vendor-unifier.js.map +1 -0
- package/hmr/server/websocket.d.ts +8 -39
- package/hmr/server/websocket.js +602 -6049
- package/hmr/server/websocket.js.map +1 -1
- package/hmr/shared/ns-globals.d.ts +118 -0
- package/hmr/shared/ns-globals.js +27 -0
- package/hmr/shared/ns-globals.js.map +1 -0
- package/hmr/shared/protocol.d.ts +136 -0
- package/hmr/shared/protocol.js +28 -0
- package/hmr/shared/protocol.js.map +1 -0
- 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 +4 -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 -7
- package/hmr/shared/vendor/manifest.js +102 -741
- 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/helpers/angular/angular-linker.d.ts +0 -13
- package/helpers/angular/angular-linker.js +0 -194
- package/helpers/angular/angular-linker.js.map +0 -1
- package/helpers/angular/inline-decorator-component-templates.js.map +0 -1
- package/helpers/angular/shared-linker.d.ts +0 -11
- package/helpers/angular/shared-linker.js +0 -75
- package/helpers/angular/shared-linker.js.map +0 -1
- package/helpers/angular/synthesize-decorator-ctor-parameters.js.map +0 -1
- package/helpers/angular/synthesize-injectable-factories.js.map +0 -1
- package/helpers/angular/util.js +0 -67
- package/helpers/angular/util.js.map +0 -1
- package/helpers/prelink-angular.d.ts +0 -2
- package/helpers/prelink-angular.js +0 -117
- package/helpers/prelink-angular.js.map +0 -1
- package/hmr/server/websocket-angular-entry.js.map +0 -1
- package/hmr/server/websocket-angular-hot-update.js +0 -239
- package/hmr/server/websocket-angular-hot-update.js.map +0 -1
- /package/{helpers/angular → hmr/frameworks/angular/build}/inline-decorator-component-templates.d.ts +0 -0
- /package/{helpers/angular → hmr/frameworks/angular/build}/synthesize-decorator-ctor-parameters.d.ts +0 -0
- /package/{helpers/angular → hmr/frameworks/angular/build}/synthesize-injectable-factories.d.ts +0 -0
- /package/hmr/{server → frameworks/angular/server}/websocket-angular-entry.d.ts +0 -0
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,79 @@ 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
|
+
function setHmrPendingOverlay(filePath) {
|
|
176
|
+
applyHmrPendingFrame(filePath, { getOverlay: getHmrOverlayApi });
|
|
177
|
+
}
|
|
104
178
|
let connectionOverlayTimer = null;
|
|
105
179
|
let connectionOverlayVisible = false;
|
|
106
180
|
let hasOpenedHmrSocket = false;
|
|
@@ -142,19 +216,19 @@ function markHmrConnectionHealthy() {
|
|
|
142
216
|
hideConnectionOverlay();
|
|
143
217
|
}
|
|
144
218
|
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
219
|
+
let CLIENT_STRATEGY;
|
|
220
|
+
const CLIENT_STRATEGY_READY = TARGET_FLAVOR === 'vue' || TARGET_FLAVOR === 'angular'
|
|
221
|
+
? import(`../frameworks/${TARGET_FLAVOR}/client/strategy.js`)
|
|
222
|
+
.then((mod) => {
|
|
223
|
+
CLIENT_STRATEGY = mod && (mod[`${TARGET_FLAVOR}ClientStrategy`] ?? mod.default);
|
|
224
|
+
if (VERBOSE)
|
|
225
|
+
console.log('[hmr-client] client strategy loaded for flavor:', TARGET_FLAVOR);
|
|
226
|
+
CLIENT_STRATEGY?.install();
|
|
227
|
+
})
|
|
228
|
+
.catch((err) => {
|
|
229
|
+
console.warn('[hmr-client] failed to load client strategy for', TARGET_FLAVOR, err);
|
|
230
|
+
})
|
|
231
|
+
: Promise.resolve();
|
|
158
232
|
// Track whether we've mounted an initial app root yet in HTTP-only boot
|
|
159
233
|
let initialMounted = !!globalThis.__NS_HMR_BOOT_COMPLETE__;
|
|
160
234
|
// Prevent duplicate initial-mount scheduling across rapid full-graph broadcasts and re-evaluations
|
|
@@ -317,39 +391,7 @@ function applyFullGraph(payload) {
|
|
|
317
391
|
}
|
|
318
392
|
return;
|
|
319
393
|
}
|
|
320
|
-
|
|
321
|
-
switch (TARGET_FLAVOR) {
|
|
322
|
-
case 'vue': {
|
|
323
|
-
const appEntry = graph.get(APP_MAIN_ENTRY_SPEC);
|
|
324
|
-
if (appEntry && Array.isArray(appEntry.deps)) {
|
|
325
|
-
const vueDep = appEntry.deps.find((d) => typeof d === 'string' && /\.vue$/i.test(d));
|
|
326
|
-
if (vueDep)
|
|
327
|
-
candidate = vueDep;
|
|
328
|
-
}
|
|
329
|
-
if (!candidate) {
|
|
330
|
-
for (const id of graph.keys()) {
|
|
331
|
-
if (/\.vue$/i.test(id)) {
|
|
332
|
-
candidate = id;
|
|
333
|
-
break;
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
// Fallback: when the module graph is empty (Vite 7+ may not populate it
|
|
338
|
-
// before the first full-graph broadcast), check the SFC artifact registry
|
|
339
|
-
// which is populated from the ns:vue-sfc-registry message.
|
|
340
|
-
if (!candidate && sfcArtifactMap.size > 0) {
|
|
341
|
-
for (const id of sfcArtifactMap.keys()) {
|
|
342
|
-
if (/\.vue$/i.test(id)) {
|
|
343
|
-
candidate = id;
|
|
344
|
-
if (VERBOSE)
|
|
345
|
-
console.log('[hmr][init] rescue candidate from SFC registry:', id);
|
|
346
|
-
break;
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
break;
|
|
351
|
-
}
|
|
352
|
-
}
|
|
394
|
+
const candidate = CLIENT_STRATEGY?.selectMountCandidate?.({ graph, appMainEntrySpec: APP_MAIN_ENTRY_SPEC }) ?? null;
|
|
353
395
|
if (!candidate)
|
|
354
396
|
return;
|
|
355
397
|
initialMounting = true;
|
|
@@ -360,10 +402,8 @@ function applyFullGraph(payload) {
|
|
|
360
402
|
(async () => {
|
|
361
403
|
try {
|
|
362
404
|
let comp = null;
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
comp = await loadSfcComponent(candidate, 'initial_mount_rescue');
|
|
366
|
-
break;
|
|
405
|
+
if (CLIENT_STRATEGY?.loadComponentForMount) {
|
|
406
|
+
comp = await CLIENT_STRATEGY.loadComponentForMount(candidate, 'initial_mount_rescue');
|
|
367
407
|
}
|
|
368
408
|
if (!comp)
|
|
369
409
|
return;
|
|
@@ -404,41 +444,11 @@ function applyFullGraph(payload) {
|
|
|
404
444
|
// Only allow initial mount when explicitly enabled. Rely on the app's own main entry start() for the first mount
|
|
405
445
|
// to avoid double-mount races that can cause duplicate navigation logs.
|
|
406
446
|
if (ALLOW_INITIAL_MOUNT && !initialMounted && !bootDone && !bootInProgress && !getCurrentApp() && !getRootFrame()) {
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
const appEntry = graph.get(APP_MAIN_ENTRY_SPEC);
|
|
411
|
-
if (appEntry && Array.isArray(appEntry.deps)) {
|
|
412
|
-
const vueDep = appEntry.deps.find((d) => typeof d === 'string' && /\.vue$/i.test(d));
|
|
413
|
-
if (vueDep)
|
|
414
|
-
candidate = vueDep;
|
|
415
|
-
}
|
|
416
|
-
if (!candidate) {
|
|
417
|
-
for (const id of graph.keys()) {
|
|
418
|
-
if (/\.vue$/i.test(id)) {
|
|
419
|
-
candidate = id;
|
|
420
|
-
break;
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
// Fallback: SFC registry (same as rescue mount above)
|
|
425
|
-
if (!candidate && sfcArtifactMap.size > 0) {
|
|
426
|
-
for (const id of sfcArtifactMap.keys()) {
|
|
427
|
-
if (/\.vue$/i.test(id)) {
|
|
428
|
-
candidate = id;
|
|
429
|
-
if (VERBOSE)
|
|
430
|
-
console.log('[hmr][init] initial mount candidate from SFC registry:', id);
|
|
431
|
-
break;
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
break;
|
|
436
|
-
}
|
|
437
|
-
case 'typescript': {
|
|
438
|
-
// For TS flavor, do not perform client-driven initial mount; rely on Application.run.
|
|
439
|
-
return;
|
|
440
|
-
}
|
|
447
|
+
if (TARGET_FLAVOR === 'typescript') {
|
|
448
|
+
// For TS flavor, do not perform client-driven initial mount; rely on Application.run.
|
|
449
|
+
return;
|
|
441
450
|
}
|
|
451
|
+
const candidate = CLIENT_STRATEGY?.selectMountCandidate?.({ graph, appMainEntrySpec: APP_MAIN_ENTRY_SPEC }) ?? null;
|
|
442
452
|
if (candidate) {
|
|
443
453
|
// Mark initial-mount in progress (both module-local and global) BEFORE scheduling async work
|
|
444
454
|
initialMounting = true;
|
|
@@ -483,21 +493,19 @@ function applyFullGraph(payload) {
|
|
|
483
493
|
}
|
|
484
494
|
catch { }
|
|
485
495
|
let comp = null;
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
}
|
|
500
|
-
break;
|
|
496
|
+
if (TARGET_FLAVOR === 'typescript') {
|
|
497
|
+
try {
|
|
498
|
+
const url = await requestModuleFromServer(candidate);
|
|
499
|
+
const mod = await import(/* @vite-ignore */ url);
|
|
500
|
+
comp = mod && (mod.default || mod);
|
|
501
|
+
}
|
|
502
|
+
catch (e) {
|
|
503
|
+
if (VERBOSE)
|
|
504
|
+
console.warn('[hmr][init] TS initial mount failed to import', candidate, e);
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
else if (CLIENT_STRATEGY?.loadComponentForMount) {
|
|
508
|
+
comp = await CLIENT_STRATEGY.loadComponentForMount(candidate, 'initial_mount');
|
|
501
509
|
}
|
|
502
510
|
if (comp) {
|
|
503
511
|
const ok = await performResetRoot(comp);
|
|
@@ -558,11 +566,7 @@ function applyDelta(payload) {
|
|
|
558
566
|
setGraphVersion(payload.newVersion);
|
|
559
567
|
}
|
|
560
568
|
const changed = payload.changed || [];
|
|
561
|
-
|
|
562
|
-
case 'vue':
|
|
563
|
-
recordVuePayloadChanges(changed, getGraphVersion());
|
|
564
|
-
break;
|
|
565
|
-
}
|
|
569
|
+
CLIENT_STRATEGY?.recordPayloadChanges?.(changed, getGraphVersion());
|
|
566
570
|
(payload.changed || []).forEach((m) => {
|
|
567
571
|
if (!m || !m.id)
|
|
568
572
|
return;
|
|
@@ -648,11 +652,7 @@ function applyDelta(payload) {
|
|
|
648
652
|
// Deterministic navigation using the current Vue app instance rather than vendor-held rootApp
|
|
649
653
|
function __nsNavigateUsingApp(comp, opts = {}) {
|
|
650
654
|
const g = globalThis;
|
|
651
|
-
|
|
652
|
-
case 'vue':
|
|
653
|
-
ensureVueGlobals();
|
|
654
|
-
break;
|
|
655
|
-
}
|
|
655
|
+
CLIENT_STRATEGY?.beforeNavigateBuild?.();
|
|
656
656
|
const AppFactory = g.createApp;
|
|
657
657
|
const RootCtor = g.NSVRoot;
|
|
658
658
|
if (typeof AppFactory !== 'function' || typeof RootCtor !== 'function') {
|
|
@@ -675,12 +675,14 @@ function __nsNavigateUsingApp(comp, opts = {}) {
|
|
|
675
675
|
const buildTarget = () => {
|
|
676
676
|
const existingApp = getCurrentApp();
|
|
677
677
|
const baseProvides = (existingApp && existingApp._context && existingApp._context.provides) || {};
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
678
|
+
// Forward `opts.props` as Vue's rootProps so `$navigateTo(Comp, { props: { … } })`
|
|
679
|
+
// reaches the destination component. nativescript-vue's stock `$navigateTo`
|
|
680
|
+
// does the same via `createNativeView(target, options?.props, …)` →
|
|
681
|
+
// `renderer.createApp(component, props)`. Dropping props here would surface
|
|
682
|
+
// at the destination as `[Vue warn]: Missing required prop` and any
|
|
683
|
+
// required-prop component would render with `undefined` bindings.
|
|
684
|
+
const app = AppFactory(normalizeComponent(comp, comp && (comp.__name || comp.name)), opts && opts.props);
|
|
685
|
+
CLIENT_STRATEGY?.onNavAppCreated?.(app);
|
|
684
686
|
try {
|
|
685
687
|
const registry = g.__nsVendorRegistry;
|
|
686
688
|
const req = registry?.get ? g.__nsVendorRequire || g.__nsRequire || g.require : g.__nsRequire || g.require;
|
|
@@ -810,7 +812,42 @@ async function processQueue() {
|
|
|
810
812
|
return;
|
|
811
813
|
if (VERBOSE)
|
|
812
814
|
console.log('[hmr][queue] processing changed ids', drained);
|
|
815
|
+
// Track wall-clock so the 'complete' frame can show a meaningful
|
|
816
|
+
// total. Only the Solid + TypeScript flavors drive the overlay
|
|
817
|
+
// from here; Angular has its own flow inside
|
|
818
|
+
// `frameworks/angular/client/index.ts`.
|
|
819
|
+
const tQueueStart = Date.now();
|
|
820
|
+
const driveSolidOverlay = TARGET_FLAVOR === 'solid';
|
|
821
|
+
// Explicit eviction step.
|
|
822
|
+
//
|
|
823
|
+
// On modern runtimes the URL canonicalizer collapses any
|
|
824
|
+
// `__ns_hmr__/<tag>/` segment back to a stable cache key, so
|
|
825
|
+
// without explicit eviction the upcoming `import(url)` would
|
|
826
|
+
// resolve via V8's `g_moduleRegistry` and return the cached
|
|
827
|
+
// stale module — making the queue drain a silent no-op for
|
|
828
|
+
// every save after the first.
|
|
829
|
+
//
|
|
830
|
+
// We hand the canonical eviction URLs to the runtime first;
|
|
831
|
+
// `invalidateModulesByUrls` is a no-op on older runtimes and
|
|
832
|
+
// `requestModuleFromServer` automatically falls back to the
|
|
833
|
+
// legacy `/ns/m/__ns_hmr__/v<N>/` URL versioning path in that
|
|
834
|
+
// case. node_modules and virtual specs are filtered out by
|
|
835
|
+
// `buildEvictionUrls` so vendor modules stay hot.
|
|
836
|
+
if (driveSolidOverlay) {
|
|
837
|
+
setUpdateOverlayStage('evicting', {
|
|
838
|
+
detail: drained.length === 1 ? `Invalidating ${drained[0]}` : `Invalidating ${drained.length} modules`,
|
|
839
|
+
});
|
|
840
|
+
}
|
|
841
|
+
const evictUrls = buildEvictionUrls(drained);
|
|
842
|
+
const evicted = invalidateModulesByUrls(evictUrls);
|
|
843
|
+
if (VERBOSE)
|
|
844
|
+
console.log(`[hmr][queue] eviction count=${evictUrls.length} ok=${evicted}`);
|
|
813
845
|
// Evaluate changed modules best-effort; failures shouldn't completely break HMR.
|
|
846
|
+
if (driveSolidOverlay) {
|
|
847
|
+
setUpdateOverlayStage('reimporting', {
|
|
848
|
+
detail: drained.length === 1 ? `Re-importing ${drained[0]}` : `Re-importing ${drained.length} modules`,
|
|
849
|
+
});
|
|
850
|
+
}
|
|
814
851
|
for (const id of drained) {
|
|
815
852
|
try {
|
|
816
853
|
const spec = normalizeSpec(id);
|
|
@@ -829,9 +866,16 @@ async function processQueue() {
|
|
|
829
866
|
// After evaluating the batch, perform flavor-specific UI refresh.
|
|
830
867
|
switch (TARGET_FLAVOR) {
|
|
831
868
|
case 'vue':
|
|
832
|
-
|
|
869
|
+
await CLIENT_STRATEGY?.refreshAfterBatch?.(drained, { setUpdateOverlayStage, startedAt: tQueueStart });
|
|
833
870
|
break;
|
|
834
871
|
case 'solid': {
|
|
872
|
+
// Boundaries discovered in this HMR cycle (tsx files reachable
|
|
873
|
+
// via the reverse import graph from any changed file, plus route
|
|
874
|
+
// files reachable from any tsx start point). Declared at the top
|
|
875
|
+
// of the case block so the emit step below can include the
|
|
876
|
+
// complete set in the listener event — framework integrations
|
|
877
|
+
// use it to map route boundaries → fresh component references.
|
|
878
|
+
const boundaries = new Set();
|
|
835
879
|
// Solid .tsx components are self-accepting via solid-refresh's inline
|
|
836
880
|
// patchRegistry — re-importing them is sufficient. For non-component
|
|
837
881
|
// .ts utility modules, we must propagate up the import graph to find
|
|
@@ -850,8 +894,10 @@ async function processQueue() {
|
|
|
850
894
|
arr.push(id);
|
|
851
895
|
}
|
|
852
896
|
}
|
|
853
|
-
// BFS from each non-tsx changed module up to tsx/jsx
|
|
854
|
-
|
|
897
|
+
// Pass 1: BFS from each non-tsx changed module up to tsx/jsx
|
|
898
|
+
// boundaries. These get re-imported below so solid-refresh's
|
|
899
|
+
// inline patchRegistry runs and (best-effort) swaps the proxy
|
|
900
|
+
// signals for any components defined in those tsx boundaries.
|
|
855
901
|
for (const id of drained) {
|
|
856
902
|
if (/\.(tsx|jsx)$/i.test(id))
|
|
857
903
|
continue; // already self-accepting
|
|
@@ -875,6 +921,51 @@ async function processQueue() {
|
|
|
875
921
|
}
|
|
876
922
|
}
|
|
877
923
|
}
|
|
924
|
+
// Pass 2: walk further from any tsx starting point (a tsx file
|
|
925
|
+
// in `drained` OR a tsx boundary discovered in pass 1) to find
|
|
926
|
+
// route files (`/src/routes/*.{tsx,jsx}`) that transitively
|
|
927
|
+
// import them. Re-importing a route file refreshes its
|
|
928
|
+
// `Route.options.component` to the freshly-imported reference
|
|
929
|
+
// and the existing boundary loop below patches the live router
|
|
930
|
+
// with that fresh reference.
|
|
931
|
+
//
|
|
932
|
+
// This is the key fix for "edit home.tsx → save → no visual
|
|
933
|
+
// update": the old BFS skipped tsx files in `drained` (assuming
|
|
934
|
+
// solid-refresh's in-place proxy patch was sufficient), but in
|
|
935
|
+
// the universal-renderer + nested-context configuration that
|
|
936
|
+
// patch does not always propagate to the visible page tree.
|
|
937
|
+
// Adding the route file as a boundary lets us patch
|
|
938
|
+
// `route.options.component` directly to a fresh module export,
|
|
939
|
+
// which the framework subscriber then passes through to the
|
|
940
|
+
// page remount — making the cycle robust to the proxy patch
|
|
941
|
+
// silently failing.
|
|
942
|
+
const tsxStarts = new Set();
|
|
943
|
+
for (const id of drained) {
|
|
944
|
+
if (/\.(tsx|jsx)$/i.test(id))
|
|
945
|
+
tsxStarts.add(id);
|
|
946
|
+
}
|
|
947
|
+
for (const b of boundaries)
|
|
948
|
+
tsxStarts.add(b);
|
|
949
|
+
const ROUTE_FILE_RE = /\/src\/routes\/.+\.(tsx|jsx)$/i;
|
|
950
|
+
for (const start of tsxStarts) {
|
|
951
|
+
const visited = new Set();
|
|
952
|
+
const queue = [start];
|
|
953
|
+
while (queue.length) {
|
|
954
|
+
const cur = queue.shift();
|
|
955
|
+
if (visited.has(cur))
|
|
956
|
+
continue;
|
|
957
|
+
visited.add(cur);
|
|
958
|
+
if (cur !== start && ROUTE_FILE_RE.test(cur)) {
|
|
959
|
+
boundaries.add(cur);
|
|
960
|
+
}
|
|
961
|
+
const importers = reverseIndex.get(cur);
|
|
962
|
+
if (!importers)
|
|
963
|
+
continue;
|
|
964
|
+
for (const imp of importers) {
|
|
965
|
+
queue.push(imp);
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
}
|
|
878
969
|
// Re-import each boundary so solid-refresh patchRegistry fires.
|
|
879
970
|
// For route files (TanStack Router), capture the new Route export
|
|
880
971
|
// and patch the router's existing route with the fresh loader.
|
|
@@ -924,6 +1015,15 @@ async function processQueue() {
|
|
|
924
1015
|
}
|
|
925
1016
|
return null;
|
|
926
1017
|
};
|
|
1018
|
+
// Evict the boundary set so re-importing each .tsx
|
|
1019
|
+
// component actually picks up the new transitive
|
|
1020
|
+
// dependency code; without this V8 returns the
|
|
1021
|
+
// cached boundary module unchanged.
|
|
1022
|
+
const boundaryIds = Array.from(boundaries);
|
|
1023
|
+
const solidEvictUrls = buildEvictionUrls(boundaryIds);
|
|
1024
|
+
const solidEvicted = invalidateModulesByUrls(solidEvictUrls);
|
|
1025
|
+
if (VERBOSE)
|
|
1026
|
+
console.log(`[hmr][solid] eviction count=${solidEvictUrls.length} ok=${solidEvicted}`);
|
|
927
1027
|
for (const id of boundaries) {
|
|
928
1028
|
if (seen.has(id))
|
|
929
1029
|
continue;
|
|
@@ -935,22 +1035,28 @@ async function processQueue() {
|
|
|
935
1035
|
if (VERBOSE)
|
|
936
1036
|
console.log('[hmr][solid] propagated to boundary', { id, url });
|
|
937
1037
|
const mod = await import(/* @vite-ignore */ url);
|
|
938
|
-
// Patch TanStack Router route
|
|
1038
|
+
// Patch TanStack Router route options for any module
|
|
1039
|
+
// that exports a `Route`. We patch BOTH the component
|
|
1040
|
+
// and the loader (when present); components-only routes
|
|
1041
|
+
// were previously skipped because the gate required a
|
|
1042
|
+
// loader, which left their `options.component` pointing
|
|
1043
|
+
// at the stale module's exports after HMR.
|
|
939
1044
|
try {
|
|
940
1045
|
const newRoute = mod?.Route;
|
|
941
|
-
if (newRoute?.options
|
|
1046
|
+
if (newRoute?.options) {
|
|
942
1047
|
const router = findRouter();
|
|
943
1048
|
const fullPath = boundaryToFullPath(id);
|
|
944
1049
|
if (VERBOSE)
|
|
945
|
-
console.log('[hmr][solid][diag] route patch attempt', { id, fullPath, hasRouter: !!router,
|
|
1050
|
+
console.log('[hmr][solid][diag] route patch attempt', { id, fullPath, hasRouter: !!router, hasLoader: !!newRoute.options.loader, hasComponent: !!newRoute.options.component });
|
|
946
1051
|
const existingRoute = fullPath && router ? findRouteByFullPath(router, fullPath) : null;
|
|
947
1052
|
if (existingRoute?.options) {
|
|
948
|
-
|
|
1053
|
+
if (newRoute.options.loader)
|
|
1054
|
+
existingRoute.options.loader = newRoute.options.loader;
|
|
949
1055
|
if (newRoute.options.component)
|
|
950
1056
|
existingRoute.options.component = newRoute.options.component;
|
|
951
1057
|
routesPatchCount++;
|
|
952
1058
|
if (VERBOSE)
|
|
953
|
-
console.log('[hmr][solid] patched route
|
|
1059
|
+
console.log('[hmr][solid] patched route', existingRoute.id, 'fullPath=', fullPath);
|
|
954
1060
|
}
|
|
955
1061
|
else if (VERBOSE) {
|
|
956
1062
|
console.log('[hmr][solid] no matching route for fullPath', fullPath);
|
|
@@ -986,6 +1092,44 @@ async function processQueue() {
|
|
|
986
1092
|
if (VERBOSE)
|
|
987
1093
|
console.warn('[hmr][solid] propagation failed', e);
|
|
988
1094
|
}
|
|
1095
|
+
// Notify any framework integrations (e.g.
|
|
1096
|
+
// `@nativescript/tanstack-router`) that a Solid HMR
|
|
1097
|
+
// cycle has completed. They use this signal to perform
|
|
1098
|
+
// framework-specific UI refresh (e.g. remount the active
|
|
1099
|
+
// router page) when solid-refresh's own reactive
|
|
1100
|
+
// propagation does not reach the visible tree under
|
|
1101
|
+
// the current renderer/context configuration.
|
|
1102
|
+
//
|
|
1103
|
+
// Boundaries include both the directly-changed tsx files
|
|
1104
|
+
// AND every tsx ancestor reachable via the reverse import
|
|
1105
|
+
// graph (route files in particular). The framework
|
|
1106
|
+
// listener uses the route-file boundaries to look up the
|
|
1107
|
+
// freshly-patched `route.options.component` and pass it
|
|
1108
|
+
// through to the page remount.
|
|
1109
|
+
try {
|
|
1110
|
+
const tsxChangedInDrained = drained.filter((id) => /\.(tsx|jsx)$/i.test(id));
|
|
1111
|
+
const allBoundaries = Array.from(new Set([...tsxChangedInDrained, ...boundaries]));
|
|
1112
|
+
nsSolidHmrEmit({
|
|
1113
|
+
kind: 'solid',
|
|
1114
|
+
changedFiles: drained.slice(),
|
|
1115
|
+
boundaries: allBoundaries,
|
|
1116
|
+
});
|
|
1117
|
+
}
|
|
1118
|
+
catch (err) {
|
|
1119
|
+
if (VERBOSE)
|
|
1120
|
+
console.warn('[hmr][solid] emit failed', err);
|
|
1121
|
+
}
|
|
1122
|
+
// Tell the overlay the cycle is done. solid-refresh's
|
|
1123
|
+
// inline patchRegistry has already flushed the new
|
|
1124
|
+
// component bodies into the live tree (the `case
|
|
1125
|
+
// 'solid'` block above re-imports each .tsx
|
|
1126
|
+
// boundary), so by the time we get here the user is
|
|
1127
|
+
// already looking at the new render. The 'complete'
|
|
1128
|
+
// frame surfaces the wall-clock total and triggers
|
|
1129
|
+
// the overlay's auto-hide.
|
|
1130
|
+
setUpdateOverlayStage('complete', {
|
|
1131
|
+
detail: `Total ${Math.max(0, Date.now() - tQueueStart)}ms`,
|
|
1132
|
+
});
|
|
989
1133
|
break;
|
|
990
1134
|
}
|
|
991
1135
|
case 'typescript': {
|
|
@@ -1274,6 +1418,14 @@ function connectHmr() {
|
|
|
1274
1418
|
showConnectionOverlayNow('synchronizing', 'Connected. Synchronizing the HMR graph.');
|
|
1275
1419
|
}
|
|
1276
1420
|
VERBOSE && console.log('[hmr-client] Connected to HMR WebSocket');
|
|
1421
|
+
// Print the active module reload mode once on first
|
|
1422
|
+
// successful connect so the user can correlate HMR latency
|
|
1423
|
+
// with runtime capability without grepping for protocol
|
|
1424
|
+
// details. The banner is verbose-gated.
|
|
1425
|
+
try {
|
|
1426
|
+
emitHmrModeBannerOnce();
|
|
1427
|
+
}
|
|
1428
|
+
catch { }
|
|
1277
1429
|
};
|
|
1278
1430
|
sock.onmessage = handleHmrMessage;
|
|
1279
1431
|
sock.onerror = (error) => {
|
|
@@ -1333,6 +1485,22 @@ async function handleHmrMessage(ev) {
|
|
|
1333
1485
|
catch { }
|
|
1334
1486
|
}
|
|
1335
1487
|
if (msg) {
|
|
1488
|
+
// `ns:hmr-pending` is a fire-and-forget UX hint emitted by the
|
|
1489
|
+
// server at the START of handleHotUpdate. We drive the
|
|
1490
|
+
// HMR-applying overlay's 'received' frame here (synchronously),
|
|
1491
|
+
// well before the authoritative payload (`ns:angular-update` /
|
|
1492
|
+
// `ns:css-updates`) lands. Skip running any other handlers —
|
|
1493
|
+
// the pending message has no module payload and intentionally
|
|
1494
|
+
// does not bump the graph version.
|
|
1495
|
+
if (msg.type === 'ns:hmr-pending' && typeof msg.path === 'string') {
|
|
1496
|
+
setHmrPendingOverlay(msg.path);
|
|
1497
|
+
return;
|
|
1498
|
+
}
|
|
1499
|
+
// The per-flavor client strategy is loaded by a dynamic import(); make
|
|
1500
|
+
// sure it has resolved (and `install()` has run) before any handler that
|
|
1501
|
+
// delegates through it. After the first message this is an already-settled
|
|
1502
|
+
// promise (microtask only); for Solid/TypeScript it is `Promise.resolve()`.
|
|
1503
|
+
await CLIENT_STRATEGY_READY;
|
|
1336
1504
|
if (msg.type === 'ns:hmr-full-graph') {
|
|
1337
1505
|
// Bump a monotonic nonce so HTTP ESM imports can always be cache-busted per update.
|
|
1338
1506
|
try {
|
|
@@ -1402,6 +1570,14 @@ async function handleHmrMessage(ev) {
|
|
|
1402
1570
|
});
|
|
1403
1571
|
if (toReimport.length && VERBOSE)
|
|
1404
1572
|
console.log('[hmr][full-graph] inferred changed modules; re-importing', toReimport);
|
|
1573
|
+
// Evict the inferred changed set before re-importing.
|
|
1574
|
+
// See `processQueue` for the architectural rationale; the
|
|
1575
|
+
// full-graph code path is the resync fallback (server chose
|
|
1576
|
+
// not to send a delta) and shares the same V8 cache pitfall.
|
|
1577
|
+
const fgEvictUrls = buildEvictionUrls(toReimport);
|
|
1578
|
+
const fgEvicted = invalidateModulesByUrls(fgEvictUrls);
|
|
1579
|
+
if (VERBOSE)
|
|
1580
|
+
console.log(`[hmr][full-graph] eviction count=${fgEvictUrls.length} ok=${fgEvicted}`);
|
|
1405
1581
|
for (const id of toReimport) {
|
|
1406
1582
|
try {
|
|
1407
1583
|
const spec = normalizeSpec(id);
|
|
@@ -1475,10 +1651,108 @@ async function handleHmrMessage(ev) {
|
|
|
1475
1651
|
return;
|
|
1476
1652
|
}
|
|
1477
1653
|
else {
|
|
1654
|
+
// Vite custom-event dispatch.
|
|
1655
|
+
//
|
|
1656
|
+
// `server.ws.send('event-name', payload)` from any Vite plugin lands
|
|
1657
|
+
// on the wire as `{ type: 'custom', event: 'event-name', data: payload }`.
|
|
1658
|
+
// On the web, Vite's stock client owns a `customListenersMap` that
|
|
1659
|
+
// fires every `import.meta.hot.on('event-name', cb)` callback. We
|
|
1660
|
+
// don't run Vite's stock client on device — the iOS runtime owns
|
|
1661
|
+
// the listener registry via `__NS_DISPATCH_HOT_EVENT__` (the
|
|
1662
|
+
// counterpart to `import.meta.hot.on` populated by user code +
|
|
1663
|
+
// compiled Angular components). Forwarding `type: 'custom'` here
|
|
1664
|
+
// is the only thing standing between server-emitted events and
|
|
1665
|
+
// the listeners they were meant for.
|
|
1666
|
+
//
|
|
1667
|
+
// `angular:component-update` is the canonical example. Analog's
|
|
1668
|
+
// plugin sends it on `.html` / component-style edits; the
|
|
1669
|
+
// compiled component `.mjs` registered a listener that
|
|
1670
|
+
// dynamic-imports `/@ng/component?c=<id>&t=<ts>` and calls
|
|
1671
|
+
// `ɵɵreplaceMetadata` on the live class — swapping the template
|
|
1672
|
+
// definition AND walking live `LView`s to recreate matching views
|
|
1673
|
+
// in-place. The page stays mounted and only the changed bits
|
|
1674
|
+
// re-render. We MUST `return` after dispatch so the reboot path
|
|
1675
|
+
// (`handleAngularHotUpdateMessage` → `__reboot_ng_modules__`)
|
|
1676
|
+
// never runs for these updates — that's the whole point of the
|
|
1677
|
+
// component-replacement pipeline.
|
|
1678
|
+
//
|
|
1679
|
+
// All other custom events are forwarded but NOT short-circuited
|
|
1680
|
+
// (Vite spec: custom events are additive — they don't replace
|
|
1681
|
+
// any framework-specific handling). The reboot path falls through
|
|
1682
|
+
// for `ns:angular-update` (the legacy/`.ts`-edit broadcast) and
|
|
1683
|
+
// for any framework not yet using the in-place replacement path.
|
|
1684
|
+
if (msg.type === 'custom' && typeof msg.event === 'string') {
|
|
1685
|
+
// Dispatch every Vite "custom" event through the runtime's
|
|
1686
|
+
// `__NS_DISPATCH_HOT_EVENT__` bridge so `import.meta.hot.on(event, cb)`
|
|
1687
|
+
// callbacks fire on the device. Critical contract: this is the
|
|
1688
|
+
// ONLY route by which Analog's `angular:component-update` reaches
|
|
1689
|
+
// the compiled component's `(d) => d.id === id && Component_HmrLoad(...)`
|
|
1690
|
+
// listener — without it, server-side broadcasts log green
|
|
1691
|
+
// (`(client) hmr update`) while the device sees nothing happen.
|
|
1692
|
+
//
|
|
1693
|
+
// Diagnostic policy: log "no dispatcher" loud (boot-time rt-bridge
|
|
1694
|
+
// failure), and listener exceptions loud (compiled HmrLoad
|
|
1695
|
+
// fetch/parse error). Successful dispatches are silent — the
|
|
1696
|
+
// runtime's `[import.meta.hot] dispatch summary` line carries
|
|
1697
|
+
// the per-event match-count diagnostic.
|
|
1698
|
+
try {
|
|
1699
|
+
const dispatch = globalThis.__NS_DISPATCH_HOT_EVENT__;
|
|
1700
|
+
if (typeof dispatch === 'function') {
|
|
1701
|
+
dispatch(msg.event, msg.data);
|
|
1702
|
+
}
|
|
1703
|
+
else {
|
|
1704
|
+
console.warn(`[hmr-client][custom] no __NS_DISPATCH_HOT_EVENT__ available for '${msg.event}'`);
|
|
1705
|
+
}
|
|
1706
|
+
}
|
|
1707
|
+
catch (err) {
|
|
1708
|
+
console.warn('[hmr-client][custom] dispatch threw for', msg.event, err);
|
|
1709
|
+
}
|
|
1710
|
+
if (msg.event === 'angular:component-update') {
|
|
1711
|
+
if (VERBOSE)
|
|
1712
|
+
console.log('[hmr-client][custom] dispatched angular:component-update — skipping reboot path');
|
|
1713
|
+
// Walk the apply-progress overlay through its
|
|
1714
|
+
// remaining stages for the in-place template-swap
|
|
1715
|
+
// path. The full reboot path
|
|
1716
|
+
// (`handleAngularHotUpdateMessage`) drives the
|
|
1717
|
+
// overlay itself ('received' → 'evicting' →
|
|
1718
|
+
// 'reimporting' → 'rebooting' → 'complete'); the
|
|
1719
|
+
// in-place path bypasses that handler entirely
|
|
1720
|
+
// because the work happens inside Angular's
|
|
1721
|
+
// `ɵɵreplaceMetadata` after the runtime forwards the
|
|
1722
|
+
// `angular:component-update` event to the compiled
|
|
1723
|
+
// component's listener. Without this update the
|
|
1724
|
+
// overlay would freeze at 5% ('received') even
|
|
1725
|
+
// though the visual swap completes a few frames
|
|
1726
|
+
// later — exactly the "Preparing update (5%)" stuck
|
|
1727
|
+
// frame we have been chasing.
|
|
1728
|
+
//
|
|
1729
|
+
// We transition straight to 'reimporting' to
|
|
1730
|
+
// communicate that metadata is being fetched (the
|
|
1731
|
+
// runtime listener fires `__ns_import('/@ng/component?c=...&t=...')`),
|
|
1732
|
+
// then schedule 'complete' on the next macrotask so
|
|
1733
|
+
// the auto-hide timer kicks in. The actual
|
|
1734
|
+
// template swap is fire-and-forget from this point;
|
|
1735
|
+
// the user sees the overlay close at the same time
|
|
1736
|
+
// as Angular re-renders the bound text/structure.
|
|
1737
|
+
try {
|
|
1738
|
+
const filePath = typeof msg.data?.id === 'string' ? decodeURIComponent(msg.data.id).split('@')[0] : undefined;
|
|
1739
|
+
const detail = filePath ? `Applying template update to ${filePath}` : 'Applying template update';
|
|
1740
|
+
setUpdateOverlayStage('reimporting', { detail });
|
|
1741
|
+
setTimeout(() => {
|
|
1742
|
+
try {
|
|
1743
|
+
setUpdateOverlayStage('complete', { detail: filePath ? `Updated ${filePath}` : 'Update applied' });
|
|
1744
|
+
}
|
|
1745
|
+
catch { }
|
|
1746
|
+
}, 16);
|
|
1747
|
+
}
|
|
1748
|
+
catch { }
|
|
1749
|
+
return;
|
|
1750
|
+
}
|
|
1751
|
+
}
|
|
1478
1752
|
if (msg.type === 'ns:angular-update' && typeof msg.version === 'number') {
|
|
1479
1753
|
setGraphVersion(Number(msg.version || getGraphVersion() || 0));
|
|
1480
1754
|
}
|
|
1481
|
-
if (await
|
|
1755
|
+
if (CLIENT_STRATEGY?.handleHotUpdateMessage && (await CLIENT_STRATEGY.handleHotUpdateMessage(msg, { getCore, verbose: VERBOSE, performResetRoot, getOverlay: getHmrOverlayApi }))) {
|
|
1482
1756
|
return;
|
|
1483
1757
|
}
|
|
1484
1758
|
}
|
|
@@ -1512,27 +1786,47 @@ async function handleHmrMessage(ev) {
|
|
|
1512
1786
|
return;
|
|
1513
1787
|
}
|
|
1514
1788
|
if (msg.type === 'ns:css-updates' && Array.isArray(msg.updates)) {
|
|
1789
|
+
// Drive the HMR-applying overlay past the 'received' (5%) frame
|
|
1790
|
+
// that `ns:hmr-pending` set earlier in the cycle. Without this
|
|
1791
|
+
// the overlay sticks at "Preparing update" forever for CSS-only
|
|
1792
|
+
// edits because `handleCssUpdates` is a leaf — there's no
|
|
1793
|
+
// downstream module-evaluation path that would hit the queue's
|
|
1794
|
+
// 'complete' transition.
|
|
1795
|
+
const cssCount = msg.updates.length;
|
|
1796
|
+
try {
|
|
1797
|
+
setUpdateOverlayStage('reimporting', { detail: buildCssApplyingDetail(cssCount) });
|
|
1798
|
+
}
|
|
1799
|
+
catch { }
|
|
1515
1800
|
try {
|
|
1516
1801
|
const origin = msg.origin || getHttpOriginForVite() || deriveHttpOrigin(getHMRWsUrl());
|
|
1517
1802
|
await handleCssUpdates(msg.updates, origin);
|
|
1803
|
+
try {
|
|
1804
|
+
setUpdateOverlayStage('complete', { detail: buildCssAppliedDetail(cssCount) });
|
|
1805
|
+
}
|
|
1806
|
+
catch { }
|
|
1518
1807
|
return;
|
|
1519
1808
|
}
|
|
1520
1809
|
catch (e) {
|
|
1521
1810
|
console.warn('[hmr-client] CSS updates handling failed:', e);
|
|
1811
|
+
try {
|
|
1812
|
+
setUpdateOverlayStage('complete', { detail: 'CSS update failed' });
|
|
1813
|
+
}
|
|
1814
|
+
catch { }
|
|
1522
1815
|
return;
|
|
1523
1816
|
}
|
|
1524
1817
|
}
|
|
1525
1818
|
if (msg.type === 'ns:vue-sfc-registry') {
|
|
1526
|
-
|
|
1819
|
+
CLIENT_STRATEGY?.handleSfcRegistry?.(msg);
|
|
1527
1820
|
return;
|
|
1528
1821
|
}
|
|
1529
1822
|
if (msg.type === 'ns:vue-sfc-registry-update') {
|
|
1530
1823
|
if (typeof msg.version === 'number')
|
|
1531
1824
|
setGraphVersion(msg.version);
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1825
|
+
// `ns:hmr-pending` already set the overlay to 'received' (5%). The Vue
|
|
1826
|
+
// strategy walks 'evicting' → 'reimporting' → 'rebooting' → 'complete'
|
|
1827
|
+
// around the SFC load + reset so the toast always lands on 'complete'
|
|
1828
|
+
// (or a failure detail) and the auto-hide timer can dismiss it.
|
|
1829
|
+
await CLIENT_STRATEGY?.handleSfcRegistryUpdate?.(msg, getGraphVersion(), { getCore, verbose: VERBOSE, performResetRoot, getOverlay: getHmrOverlayApi });
|
|
1536
1830
|
return;
|
|
1537
1831
|
}
|
|
1538
1832
|
}
|
|
@@ -1552,7 +1846,7 @@ function normalizeComponent(input, nameHint) {
|
|
|
1552
1846
|
}
|
|
1553
1847
|
// If provided a render function, wrap with defineComponent
|
|
1554
1848
|
if (typeof input === 'function') {
|
|
1555
|
-
|
|
1849
|
+
CLIENT_STRATEGY?.beforeNavigateBuild?.();
|
|
1556
1850
|
const comp = globalThis.defineComponent
|
|
1557
1851
|
? globalThis.defineComponent({
|
|
1558
1852
|
name: nameHint || input.name || 'AnonymousSFC',
|
|
@@ -1563,7 +1857,7 @@ function normalizeComponent(input, nameHint) {
|
|
|
1563
1857
|
}
|
|
1564
1858
|
// If object has a render function property
|
|
1565
1859
|
if (input?.render && typeof input.render === 'function') {
|
|
1566
|
-
|
|
1860
|
+
CLIENT_STRATEGY?.beforeNavigateBuild?.();
|
|
1567
1861
|
const comp = globalThis.defineComponent
|
|
1568
1862
|
? globalThis.defineComponent({
|
|
1569
1863
|
name: nameHint || input.name || 'AnonymousSFC',
|
|
@@ -1621,35 +1915,32 @@ async function performResetRoot(newComponent) {
|
|
|
1621
1915
|
if (cachedRoot)
|
|
1622
1916
|
return cachedRoot;
|
|
1623
1917
|
try {
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
root = newComponent();
|
|
1634
|
-
}
|
|
1635
|
-
else {
|
|
1636
|
-
root = newComponent;
|
|
1637
|
-
}
|
|
1918
|
+
if (CLIENT_STRATEGY?.createRoot) {
|
|
1919
|
+
cachedRoot = CLIENT_STRATEGY.createRoot(newComponent, state);
|
|
1920
|
+
}
|
|
1921
|
+
else if (TARGET_FLAVOR === 'typescript') {
|
|
1922
|
+
// For TS flavor, treat the component as a factory or direct NS view.
|
|
1923
|
+
let root = null;
|
|
1924
|
+
try {
|
|
1925
|
+
if (typeof newComponent === 'function') {
|
|
1926
|
+
root = newComponent();
|
|
1638
1927
|
}
|
|
1639
|
-
|
|
1640
|
-
|
|
1928
|
+
else {
|
|
1929
|
+
root = newComponent;
|
|
1641
1930
|
}
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1931
|
+
}
|
|
1932
|
+
catch (e) {
|
|
1933
|
+
console.warn('[hmr-client][ts] root factory invocation failed', e);
|
|
1934
|
+
}
|
|
1935
|
+
cachedRoot = root || {};
|
|
1936
|
+
// Heuristic: if the root "looks" like a Frame, prefer frame semantics
|
|
1937
|
+
try {
|
|
1938
|
+
const name = String(cachedRoot?.constructor?.name || '').replace(/^_+/, '');
|
|
1939
|
+
if (/^Frame(\$\d+)?$/.test(name)) {
|
|
1940
|
+
rootKind = 'frame';
|
|
1649
1941
|
}
|
|
1650
|
-
catch { }
|
|
1651
|
-
break;
|
|
1652
1942
|
}
|
|
1943
|
+
catch { }
|
|
1653
1944
|
}
|
|
1654
1945
|
return cachedRoot;
|
|
1655
1946
|
}
|
|
@@ -1794,7 +2085,14 @@ async function performResetRoot(newComponent) {
|
|
|
1794
2085
|
}
|
|
1795
2086
|
catch { }
|
|
1796
2087
|
const isAuthoritativeFrame = !!existingAppFrame && existingAppFrame !== placeholderFrame;
|
|
1797
|
-
|
|
2088
|
+
// Vue: skip the in-place navigate path. After `app.mount(NSVRoot)` in getRootForVue the
|
|
2089
|
+
// new Page already has a parent (the freshly-constructed NSVRoot), so an attempt to navigate
|
|
2090
|
+
// the existing app Frame to that same Page completes silently without ever rebinding the
|
|
2091
|
+
// page to the Frame — the screen keeps showing the previous render. resetRootView with a
|
|
2092
|
+
// fresh Frame correctly reparents the Page and is the proven path that produces visible
|
|
2093
|
+
// in-place updates for SFC HMR cycles. Non-Vue flavors keep the legacy navigate fast path.
|
|
2094
|
+
const allowNavigateFastPath = CLIENT_STRATEGY?.allowNavigateFastPath ?? true;
|
|
2095
|
+
if (allowNavigateFastPath && !hadPlaceholder && !isFrameRoot && isAuthoritativeFrame && typeof existingAppFrame.navigate === 'function') {
|
|
1798
2096
|
try {
|
|
1799
2097
|
const navEntry = {
|
|
1800
2098
|
create: () => preparedRoot,
|
|
@@ -1957,12 +2255,9 @@ export function initHmrClient(opts) {
|
|
|
1957
2255
|
console.log('[hmr-client] deferring WebSocket connection until boot completes');
|
|
1958
2256
|
setTimeout(waitForBoot, 100);
|
|
1959
2257
|
}
|
|
1960
|
-
// Best-effort: install back wrapper even before first remount; original root may be captured later
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
ensureBackWrapperInstalled(performResetRoot, getCore);
|
|
1964
|
-
break;
|
|
1965
|
-
}
|
|
2258
|
+
// Best-effort: install back wrapper even before first remount; original root may be captured later.
|
|
2259
|
+
// Deferred until the dynamically-imported strategy resolves.
|
|
2260
|
+
void CLIENT_STRATEGY_READY.then(() => CLIENT_STRATEGY?.installBackWrapper?.(performResetRoot, getCore));
|
|
1966
2261
|
}
|
|
1967
2262
|
export default function startViteHMR(opts) {
|
|
1968
2263
|
if (VERBOSE)
|