Repository navigation
Description
Issue Description
Runtime error (dev server / HMR only). @nativescript/vite 8.0.5 · nativescript-vue 3.0.3 · @nativescript/core 9.1.1 · iOS simulator (iPhone 17 Pro Max).
Scope: iOS simulator only; not tested on Android or a physical device. This only becomes reachable in my setup once #11421 is worked around (NS_VENDOR_INCLUDE=...), but it is a separate mechanism.
Under HMR, $navigateTo comes from the /ns/rt bridge, which delegates to globalThis.__nsNavigateUsingApp and throws when that global is missing. The global is installed by the Vue client strategy, which is loaded by a fire-and-forget dynamic import() at module scope — nothing gates app boot on it.
Measured on an iOS simulator, the global is undefined at root-component mount (t+2-3ms) and becomes a function at t+395ms / t+434ms across runs. It's a device-side HTTP fetch, so a real device or a slower network will be later — no fixed delay is safe to assume. So a root/loader component that navigates shortly after mount fails:
Error: $navigateTo unavailable: app navigator missing
It's a race, not a permanent absence — a navigate at t+170ms fails, the same navigate at t+3000ms succeeds.
Expected behavior: $navigateTo from /ns/rt navigates (possibly after the strategy finishes loading) instead of throwing, matching what the same code does with --no-hmr.
I intend to submit a PR for this — have the bridge's $navigateTo wait for the client strategy to be installed (the loader already exports CLIENT_STRATEGY_READY) instead of throwing.
Mechanism (published 8.0.5 .js lines, with the matching packages/vite .ts lines on main)
/ns/rt's generated$navigateTothrows[ns-rt] $navigateTo unavailable: app navigator missingwhenglobalThis.__nsNavigateUsingAppis absent (hmr/server/ns-rt-bridge.js:96;.ts:123).- That global is only installed by
vueClientStrategy.install()→installVueNavigateUsingApp()(hmr/frameworks/vue/client/strategy.js:74-81/.ts:86-93;hmr/frameworks/vue/client/navigate-app.js:241/.ts:231-233). install()runs in the.then()of a bareimport(CLIENT_STRATEGY_URL)at module scope (hmr/client/strategy-loader.js:116-127;.ts:121-135) — an HTTP-ESM fetch on the device. Nothing awaits it before app code runs; the file's own comment (.ts:9-13) callsinstall()"not boot-critical".CLIENT_STRATEGY_READY(.ts:123) is awaited byhandleHmrMessage(hmr/client/protocol-dispatch.ts:82) but not by the bridge.
Reproduction
The realistic trigger is a root/loader component that navigates on startup (auth check, then go to Home):
// Root component (Loader.vue), plain nativescript-vue 3
import { $navigateTo } from 'nativescript-vue';
onMounted(() => {
nextTick(async () => {
await checkAuth(); // any short async step
$navigateTo(Home);
});
});- Blank
ns createVue TS app +npx nativescript-vite init(boots under HMR). - Make the root component navigate as above, ~150ms after mount.
ns debug ios→ throws$navigateTo unavailable: app navigator missing.ns debug ios --no-hmr→ navigates fine.
That exact shape passes with --no-hmr and fails under HMR, so the difference is the bridge, not the app. (Under --no-hmr the global is never installed at all — it logs "NEVER INSTALLED after 8597ms" and still navigates, because $navigateTo there is the vendor's, not the bridge's. So a timing difference can't explain the pass.)
Note: an immediate synchronous navigate from the root onMounted is invalid even without HMR (_context of null), so the async-then-navigate shape above is the load-bearing case.
Measured on the blank app with the #11421 workaround applied:
| Moment | typeof globalThis.__nsNavigateUsingApp |
|---|---|
| root mount (t+2-3ms) | undefined |
| t+395ms / t+434ms (two runs) | function |
| navigate scheduled +150ms (fired t+170ms) | throws |
| navigate at t+3000ms | succeeds |
App-side mitigation that works
Before the first navigate: if globalThis.__NS_HOT_REGISTRY__ exists (assigned only in hmr/client/hot-context.js:391 / .ts:466, so it is a reliable "HMR is on" probe), poll for __nsNavigateUsingApp every ~25ms with a bounded number of attempts; otherwise proceed immediately. That removes the failure entirely, and with it the app boots to Home under HMR with live edits applying.
Not tested: whether importing $navigateTo directly from nativescript-vue (bypassing /ns/rt) avoids this under HMR.
Relevant log output (if applicable)
[ns-rt] $navigateTo unavailable: app navigator missing
Error: $navigateTo unavailable: app navigator missingEnvironment
OS: macOS 26.6.2
CPU: (16) arm64 Apple M3 Max
Shell: /bin/zsh
node: 24.21.0
npm: 11.19.0
nativescript: 9.1.0 (project-local)
# ios
xcode: 26.6/17F113
cocoapods: 1.14.2
platforms:
- iOS 26.5"dependencies": {
"@nativescript/core": "~9.1.0",
"nativescript-vue": "~3.0.3",
"@valor/nativescript-websockets": "^2.0.2"
},
"devDependencies": {
"@nativescript/ios": "~9.1.0",
"@nativescript/tailwind": "^4.0.0",
"@nativescript/types": "~9.1.0",
"@nativescript/vite": "~8.0.4",
"@types/node": "^20.0.0",
"@vitejs/plugin-vue": "^6.0.8",
"@vitejs/plugin-vue-jsx": "^5.1.6",
"nativescript": "~9.1.0",
"tailwindcss": "^4.0.0",
"typescript": "~6.0.0",
"vite": "^8.2.2",
"vue-tsc": "^3.3.9"
}Please accept these terms
- I have searched the existing issues as well as StackOverflow and this has not been posted before
- This is a bug report
- I agree to follow this project's Code of Conduct
Activity
fix(vite): await the client strategy before /ns/rt $navigateTo report…