@nativescript/vite 8.0.0-alpha.6 → 8.0.0-alpha.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/configuration/base.js +8 -8
  2. package/configuration/base.js.map +1 -1
  3. package/helpers/global-defines.d.ts +7 -13
  4. package/helpers/global-defines.js +10 -16
  5. package/helpers/global-defines.js.map +1 -1
  6. package/helpers/main-entry.js +5 -6
  7. package/helpers/main-entry.js.map +1 -1
  8. package/helpers/ns-core-url.d.ts +5 -6
  9. package/helpers/ns-core-url.js +5 -6
  10. package/helpers/ns-core-url.js.map +1 -1
  11. package/hmr/client/css-handler.js +2 -1
  12. package/hmr/client/css-handler.js.map +1 -1
  13. package/hmr/client/hmr-pending-overlay.d.ts +1 -1
  14. package/hmr/client/hmr-pending-overlay.js +1 -1
  15. package/hmr/client/index.js +27 -26
  16. package/hmr/client/index.js.map +1 -1
  17. package/hmr/client/utils.js +27 -25
  18. package/hmr/client/utils.js.map +1 -1
  19. package/hmr/frameworks/angular/client/index.js +78 -86
  20. package/hmr/frameworks/angular/client/index.js.map +1 -1
  21. package/hmr/server/core-sanitize.js +8 -8
  22. package/hmr/server/core-sanitize.js.map +1 -1
  23. package/hmr/server/import-map.js +3 -4
  24. package/hmr/server/import-map.js.map +1 -1
  25. package/hmr/server/ns-core-cjs-shape.d.ts +2 -4
  26. package/hmr/server/ns-core-cjs-shape.js +3 -5
  27. package/hmr/server/ns-core-cjs-shape.js.map +1 -1
  28. package/hmr/server/perf-instrumentation.d.ts +5 -9
  29. package/hmr/server/perf-instrumentation.js +2 -5
  30. package/hmr/server/perf-instrumentation.js.map +1 -1
  31. package/hmr/server/vite-plugin.js +3 -1
  32. package/hmr/server/vite-plugin.js.map +1 -1
  33. package/hmr/server/websocket-angular-hot-update.js +27 -29
  34. package/hmr/server/websocket-angular-hot-update.js.map +1 -1
  35. package/hmr/server/websocket-core-bridge.js +11 -16
  36. package/hmr/server/websocket-core-bridge.js.map +1 -1
  37. package/hmr/server/websocket-hmr-pending.d.ts +1 -1
  38. package/hmr/server/websocket-hmr-pending.js +1 -1
  39. package/hmr/server/websocket-ns-m-paths.js +14 -15
  40. package/hmr/server/websocket-ns-m-paths.js.map +1 -1
  41. package/hmr/server/websocket-runtime-compat.js +3 -2
  42. package/hmr/server/websocket-runtime-compat.js.map +1 -1
  43. package/hmr/server/websocket-served-module-helpers.js +13 -12
  44. package/hmr/server/websocket-served-module-helpers.js.map +1 -1
  45. package/hmr/server/websocket.js +238 -219
  46. package/hmr/server/websocket.js.map +1 -1
  47. package/hmr/shared/runtime/boot-timeline.js +0 -3
  48. package/hmr/shared/runtime/boot-timeline.js.map +1 -1
  49. package/hmr/shared/runtime/dev-overlay.js +31 -33
  50. package/hmr/shared/runtime/dev-overlay.js.map +1 -1
  51. package/hmr/shared/runtime/session-bootstrap.js +12 -9
  52. package/hmr/shared/runtime/session-bootstrap.js.map +1 -1
  53. package/package.json +1 -1
@@ -80,14 +80,13 @@ const APP_VIRTUAL_PREFIX = getProjectAppVirtualPath();
80
80
  const APP_VIRTUAL_WITH_SLASH = `${APP_VIRTUAL_PREFIX}/`;
81
81
  const DEFAULT_MAIN_ENTRY = getProjectAppRelativePath('app.ts');
82
82
  const DEFAULT_MAIN_ENTRY_VIRTUAL = getProjectAppVirtualPath('app.ts');
83
- // alpha.59 — Stable URL + Explicit Invalidation:
84
83
  // Memoized resolver for the project bootstrap entry as a posix
85
- // project-relative path (e.g. `/src/main.ts`). This mirrors the resolution
86
- // the cold-boot wrapper performs (`getPackageJson().main` →
87
- // project-relative under `/<APP_ROOT_DIR>/`) so the eviction set for HMR
88
- // always lines up with the URL the runtime actually re-imports. Resolved
89
- // at first call and cached: `package.json` is read at startup and never
90
- // changes during a dev session, so it's safe to memoize.
84
+ // project-relative path (e.g. `/src/main.ts`). This mirrors the
85
+ // resolution the cold-boot wrapper performs (`getPackageJson().main` →
86
+ // project-relative under `/<APP_ROOT_DIR>/`) so the eviction set for
87
+ // HMR always lines up with the URL the runtime actually re-imports.
88
+ // Resolved at first call and cached: `package.json` is read at startup
89
+ // and never changes during a dev session, so it's safe to memoize.
91
90
  let __ns_bootstrap_entry_rel_cached = null;
92
91
  function getBootstrapEntryRelPath() {
93
92
  if (__ns_bootstrap_entry_rel_cached)
@@ -354,11 +353,9 @@ function ensureGuardPlainDynamicImports(code, origin) {
354
353
  return code;
355
354
  }
356
355
  }
357
- // alpha.59 — `ensureDynamicHmrImportHelper` was previously duplicated
358
- // here. Single source of truth now lives in
356
+ // `ensureDynamicHmrImportHelper` lives in
359
357
  // `./websocket-served-module-helpers.js`. See that file for the
360
- // architectural rationale and the current (much smaller) helper
361
- // implementation.
358
+ // architectural rationale and the current helper implementation.
362
359
  async function expandStarExports(code, server, projectRoot, verbose, sharedTransformer) {
363
360
  const STAR_RE = /^[ \t]*(export\s+\*\s+from\s+["'])([^"']+)(["'];?)[ \t]*$/gm;
364
361
  let match;
@@ -914,14 +911,13 @@ function toNodeModulesHttpModuleId(importPath) {
914
911
  }
915
912
  return `/ns/m/node_modules/${nodeModulesSpecifier}`;
916
913
  }
917
- // alpha.59 — `rewriteNsMImportPathForHmr` and `getNumericServeVersionTag`
918
- // previously lived here as duplicates of the implementations in
914
+ // `rewriteNsMImportPathForHmr` and `getNumericServeVersionTag` live in
919
915
  // `./websocket-ns-m-paths.js`. The path rewriter is part of the
920
- // "Stable URL + Explicit Invalidation" architecture (see
921
- // HMR_STABLE_URL_INVALIDATION_PLAN.md) and must be a single source of
922
- // truth so the canonicalization rules can't drift between the two files.
923
- // They are imported above and re-exported below for tests / external
924
- // callers that historically reached them through this module.
916
+ // "Stable URL + Explicit Invalidation" architecture and must be a
917
+ // single source of truth so the canonicalization rules can't drift
918
+ // between modules. They are imported above and re-exported below for
919
+ // tests / external callers that historically reached them through this
920
+ // module.
925
921
  function normalizeAbsoluteFilesystemImport(spec, importerPath, projectRoot) {
926
922
  if (!spec || typeof spec !== 'string') {
927
923
  return null;
@@ -2593,7 +2589,7 @@ function createHmrWebSocketPlugin(opts) {
2593
2589
  }
2594
2590
  // bumpVersion: false — the initial walk is a bulk load, not a live
2595
2591
  // edit. Keeping graphVersion stable during cold boot avoids double
2596
- // cache-key drift described in Track 1.3 of the HMR plan.
2592
+ // cache-key drift.
2597
2593
  upsertGraphModule(rel, code, deps, { bumpVersion: false });
2598
2594
  }
2599
2595
  catch { }
@@ -2607,18 +2603,22 @@ function createHmrWebSocketPlugin(opts) {
2607
2603
  await walk(pathMod.join(root, 'src'));
2608
2604
  }
2609
2605
  catch { }
2610
- // Diagnostic summary: Always-on so slow
2611
- // cold-boot walks surface even when verbose is off. A `bumpedVersion=no`
2612
- // result is the happy path (Track 1.3); `yes` indicates a regression.
2613
- try {
2614
- console.info(formatPopulateInitialGraphSummary({
2615
- moduleCount: graph.size,
2616
- durationMs: Date.now() - tStart,
2617
- graphVersion,
2618
- bumpedVersion: graphVersion !== versionAtStart,
2619
- }));
2606
+ // Diagnostic summary. Gated behind the verbose flag so the
2607
+ // dev console stays quiet on a normal save. Flip
2608
+ // NS_VITE_VERBOSE=1 to surface slow cold-boot walks; a
2609
+ // `bumpedVersion=no` result is the happy path, `yes`
2610
+ // indicates a regression.
2611
+ if (verbose) {
2612
+ try {
2613
+ console.info(formatPopulateInitialGraphSummary({
2614
+ moduleCount: graph.size,
2615
+ durationMs: Date.now() - tStart,
2616
+ graphVersion,
2617
+ bumpedVersion: graphVersion !== versionAtStart,
2618
+ }));
2619
+ }
2620
+ catch { }
2620
2621
  }
2621
- catch { }
2622
2622
  }
2623
2623
  // Kick off `populateInitialGraph` in the background (non-awaited) so /ns/m
2624
2624
  // responses are never blocked on a full tree walk. Returns the shared
@@ -2669,16 +2669,16 @@ function createHmrWebSocketPlugin(opts) {
2669
2669
  // race conditions during HTTP HMR startup, but the shared runner
2670
2670
  // already has per-URL coalescing and an async-cached result map,
2671
2671
  // so higher fan-out is safe and dramatically reduces cold-boot
2672
- // time (Track 1.4 in HMR_CORE_REALM_DETERMINISTIC_PLAN.md). We cap
2673
- // at 8 by default to match typical dev machines and respect Vite's
2674
- // internal worker pool limits. Override via the env var when needed.
2672
+ // time. We cap at 8 by default to match typical dev machines and
2673
+ // respect Vite's internal worker pool limits. Override via the
2674
+ // `NS_VITE_HMR_TRANSFORM_CONCURRENCY` env var when needed.
2675
2675
  const configuredTransformConcurrency = Number.parseInt(process.env.NS_VITE_HMR_TRANSFORM_CONCURRENCY || '', 10);
2676
2676
  const transformConcurrency = Number.isFinite(configuredTransformConcurrency) && configuredTransformConcurrency > 0 ? configuredTransformConcurrency : 8;
2677
- // Keep transformed code cached for longer across HMR updates so that
2678
- // unchanged neighbours of an edited file don't re-run through the
2679
- // Angular/TypeScript/Vite transform pipeline. The HMR flow
2680
- // explicitly invalidates affected URLs, so a longer TTL is safe.
2681
- // See Track 2.2 in HMR_CORE_REALM_DETERMINISTIC_PLAN.md.
2677
+ // Keep transformed code cached for longer across HMR updates so
2678
+ // that unchanged neighbours of an edited file don't re-run
2679
+ // through the Angular/TypeScript/Vite transform pipeline. The
2680
+ // HMR flow explicitly invalidates affected URLs, so a longer TTL
2681
+ // is safe. Override with `NS_VITE_HMR_TRANSFORM_CACHE_MS`.
2682
2682
  const configuredTransformCacheMs = Number.parseInt(process.env.NS_VITE_HMR_TRANSFORM_CACHE_MS || '', 10);
2683
2683
  const transformCacheMs = Number.isFinite(configuredTransformCacheMs) && configuredTransformCacheMs >= 0 ? configuredTransformCacheMs : 60000;
2684
2684
  sharedTransformRequest = createSharedTransformRequestRunner((url) => server.transformRequest(url), (url, timeoutMs) => {
@@ -2691,10 +2691,9 @@ function createHmrWebSocketPlugin(opts) {
2691
2691
  resultCacheTtlMs: transformCacheMs,
2692
2692
  getResultCacheKey: (url) => canonicalizeTransformRequestCacheKey(url, pluginRoot || process.cwd()),
2693
2693
  });
2694
- // Always-on startup banner — prints once per dev server process so
2695
- // anyone investigating perf can immediately see which build is live
2696
- // and what knobs are active. See HMR_CORE_REALM_DETERMINISTIC_PLAN.md
2697
- // ("Track 1 + 2 — diagnostic instrumentation").
2694
+ // Always-on startup banner — prints once per dev server process
2695
+ // so anyone investigating perf can immediately see which build
2696
+ // is live and what knobs are active.
2698
2697
  try {
2699
2698
  let pkgVersion = 'unknown';
2700
2699
  try {
@@ -2717,26 +2716,27 @@ function createHmrWebSocketPlugin(opts) {
2717
2716
  }
2718
2717
  catch { }
2719
2718
  }
2720
- console.info(formatServerStartupBanner({
2721
- version: pkgVersion,
2722
- transformConcurrency,
2723
- transformCacheMs,
2724
- lazyInitialGraph: true,
2725
- graphVersion,
2726
- }));
2719
+ if (verbose) {
2720
+ console.info(formatServerStartupBanner({
2721
+ version: pkgVersion,
2722
+ transformConcurrency,
2723
+ transformCacheMs,
2724
+ lazyInitialGraph: true,
2725
+ graphVersion,
2726
+ }));
2727
+ }
2727
2728
  }
2728
2729
  catch { }
2729
- // Always-on cold-boot request trace. Runs in front of every other
2730
- // middleware so it catches all NS dev routes (/ns/m/*, /ns/rt/*,
2731
- // /ns/core/*, /__ns_boot__/*, etc.) with a single hook. Closes
2732
- // itself after an idle window so HMR edits don't get rolled into
2733
- // the cold-boot numbers. The idle window is generous by default
2734
- // (5s) because V8's HTTP ESM resolver pauses between dep levels
2735
- // while parsing — a too-tight window was closing after the first
2736
- // wave and under-reporting boot by 100x. Override via
2737
- // NS_VITE_HMR_BOOT_TRACE_IDLE_MS when profiling something tricky.
2738
- // See HMR_CORE_REALM_DETERMINISTIC_PLAN.md ("Track 1 + 2 — round
2739
- // three, 2026-04").
2730
+ // Always-on cold-boot request trace. Runs in front of every
2731
+ // other middleware so it catches all NS dev routes (/ns/m/*,
2732
+ // /ns/rt/*, /ns/core/*, /__ns_boot__/*, etc.) with a single
2733
+ // hook. Closes itself after an idle window so HMR edits don't
2734
+ // get rolled into the cold-boot numbers. The idle window is
2735
+ // generous by default (5s) because V8's HTTP ESM resolver
2736
+ // pauses between dep levels while parsing — a too-tight window
2737
+ // was closing after the first wave and under-reporting boot by
2738
+ // 100x. Override via `NS_VITE_HMR_BOOT_TRACE_IDLE_MS` when
2739
+ // profiling something tricky.
2740
2740
  try {
2741
2741
  const configuredIdleMs = Number.parseInt(process.env.NS_VITE_HMR_BOOT_TRACE_IDLE_MS || '', 10);
2742
2742
  const idleWindowMs = Number.isFinite(configuredIdleMs) && configuredIdleMs > 0 ? configuredIdleMs : 5000;
@@ -2746,7 +2746,12 @@ function createHmrWebSocketPlugin(opts) {
2746
2746
  coldBootCounter = createColdBootRequestCounter({
2747
2747
  summaryEvery,
2748
2748
  idleWindowMs,
2749
+ // Gated on the verbose flag so cold-boot progress and
2750
+ // the final window-closed summary stay quiet by
2751
+ // default. Flip NS_VITE_VERBOSE=1 to surface them.
2749
2752
  log: (line) => {
2753
+ if (!verbose)
2754
+ return;
2750
2755
  try {
2751
2756
  console.info(line);
2752
2757
  }
@@ -2784,13 +2789,12 @@ function createHmrWebSocketPlugin(opts) {
2784
2789
  // kicked off on the first /ns/m hit, which meant populate was
2785
2790
  // competing with the device for the same 8 transform slots
2786
2791
  // throughout the first 4-5 seconds of cold boot. Starting at
2787
- // `configureServer` time gives populate the full app build/launch
2788
- // window (typically 2-3s on simulator) as a head start, so more
2789
- // of its work lands before the device even connects. Disable via
2790
- // NS_VITE_HMR_DISABLE_POPULATE=1 when profiling whether populate
2791
- // is helping or hurting a specific app. See
2792
- // HMR_CORE_REALM_DETERMINISTIC_PLAN.md ("Track 1 + 2 — round
2793
- // three").
2792
+ // `configureServer` time gives populate the full app
2793
+ // build/launch window (typically 2-3s on simulator) as a head
2794
+ // start, so more of its work lands before the device even
2795
+ // connects. Disable via `NS_VITE_HMR_DISABLE_POPULATE=1` when
2796
+ // profiling whether populate is helping or hurting a specific
2797
+ // app.
2794
2798
  try {
2795
2799
  const disablePopulate = process.env.NS_VITE_HMR_DISABLE_POPULATE === '1' || process.env.NS_VITE_HMR_DISABLE_POPULATE === 'true';
2796
2800
  if (disablePopulate) {
@@ -3084,12 +3088,12 @@ function createHmrWebSocketPlugin(opts) {
3084
3088
  // That gave deterministic URL tags but blocked the cold boot on a
3085
3089
  // full src/ tree walk (hundreds of transformRequest calls, 3-6s).
3086
3090
  //
3087
- // Track 1.3: graphVersion now starts at 1 and stays stable during
3088
- // cold boot (see `upsertGraphModule`'s bumpVersion option and the
3089
- // inline comment at the graphVersion declaration). We kick off the
3090
- // initial population in the background so it doesn't block the first
3091
- // response. `handleHotUpdate` awaits the same promise so the first
3092
- // HMR event still sees a fully populated graph.
3091
+ // graphVersion now starts at 1 and stays stable during cold boot
3092
+ // (see `upsertGraphModule`'s bumpVersion option and the inline
3093
+ // comment at the graphVersion declaration). We kick off the
3094
+ // initial population in the background so it doesn't block the
3095
+ // first response. `handleHotUpdate` awaits the same promise so
3096
+ // the first HMR event still sees a fully populated graph.
3093
3097
  ensureInitialGraphPopulationStarted(server);
3094
3098
  // Cold-boot counter is now hooked via the leading boot-trace
3095
3099
  // middleware (see `configureServer` — it records the request
@@ -3307,7 +3311,9 @@ function createHmrWebSocketPlugin(opts) {
3307
3311
  if (transformed?.code && ACTIVE_STRATEGY?.flavor === 'solid' && (resolvedCandidate || spec || '').includes('@solid-refresh')) {
3308
3312
  const PATCH_SENTINEL = '/* __ns_solid_refresh_patched__ */';
3309
3313
  const alreadyPatched = transformed.code.includes(PATCH_SENTINEL);
3310
- console.log('[hmr-ws][solid] @solid-refresh patch check:', { spec: resolvedCandidate || spec, alreadyPatched, codeLen: transformed.code.length });
3314
+ if (verbose) {
3315
+ console.log('[hmr-ws][solid] @solid-refresh patch check:', { spec: resolvedCandidate || spec, alreadyPatched, codeLen: transformed.code.length });
3316
+ }
3311
3317
  if (!alreadyPatched) {
3312
3318
  let patchedCode = transformed.code;
3313
3319
  // Patch 1: Bypass shouldWarnAndDecline() — the vendor-bundled solid-js
@@ -3316,7 +3322,9 @@ function createHmrWebSocketPlugin(opts) {
3316
3322
  const declineCheck = 'function shouldWarnAndDecline() {';
3317
3323
  if (patchedCode.includes(declineCheck)) {
3318
3324
  patchedCode = patchedCode.replace(declineCheck, `${PATCH_SENTINEL}\nfunction shouldWarnAndDecline() { return false; /* NS HMR: always allow refresh */ }\nfunction __original_shouldWarnAndDecline() {`);
3319
- console.log('[hmr-ws][solid] bypassed shouldWarnAndDecline() for NativeScript HMR');
3325
+ if (verbose) {
3326
+ console.log('[hmr-ws][solid] bypassed shouldWarnAndDecline() for NativeScript HMR');
3327
+ }
3320
3328
  }
3321
3329
  // Patch 2: Force createMemo path in createProxy.
3322
3330
  // Without the 'development' condition, $DEVCOMP is not set on components,
@@ -3327,10 +3335,17 @@ function createHmrWebSocketPlugin(opts) {
3327
3335
  const proxyCondition = 'if (!s || $DEVCOMP in s) {';
3328
3336
  if (patchedCode.includes(proxyCondition)) {
3329
3337
  patchedCode = patchedCode.replace(proxyCondition, 'if (true) { /* NS HMR: always use createMemo for reactive HMR updates */');
3330
- console.log('[hmr-ws][solid] forced createMemo path in createProxy for NativeScript HMR');
3338
+ if (verbose) {
3339
+ console.log('[hmr-ws][solid] forced createMemo path in createProxy for NativeScript HMR');
3340
+ }
3331
3341
  }
3332
3342
  // Patch 3: Inline patchRegistry call so updates apply immediately
3333
3343
  // on module re-evaluation (accept callbacks are not invoked by the HMR client).
3344
+ // The injected `console.log` helpers run inside the user's runtime
3345
+ // when @solid-refresh re-evaluates a module, so they are a runtime
3346
+ // concern (stripped if the user disables the patch). Keeping them
3347
+ // behind the patch sentinel rather than the dev-server `verbose`
3348
+ // flag is intentional — the patch only runs when Solid HMR fires.
3334
3349
  const marker = 'hot.data[SOLID_REFRESH] = hot.data[SOLID_REFRESH] || registry;';
3335
3350
  if (patchedCode.includes(marker)) {
3336
3351
  const patchCode = [
@@ -3344,7 +3359,9 @@ function createHmrWebSocketPlugin(opts) {
3344
3359
  `}`,
3345
3360
  ].join('\n ');
3346
3361
  patchedCode = patchedCode.replace(marker, `${patchCode}\n ${marker}`);
3347
- console.log('[hmr-ws][solid] added inline patchRegistry for NativeScript HMR');
3362
+ if (verbose) {
3363
+ console.log('[hmr-ws][solid] added inline patchRegistry for NativeScript HMR');
3364
+ }
3348
3365
  }
3349
3366
  // Work on a copy to avoid mutating Vite's cached TransformResult
3350
3367
  transformed = { ...transformed, code: patchedCode };
@@ -3375,7 +3392,7 @@ function createHmrWebSocketPlugin(opts) {
3375
3392
  catch { }
3376
3393
  }
3377
3394
  // Serve-time warm-up: no live edit happened, so don't bump
3378
- // graphVersion. See Track 1.3 in HMR_CORE_REALM_DETERMINISTIC_PLAN.md.
3395
+ // graphVersion.
3379
3396
  upsertGraphModule(id, code, deps, { bumpVersion: false });
3380
3397
  }
3381
3398
  }
@@ -3599,19 +3616,20 @@ export const piniaSymbol = p.piniaSymbol;
3599
3616
  }
3600
3617
  }
3601
3618
  catch { }
3602
- // alpha.59 — `/ns/rt` and `/ns/core` URL versioning.
3619
+ // `/ns/rt` and `/ns/core` URL versioning.
3603
3620
  //
3604
- // Pre-alpha.59 these URLs were emitted as `/ns/rt/<ver>`
3605
- // and `/ns/core/<ver>` so V8's HTTP module cache would see
3606
- // a fresh URL on every save. The runtime canonicalizer
3607
- // (HMRSupport.mm `CanonicalizeHttpUrlKey`) collapses these
3608
- // version segments to the bare `/ns/rt` and `/ns/core`
3609
- // keys before lookup, so V8 actually saw a single cache
3610
- // entry — but the server was doing extra work to inject a
3611
- // version segment that the runtime then immediately
3612
- // stripped. Now that alpha.59 has explicit eviction (and
3613
- // these bridge endpoints don't change at HMR time
3614
- // anyway), the version segment is purely vestigial.
3621
+ // Older versions of the server emitted `/ns/rt/<ver>` and
3622
+ // `/ns/core/<ver>` so V8's HTTP module cache would see a
3623
+ // fresh URL on every save. The runtime canonicalizer
3624
+ // (`CanonicalizeHttpUrlKey` in HMRSupport.mm) collapses
3625
+ // these version segments to the bare `/ns/rt` and
3626
+ // `/ns/core` keys before lookup, so V8 actually saw a
3627
+ // single cache entry — but the server was doing extra
3628
+ // work to inject a version segment that the runtime then
3629
+ // immediately stripped. Now that the runtime supports
3630
+ // explicit eviction (and these bridge endpoints don't
3631
+ // change at HMR time anyway), the version segment is
3632
+ // purely vestigial.
3615
3633
  //
3616
3634
  // Rather than rip the helpers out (which would touch
3617
3635
  // every ensureVersionedImports caller and risk bumping
@@ -3627,25 +3645,25 @@ export const piniaSymbol = p.piniaSymbol;
3627
3645
  code = ensureVersionedCoreImports(code, getServerOrigin(server), verNum);
3628
3646
  }
3629
3647
  catch { }
3630
- // alpha.59 — `/ns/m` URL finalize step.
3648
+ // `/ns/m` URL finalize step.
3631
3649
  //
3632
- // `rewriteNsMImportPathForHmr` (Phase 3a) is now a
3633
- // canonicalizer: it strips legacy `__ns_hmr__/<tag>/`
3634
- // segments and adds `__ns_boot__/b1/` only for boot-tagged
3635
- // requests. The `ver` parameter is preserved on the
3636
- // signature for API compatibility but is ignored for app
3637
- // modules (cache busting is driven by
3638
- // `__nsInvalidateModules`, not URL versioning). We pass
3639
- // `'v0'` as a stable placeholder the canonicalizer
3640
- // emits the same URL regardless of this value, but a
3641
- // constant placeholder makes the contract explicit.
3650
+ // `rewriteNsMImportPathForHmr` is a canonicalizer: it
3651
+ // strips legacy `__ns_hmr__/<tag>/` segments and adds
3652
+ // `__ns_boot__/b1/` only for boot-tagged requests. The
3653
+ // `ver` parameter is preserved on the signature for API
3654
+ // compatibility but is ignored for app modules (cache
3655
+ // busting is driven by `__nsInvalidateModules`, not URL
3656
+ // versioning). We pass `'v0'` as a stable placeholder —
3657
+ // the canonicalizer emits the same URL regardless of
3658
+ // this value, but a constant placeholder makes the
3659
+ // contract explicit.
3642
3660
  //
3643
3661
  // SFC URLs (line below, `/ns/sfc/${verTag}/...`) still
3644
3662
  // embed a version because the Vue SFC pathway does not
3645
- // yet have an eviction protocol. The runtime canonicalizer
3646
- // does NOT strip `/ns/sfc/<ver>/`, so Vue users still see
3647
- // per-save SFC re-fetches — that's a known follow-up
3648
- // (HMR_STABLE_URL_INVALIDATION_PLAN.md "Vue Follow-up").
3663
+ // yet have an eviction protocol. The runtime
3664
+ // canonicalizer does NOT strip `/ns/sfc/<ver>/`, so Vue
3665
+ // users still see per-save SFC re-fetches — that's a
3666
+ // known follow-up.
3649
3667
  try {
3650
3668
  const verTag = (() => {
3651
3669
  const numeric = getNumericServeVersionTag(forcedVer, Number(graphVersion || 0));
@@ -3789,10 +3807,12 @@ export const piniaSymbol = p.piniaSymbol;
3789
3807
  // by the serving pipeline. Only warn, don't fatally block the importer.
3790
3808
  const hasCjsPattern = /\bmodule\s*\.\s*exports\b/.test(targetCode) || /\bexports\s*\.\s*\w/.test(targetCode);
3791
3809
  if (hasCjsPattern) {
3792
- try {
3793
- console.warn(`[ns:m][link-check] CJS module without export default: ${u.pathname} (will be CJS-wrapped at serve time)`);
3810
+ if (verbose) {
3811
+ try {
3812
+ console.warn(`[ns:m][link-check] CJS module without export default: ${u.pathname} (will be CJS-wrapped at serve time)`);
3813
+ }
3814
+ catch { }
3794
3815
  }
3795
- catch { }
3796
3816
  continue;
3797
3817
  }
3798
3818
  const msg = `[link-check] Missing default export in ${u.pathname}${u.search} (imported by ${resolvedCandidate || spec})`;
@@ -3806,10 +3826,12 @@ export const piniaSymbol = p.piniaSymbol;
3806
3826
  }
3807
3827
  }
3808
3828
  catch (eLC) {
3809
- try {
3810
- console.warn('[ns:m][link-check] failed', eLC?.message || eLC);
3829
+ if (verbose) {
3830
+ try {
3831
+ console.warn('[ns:m][link-check] failed', eLC?.message || eLC);
3832
+ }
3833
+ catch { }
3811
3834
  }
3812
- catch { }
3813
3835
  }
3814
3836
  res.statusCode = 200;
3815
3837
  res.end(code);
@@ -3851,8 +3873,10 @@ export const piniaSymbol = p.piniaSymbol;
3851
3873
  `let __cached_rt = null;\n` +
3852
3874
  `let __cached_vm = null;\n` +
3853
3875
  `const __RT_REALM_TAG = (globalThis.__NS_RT_REALM__ ||= Math.random().toString(36).slice(2));\n` +
3854
- // Unconditional one-shot evaluation marker to confirm bridge is executed on device
3855
- `try { if (!(globalThis.__NS_RT_ONCE__ && globalThis.__NS_RT_ONCE__.eval)) { (globalThis.__NS_RT_ONCE__ ||= {}).eval = true; console.log('[ns-rt] evaluated', { rtRealm: __RT_REALM_TAG }); } } catch {}\n` +
3876
+ // One-shot evaluation marker to confirm the bridge is executed on
3877
+ // device. Gated on __NS_ENV_VERBOSE__ so it stays silent unless
3878
+ // the developer opts in via NS_VITE_VERBOSE / VITE_DEBUG_LOGS.
3879
+ `try { if (!(globalThis.__NS_RT_ONCE__ && globalThis.__NS_RT_ONCE__.eval)) { (globalThis.__NS_RT_ONCE__ ||= {}).eval = true; if (globalThis.__NS_ENV_VERBOSE__) console.log('[ns-rt] evaluated', { rtRealm: __RT_REALM_TAG }); } } catch {}\n` +
3856
3880
  `function __ensure(){\n` +
3857
3881
  ` if (__cached_rt) return __cached_rt;\n` +
3858
3882
  ` let vm = null;\n` +
@@ -4032,15 +4056,15 @@ export const piniaSymbol = p.piniaSymbol;
4032
4056
  });
4033
4057
  // 2.6) ESM bridge for @nativescript/core: GET /ns/core[/<ver>][?p=sub/path]
4034
4058
  //
4035
- // Since bundle.mjs no longer bundles @nativescript/core (see
4036
- // HMR_CORE_REALM_DETERMINISTIC_PLAN.md external in the rolldown
4037
- // config under HMR), this endpoint is the ONE place core is
4038
- // evaluated. Every consumer — bundle.mjs's own `@nativescript/core*`
4039
- // imports (resolved to full HTTP URLs in the entry virtual module),
4040
- // externalized vendor packages, HTTP-served app modules — all end
4041
- // up here. No more proxy bridge, no enumeration, no namespace
4042
- // detection, no prototype-polluted maps. We just serve Vite's
4043
- // authoritative transformed module content.
4059
+ // Since bundle.mjs no longer bundles @nativescript/core (it is
4060
+ // declared external in the rolldown config under HMR), this
4061
+ // endpoint is the ONE place core is evaluated. Every consumer —
4062
+ // bundle.mjs's own `@nativescript/core*` imports (resolved to
4063
+ // full HTTP URLs in the entry virtual module), externalized
4064
+ // vendor packages, HTTP-served app modules — all end up here.
4065
+ // No more proxy bridge, no enumeration, no namespace detection,
4066
+ // no prototype-polluted maps. We just serve Vite's authoritative
4067
+ // transformed module content.
4044
4068
  //
4045
4069
  // iOS caches by URL path, so each unique URL is evaluated exactly
4046
4070
  // once per app lifetime. Every class identity is shared, every
@@ -4147,16 +4171,15 @@ export const piniaSymbol = p.piniaSymbol;
4147
4171
  `const __TEST__ = false;`,
4148
4172
  ].join('\n');
4149
4173
  // Boot-time instrumentation + module self-registration.
4150
- // See HMR_CORE_REALM_DETERMINISTIC_PLAN.md:
4151
- // - Invariant A (URL canonicalization): the same
4152
- // logical module must always resolve to byte-
4153
- // identical URLs across every emitter. The /ns/core
4154
- // handler records the first URL seen for each
4155
- // canonical sub (or '' for main) in
4156
- // `globalThis.__NS_CORE_FIRST_URL__` and fails hard
4157
- // on mismatch so drift in any emitter surfaces
4174
+ //
4175
+ // - URL canonicalization: the same logical module must
4176
+ // always resolve to byte-identical URLs across every
4177
+ // emitter. The /ns/core handler records the first URL
4178
+ // seen for each canonical sub (or '' for main) in
4179
+ // `globalThis.__NS_CORE_FIRST_URL__` and fails hard on
4180
+ // mismatch so drift in any emitter surfaces
4158
4181
  // immediately, before the realm splits.
4159
- // - Invariant C (boot-order): CommonJS
4182
+ // - CJS/ESM boot order: CommonJS
4160
4183
  // `require('@nativescript/core/...')` calls from
4161
4184
  // vendor install() hooks must resolve to the SAME
4162
4185
  // ESM namespace that ran this side-effect preamble.
@@ -4185,13 +4208,13 @@ export const piniaSymbol = p.piniaSymbol;
4185
4208
  ` const __nsUrl = ${JSON.stringify(canonicalUrl)};`,
4186
4209
  ` __nsSeen.push(__nsUrl);`,
4187
4210
  ` if (typeof __nsFirst[__nsKey] === 'string' && __nsFirst[__nsKey] !== __nsUrl) {`,
4188
- ` throw new Error('[ns-core] URL drift for sub=' + __nsKey + ': first=' + __nsFirst[__nsKey] + ' now=' + __nsUrl + ' (see HMR_CORE_REALM_DETERMINISTIC_PLAN.md Invariant A)');`,
4211
+ ` throw new Error('[ns-core] URL drift for sub=' + __nsKey + ': first=' + __nsFirst[__nsKey] + ' now=' + __nsUrl);`,
4189
4212
  ` }`,
4190
4213
  ` if (!__nsFirst[__nsKey]) __nsFirst[__nsKey] = __nsUrl;`,
4191
4214
  ` globalThis.__NS_CORE_EVAL_COUNT__ = (globalThis.__NS_CORE_EVAL_COUNT__ || 0) + 1;`,
4192
4215
  `} } catch (e) { try { console.warn('[ns-core] instrumentation failed:', (e && e.message) || e); } catch {} }`,
4193
4216
  ].join('\n');
4194
- // Invariant D (CJS/ESM interop shape) — REGISTRATION side.
4217
+ // CJS/ESM interop shape — REGISTRATION side.
4195
4218
  //
4196
4219
  // The actual shape installer runs earlier in the module
4197
4220
  // body (between preamble and selfImport; see
@@ -4207,9 +4230,6 @@ export const piniaSymbol = p.piniaSymbol;
4207
4230
  // registration — the shape function is identity-preserving
4208
4231
  // via WeakMap — gives a stable, shared, CJS-compatible
4209
4232
  // view without copying on every require.
4210
- //
4211
- // See HMR_CORE_REALM_DETERMINISTIC_PLAN.md § "Invariant D"
4212
- // for the full rationale.
4213
4233
  const registrationFooter = [
4214
4234
  `try { if (typeof globalThis !== 'undefined') {`,
4215
4235
  ` const __nsReg = globalThis.__NS_CORE_MODULES__ || (globalThis.__NS_CORE_MODULES__ = Object.create(null));`,
@@ -4321,7 +4341,8 @@ export const piniaSymbol = p.piniaSymbol;
4321
4341
  content = 'export default async function start(){ console.error("[/ns/entry-rt] not found"); }\n';
4322
4342
  }
4323
4343
  }
4324
- console.log('[hmr-http] /ns/entry-rt serving', content.length, 'bytes');
4344
+ if (verbose)
4345
+ console.log('[hmr-http] /ns/entry-rt serving', content.length, 'bytes');
4325
4346
  res.statusCode = 200;
4326
4347
  res.end(content);
4327
4348
  }
@@ -6054,13 +6075,12 @@ export const piniaSymbol = p.piniaSymbol;
6054
6075
  if (isRuntimeGraphExcludedPath(file)) {
6055
6076
  return;
6056
6077
  }
6057
- // Always-on update timing see HMR_CORE_REALM_DETERMINISTIC_PLAN.md
6058
- // ("Track 2 — round one, 2026-04: HMR update metrics"). Captures
6059
- // the four phases (await, framework, broadcast, total) plus
6060
- // invalidated module count and recipient count. Emitted at the
6061
- // end of this function via `emitHmrUpdateSummary()`. Single line,
6062
- // always-on so a 6-second `.ts` save is immediately visible
6063
- // without flipping verbose.
6078
+ // Always-on update timing. Captures the four phases (await,
6079
+ // framework, broadcast, total) plus invalidated module count
6080
+ // and recipient count. Emitted at the end of this function via
6081
+ // `emitHmrUpdateSummary()`. Single line, always-on so a
6082
+ // 6-second `.ts` save is immediately visible without flipping
6083
+ // verbose.
6064
6084
  const updateRoot = server.config.root || process.cwd();
6065
6085
  const updateRel = (() => {
6066
6086
  try {
@@ -6079,21 +6099,19 @@ export const piniaSymbol = p.piniaSymbol;
6079
6099
  tEnd: 0,
6080
6100
  invalidated: 0,
6081
6101
  recipients: 0,
6082
- // Round-eight diagnostic — populated by the angular branch when
6102
+ // Narrowing diagnostic — populated by the angular branch when
6083
6103
  // the changed file is `.ts`, otherwise remains undefined and is
6084
- // omitted from the summary line entirely. See
6085
- // HMR_CORE_REALM_DETERMINISTIC_PLAN.md ("Round-eight — surface
6086
- // narrowing decision").
6104
+ // omitted from the summary line entirely.
6087
6105
  narrowed: undefined,
6088
6106
  emitted: false,
6089
6107
  };
6090
- // alpha.62 follow-up — broadcast a "pending" notification at
6091
- // the very start of handleHotUpdate so the client can show
6092
- // the HMR-applying overlay BEFORE we spend time on graph
6093
- // updates / transforms / dependency analysis (typically
6094
- // 7–200ms on a warm cache). Without this, the overlay only
6095
- // appears at `ns:angular-update` broadcast time and the
6096
- // user perceives a "delayed" reaction to their save.
6108
+ // Broadcast a "pending" notification at the very start of
6109
+ // handleHotUpdate so the client can show the HMR-applying
6110
+ // overlay BEFORE we spend time on graph updates / transforms /
6111
+ // dependency analysis (typically 7–200ms on a warm cache).
6112
+ // Without this, the overlay only appears at `ns:angular-update`
6113
+ // broadcast time and the user perceives a "delayed" reaction
6114
+ // to their save.
6097
6115
  //
6098
6116
  // Fire-and-forget: a failed pending broadcast must never
6099
6117
  // hold up the actual update. The client treats receipt of
@@ -6140,10 +6158,11 @@ export const piniaSymbol = p.piniaSymbol;
6140
6158
  }
6141
6159
  catch { }
6142
6160
  };
6143
- // Track 1.3: the first /ns/m request kicks off populateInitialGraph
6144
- // in the background. If an HMR update races in before that walk
6145
- // completes, we'd lose transitive-importer data. Await completion
6146
- // here so the delta computation below always sees a populated graph.
6161
+ // The first /ns/m request kicks off populateInitialGraph in the
6162
+ // background. If an HMR update races in before that walk
6163
+ // completes, we'd lose transitive-importer data. Await
6164
+ // completion here so the delta computation below always sees a
6165
+ // populated graph.
6147
6166
  if (graphInitialPopulationPromise) {
6148
6167
  try {
6149
6168
  await graphInitialPopulationPromise;
@@ -6259,13 +6278,13 @@ export const piniaSymbol = p.piniaSymbol;
6259
6278
  }
6260
6279
  }
6261
6280
  const angularTransitiveInvalidationRoots = (angularHotUpdateRoots.length ? angularHotUpdateRoots : ctx.modules);
6262
- // Round-six narrowing: read the source for `.ts/.tsx/.js/.jsx`
6263
- // edits so `shouldInvalidateAngularTransitiveImporters` can
6281
+ // Read the source for `.ts/.tsx/.js/.jsx` edits so
6282
+ // `shouldInvalidateAngularTransitiveImporters` can
6264
6283
  // distinguish leaf modules (constants/utils) from real
6265
6284
  // Angular files. If `ctx.read()` throws (file deleted, race
6266
6285
  // against the watcher), `angularChangedSource` stays
6267
- // undefined and we fall back to the conservative
6268
- // pre-round-six "always invalidate transitively" behavior.
6286
+ // undefined and we fall back to the conservative "always
6287
+ // invalidate transitively" behavior.
6269
6288
  let angularChangedSource;
6270
6289
  if (isTs) {
6271
6290
  try {
@@ -6280,37 +6299,36 @@ export const piniaSymbol = p.piniaSymbol;
6280
6299
  file,
6281
6300
  source: angularChangedSource,
6282
6301
  });
6283
- // Round-eight diagnostic. We surface the narrowing decision on
6284
- // every `.ts` Angular hot update (HTML routes always invalidate
6285
- // transitively today and aren't subject to Round-Seven, so we
6286
- // leave them as `undefined` — the field is omitted from the
6287
- // summary line). The boolean is the inverse of
6288
- // `angularNeedsTransitive` because "needs transitive" is the
6289
- // pre-Round-Seven (broad) behavior.
6302
+ // Surface the narrowing decision on every `.ts` Angular hot
6303
+ // update (HTML routes always invalidate transitively and
6304
+ // aren't subject to narrowing, so we leave them as
6305
+ // `undefined` — the field is omitted from the summary line).
6306
+ // The boolean is the inverse of `angularNeedsTransitive`
6307
+ // because "needs transitive" is the broad (un-narrowed)
6308
+ // behavior.
6290
6309
  if (isTs) {
6291
6310
  updateMetrics.narrowed = !angularNeedsTransitive;
6292
6311
  }
6293
- // alpha.59 — Stable URL + Explicit Invalidation:
6312
+ // Stable URL + Explicit Invalidation:
6294
6313
  //
6295
- // Compute the transitive importer closure ONCE here and reuse it
6296
- // for (a) `server.moduleGraph.invalidateModule` (so Vite's
6314
+ // Compute the transitive importer closure ONCE here and reuse
6315
+ // it for (a) `server.moduleGraph.invalidateModule` (so Vite's
6297
6316
  // transform pipeline re-runs on next request), (b) the shared
6298
- // transform-request cache, and (c) the runtime eviction set we
6299
- // broadcast in `ns:angular-update`. Pre-alpha.59 code computed
6300
- // this list twice in adjacent try blocks; consolidating it
6317
+ // transform-request cache, and (c) the runtime eviction set
6318
+ // we broadcast in `ns:angular-update`. Consolidating this
6301
6319
  // removes a redundant graph walk and guarantees the three
6302
6320
  // consumers see the exact same set of importers (otherwise a
6303
6321
  // late module-graph mutation between calls could leave an
6304
6322
  // asymmetric narrowed/broad mix).
6305
6323
  //
6306
- // alpha.59.1 separate Vite-transform narrowing from runtime
6307
- // eviction. `angularNeedsTransitive` answers the question "does
6308
- // the changed file's symbol shape change such that importers
6309
- // must be re-transformed by Vite?". The runtime, however, has
6310
- // a stricter requirement: ESM live bindings only refresh if
6311
- // the importing module re-evaluates inside V8. A constants
6312
- // file with no Angular decorator does NOT need a Vite
6313
- // re-transform of its importers (their compiled JS is
6324
+ // We separate Vite-transform narrowing from runtime eviction:
6325
+ // `angularNeedsTransitive` answers the question "does the
6326
+ // changed file's symbol shape change such that importers
6327
+ // must be re-transformed by Vite?". The runtime, however,
6328
+ // has a stricter requirement: ESM live bindings only refresh
6329
+ // if the importing module re-evaluates inside V8. A
6330
+ // constants file with no Angular decorator does NOT need a
6331
+ // Vite re-transform of its importers (their compiled JS is
6314
6332
  // identical), but its importers still hold stale bindings to
6315
6333
  // the OLD constants Module record. After eviction + re-import
6316
6334
  // of `main.ts`, V8 sees the cached importers, returns them
@@ -6318,12 +6336,13 @@ export const piniaSymbol = p.piniaSymbol;
6318
6336
  // user-visible symptom: HMR completes successfully, logs are
6319
6337
  // clean, but the simulator does not reflect the change.
6320
6338
  //
6321
- // The fix: ALWAYS compute the transitive importer closure for
6322
- // runtime eviction. Only skip Vite's `moduleGraph.invalidate`
6323
- // + transform-cache purge when `angularNeedsTransitive` is
6324
- // false — those are the genuine narrowing wins (saves
6325
- // re-transform work on the server). The eviction set always
6326
- // includes importers so V8 re-fetches and re-binds them.
6339
+ // The fix: ALWAYS compute the transitive importer closure
6340
+ // for runtime eviction. Only skip Vite's
6341
+ // `moduleGraph.invalidate` + transform-cache purge when
6342
+ // `angularNeedsTransitive` is false — those are the genuine
6343
+ // narrowing wins (saves re-transform work on the server).
6344
+ // The eviction set always includes importers so V8 re-fetches
6345
+ // and re-binds them.
6327
6346
  let transitiveImporters = [];
6328
6347
  try {
6329
6348
  transitiveImporters = collectAngularTransitiveImportersForInvalidation({
@@ -6348,19 +6367,18 @@ export const piniaSymbol = p.piniaSymbol;
6348
6367
  }
6349
6368
  }
6350
6369
  else if (isTs && typeof angularChangedSource === 'string') {
6351
- // Round-eight: was previously gated on `verbose`. Surfacing this
6352
- // log unconditionally lets the user immediately confirm whether
6353
- // Round-Seven's narrowing fired for a given `.ts` edit (the
6354
- // summary line below still emits `narrowed=yes`/`no`, but
6355
- // having both makes the decision easier to spot in noisy logs
6356
- // and lets the user diff scenarios without flipping
6370
+ // Surfacing this log unconditionally lets the user
6371
+ // immediately confirm whether narrowing fired for a
6372
+ // given `.ts` edit (the summary line below still
6373
+ // emits `narrowed=yes`/`no`, but having both makes
6374
+ // the decision easier to spot in noisy logs and lets
6375
+ // the user diff scenarios without flipping
6357
6376
  // `NS_HMR_VERBOSE=true`).
6358
6377
  //
6359
- // alpha.59.1 — narrowing now means "skip Vite re-transform"
6360
- // (the importers still get evicted from the V8 module
6361
- // registry so live bindings refresh). The log call-out is
6362
- // preserved but extended with the importer count to make the
6363
- // distinction visible.
6378
+ // Narrowing means "skip Vite re-transform" (the
6379
+ // importers still get evicted from the V8 module
6380
+ // registry so live bindings refresh). The importer
6381
+ // count is appended so the distinction is visible.
6364
6382
  console.log(`[hmr-ws][angular] narrowed transitive invalidation (no @Component/@Directive/@Pipe/@Injectable/@NgModule): ${updateRel} — Vite transform skipped, runtime eviction includes ${transitiveImporters.length} importer(s)`);
6365
6383
  }
6366
6384
  }
@@ -6369,13 +6387,13 @@ export const piniaSymbol = p.piniaSymbol;
6369
6387
  console.warn('[hmr-ws][angular] transitive importer collection failed', error);
6370
6388
  }
6371
6389
  try {
6372
- // alpha.59.1 — purge shared transform cache for the changed
6373
- // file + hot-update roots unconditionally (their transform
6374
- // output IS different now). Transitive importers are only
6375
- // purged when narrowing decides their output may have
6376
- // changed; otherwise their cached transforms are still
6377
- // valid (compiled JS is identical even though the runtime
6378
- // must re-evaluate them to refresh ESM bindings).
6390
+ // Purge shared transform cache for the changed file +
6391
+ // hot-update roots unconditionally (their transform
6392
+ // output IS different now). Transitive importers are
6393
+ // only purged when narrowing decides their output may
6394
+ // have changed; otherwise their cached transforms are
6395
+ // still valid (compiled JS is identical even though the
6396
+ // runtime must re-evaluate them to refresh ESM bindings).
6379
6397
  const transformCacheInvalidationUrls = new Set(collectAngularTransformCacheInvalidationUrls({
6380
6398
  file,
6381
6399
  isTs,
@@ -6401,19 +6419,19 @@ export const piniaSymbol = p.piniaSymbol;
6401
6419
  rememberAngularReloadSuppression(root, file);
6402
6420
  const origin = getServerOrigin(server);
6403
6421
  const bootstrapEntryRel = getBootstrapEntryRelPath();
6404
- // alpha.59 — Stable URL + Explicit Invalidation:
6422
+ // Stable URL + Explicit Invalidation:
6405
6423
  //
6406
6424
  // `evictPaths` is the canonical list of `/ns/m/<rel>` URLs
6407
6425
  // the runtime must drop from `g_moduleRegistry` before
6408
- // re-importing `importerEntry`. Pre-alpha.59 the server
6409
- // signaled invalidation by bumping a global `graphVersion`
6410
- // counter and embedding it in every URL — but V8 keys the
6411
- // module registry by full URL, so a v1 → v2 bump
6412
- // effectively flushed the entire dependency graph from
6413
- // the cache and forced the runtime to re-fetch + re-eval
6414
- // every transitively-imported module on each save (~3s
6415
- // HMR cycles, dominated by Vite's single-threaded transform
6416
- // pipeline). The new model:
6426
+ // re-importing `importerEntry`. Older versions of the
6427
+ // server signaled invalidation by bumping a global
6428
+ // `graphVersion` counter and embedding it in every URL —
6429
+ // but V8 keys the module registry by full URL, so a v1 →
6430
+ // v2 bump effectively flushed the entire dependency
6431
+ // graph from the cache and forced the runtime to
6432
+ // re-fetch + re-eval every transitively-imported module
6433
+ // on each save (~3s HMR cycles, dominated by Vite's
6434
+ // single-threaded transform pipeline). The new model:
6417
6435
  //
6418
6436
  // 1. URLs are stable: `/ns/m/<rel>` everywhere, no `vN`.
6419
6437
  // 2. The server walks the inverse-dependency closure and
@@ -6550,7 +6568,8 @@ export const piniaSymbol = p.piniaSymbol;
6550
6568
  console.log('[hmr-ws] Not a .vue file, skipping');
6551
6569
  return;
6552
6570
  }
6553
- console.log('[hmr-ws] Processing .vue file update...');
6571
+ if (verbose)
6572
+ console.log('[hmr-ws] Processing .vue file update...');
6554
6573
  try {
6555
6574
  const root = server.config.root || process.cwd();
6556
6575
  let rel = '/' + path.posix.normalize(path.relative(root, file)).split(path.sep).join('/');