@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.
- package/configuration/base.js +8 -8
- package/configuration/base.js.map +1 -1
- package/helpers/global-defines.d.ts +7 -13
- package/helpers/global-defines.js +10 -16
- package/helpers/global-defines.js.map +1 -1
- package/helpers/main-entry.js +5 -6
- package/helpers/main-entry.js.map +1 -1
- package/helpers/ns-core-url.d.ts +5 -6
- package/helpers/ns-core-url.js +5 -6
- package/helpers/ns-core-url.js.map +1 -1
- package/hmr/client/css-handler.js +2 -1
- package/hmr/client/css-handler.js.map +1 -1
- package/hmr/client/hmr-pending-overlay.d.ts +1 -1
- package/hmr/client/hmr-pending-overlay.js +1 -1
- package/hmr/client/index.js +27 -26
- package/hmr/client/index.js.map +1 -1
- package/hmr/client/utils.js +27 -25
- package/hmr/client/utils.js.map +1 -1
- package/hmr/frameworks/angular/client/index.js +78 -86
- package/hmr/frameworks/angular/client/index.js.map +1 -1
- package/hmr/server/core-sanitize.js +8 -8
- package/hmr/server/core-sanitize.js.map +1 -1
- package/hmr/server/import-map.js +3 -4
- package/hmr/server/import-map.js.map +1 -1
- package/hmr/server/ns-core-cjs-shape.d.ts +2 -4
- package/hmr/server/ns-core-cjs-shape.js +3 -5
- package/hmr/server/ns-core-cjs-shape.js.map +1 -1
- package/hmr/server/perf-instrumentation.d.ts +5 -9
- package/hmr/server/perf-instrumentation.js +2 -5
- package/hmr/server/perf-instrumentation.js.map +1 -1
- package/hmr/server/vite-plugin.js +3 -1
- package/hmr/server/vite-plugin.js.map +1 -1
- package/hmr/server/websocket-angular-hot-update.js +27 -29
- package/hmr/server/websocket-angular-hot-update.js.map +1 -1
- package/hmr/server/websocket-core-bridge.js +11 -16
- package/hmr/server/websocket-core-bridge.js.map +1 -1
- package/hmr/server/websocket-hmr-pending.d.ts +1 -1
- package/hmr/server/websocket-hmr-pending.js +1 -1
- package/hmr/server/websocket-ns-m-paths.js +14 -15
- package/hmr/server/websocket-ns-m-paths.js.map +1 -1
- package/hmr/server/websocket-runtime-compat.js +3 -2
- package/hmr/server/websocket-runtime-compat.js.map +1 -1
- package/hmr/server/websocket-served-module-helpers.js +13 -12
- package/hmr/server/websocket-served-module-helpers.js.map +1 -1
- package/hmr/server/websocket.js +238 -219
- package/hmr/server/websocket.js.map +1 -1
- package/hmr/shared/runtime/boot-timeline.js +0 -3
- package/hmr/shared/runtime/boot-timeline.js.map +1 -1
- package/hmr/shared/runtime/dev-overlay.js +31 -33
- package/hmr/shared/runtime/dev-overlay.js.map +1 -1
- package/hmr/shared/runtime/session-bootstrap.js +12 -9
- package/hmr/shared/runtime/session-bootstrap.js.map +1 -1
- package/package.json +1 -1
package/hmr/server/websocket.js
CHANGED
|
@@ -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
|
|
86
|
-
// the cold-boot wrapper performs (`getPackageJson().main` →
|
|
87
|
-
// project-relative under `/<APP_ROOT_DIR>/`) so the eviction set for
|
|
88
|
-
// always lines up with the URL the runtime actually re-imports.
|
|
89
|
-
// at first call and cached: `package.json` is read at startup
|
|
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
|
-
//
|
|
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
|
|
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
|
-
//
|
|
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
|
|
921
|
-
//
|
|
922
|
-
//
|
|
923
|
-
//
|
|
924
|
-
//
|
|
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
|
|
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
|
|
2611
|
-
//
|
|
2612
|
-
//
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
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
|
|
2673
|
-
//
|
|
2674
|
-
//
|
|
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
|
|
2678
|
-
// unchanged neighbours of an edited file don't re-run
|
|
2679
|
-
// Angular/TypeScript/Vite transform pipeline. The
|
|
2680
|
-
// explicitly invalidates affected URLs, so a longer TTL
|
|
2681
|
-
//
|
|
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
|
|
2695
|
-
// anyone investigating perf can immediately see which build
|
|
2696
|
-
// and what knobs are active.
|
|
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
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
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
|
|
2730
|
-
// middleware so it catches all NS dev routes (/ns/m/*,
|
|
2731
|
-
// /ns/core/*, /__ns_boot__/*, etc.) with a single
|
|
2732
|
-
// itself after an idle window so HMR edits don't
|
|
2733
|
-
// the cold-boot numbers. The idle window is
|
|
2734
|
-
// (5s) because V8's HTTP ESM resolver
|
|
2735
|
-
// while parsing — a too-tight window
|
|
2736
|
-
// wave and under-reporting boot by
|
|
2737
|
-
//
|
|
2738
|
-
//
|
|
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
|
|
2788
|
-
// window (typically 2-3s on simulator) as a head
|
|
2789
|
-
// of its work lands before the device even
|
|
2790
|
-
// NS_VITE_HMR_DISABLE_POPULATE=1 when
|
|
2791
|
-
// is helping or hurting a specific
|
|
2792
|
-
//
|
|
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
|
-
//
|
|
3088
|
-
//
|
|
3089
|
-
//
|
|
3090
|
-
// initial population in the background so it doesn't block the
|
|
3091
|
-
// response. `handleHotUpdate` awaits the same promise so
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
-
//
|
|
3619
|
+
// `/ns/rt` and `/ns/core` URL versioning.
|
|
3603
3620
|
//
|
|
3604
|
-
//
|
|
3605
|
-
//
|
|
3606
|
-
//
|
|
3607
|
-
// (HMRSupport.mm
|
|
3608
|
-
// version segments to the bare `/ns/rt` and
|
|
3609
|
-
// keys before lookup, so V8 actually saw a
|
|
3610
|
-
// entry — but the server was doing extra
|
|
3611
|
-
// version segment that the runtime then
|
|
3612
|
-
// stripped. Now that
|
|
3613
|
-
// these bridge endpoints don't
|
|
3614
|
-
// anyway), the version segment is
|
|
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
|
-
//
|
|
3648
|
+
// `/ns/m` URL finalize step.
|
|
3631
3649
|
//
|
|
3632
|
-
// `rewriteNsMImportPathForHmr`
|
|
3633
|
-
//
|
|
3634
|
-
//
|
|
3635
|
-
//
|
|
3636
|
-
//
|
|
3637
|
-
//
|
|
3638
|
-
//
|
|
3639
|
-
//
|
|
3640
|
-
//
|
|
3641
|
-
//
|
|
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
|
|
3646
|
-
// does NOT strip `/ns/sfc/<ver>/`, so Vue
|
|
3647
|
-
// per-save SFC re-fetches — that's a
|
|
3648
|
-
//
|
|
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
|
-
|
|
3793
|
-
|
|
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
|
-
|
|
3810
|
-
|
|
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
|
-
//
|
|
3855
|
-
|
|
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 (
|
|
4036
|
-
//
|
|
4037
|
-
//
|
|
4038
|
-
//
|
|
4039
|
-
//
|
|
4040
|
-
//
|
|
4041
|
-
//
|
|
4042
|
-
//
|
|
4043
|
-
//
|
|
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
|
-
//
|
|
4151
|
-
// -
|
|
4152
|
-
//
|
|
4153
|
-
//
|
|
4154
|
-
//
|
|
4155
|
-
//
|
|
4156
|
-
//
|
|
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
|
-
// -
|
|
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
|
|
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
|
-
//
|
|
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
|
-
|
|
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
|
|
6058
|
-
//
|
|
6059
|
-
//
|
|
6060
|
-
//
|
|
6061
|
-
//
|
|
6062
|
-
//
|
|
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
|
-
//
|
|
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.
|
|
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
|
-
//
|
|
6091
|
-
//
|
|
6092
|
-
//
|
|
6093
|
-
//
|
|
6094
|
-
//
|
|
6095
|
-
//
|
|
6096
|
-
//
|
|
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
|
-
//
|
|
6144
|
-
//
|
|
6145
|
-
// completes, we'd lose transitive-importer data. Await
|
|
6146
|
-
// here so the delta computation below always sees a
|
|
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
|
-
//
|
|
6263
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
6284
|
-
//
|
|
6285
|
-
//
|
|
6286
|
-
//
|
|
6287
|
-
//
|
|
6288
|
-
//
|
|
6289
|
-
//
|
|
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
|
-
//
|
|
6312
|
+
// Stable URL + Explicit Invalidation:
|
|
6294
6313
|
//
|
|
6295
|
-
// Compute the transitive importer closure ONCE here and reuse
|
|
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
|
|
6299
|
-
// broadcast in `ns:angular-update`.
|
|
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
|
-
//
|
|
6307
|
-
//
|
|
6308
|
-
//
|
|
6309
|
-
// must be re-transformed by Vite?". The runtime, however,
|
|
6310
|
-
// a stricter requirement: ESM live bindings only refresh
|
|
6311
|
-
// the importing module re-evaluates inside V8. A
|
|
6312
|
-
// file with no Angular decorator does NOT need a
|
|
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
|
|
6322
|
-
// runtime eviction. Only skip Vite's
|
|
6323
|
-
// + transform-cache purge when
|
|
6324
|
-
// false — those are the genuine
|
|
6325
|
-
// re-transform work on the server).
|
|
6326
|
-
// includes importers so V8 re-fetches
|
|
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
|
-
//
|
|
6352
|
-
//
|
|
6353
|
-
//
|
|
6354
|
-
//
|
|
6355
|
-
//
|
|
6356
|
-
//
|
|
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
|
-
//
|
|
6360
|
-
//
|
|
6361
|
-
// registry so live bindings refresh). The
|
|
6362
|
-
//
|
|
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
|
-
//
|
|
6373
|
-
//
|
|
6374
|
-
// output IS different now). Transitive importers are
|
|
6375
|
-
// purged when narrowing decides their output may
|
|
6376
|
-
// changed; otherwise their cached transforms are
|
|
6377
|
-
// valid (compiled JS is identical even though the
|
|
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
|
-
//
|
|
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`.
|
|
6409
|
-
// signaled invalidation by bumping a global
|
|
6410
|
-
// counter and embedding it in every URL —
|
|
6411
|
-
// module registry by full URL, so a v1 →
|
|
6412
|
-
// effectively flushed the entire dependency
|
|
6413
|
-
// the cache and forced the runtime to
|
|
6414
|
-
// every transitively-imported module
|
|
6415
|
-
// HMR cycles, dominated by Vite's
|
|
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
|
-
|
|
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('/');
|