mirror of
https://github.com/cloudflare/vinext.git
synced 2026-09-14 19:04:59 +08:00
28980b01f1
* fix: prevent URL/content mismatch on rapid Pages Router navigation Replace the boolean `_navInProgress` guard in navigateClient() with a monotonically increasing navigation ID + AbortController. The old guard silently dropped the second navigation when two push() calls overlapped, leaving the URL bar showing B while page content showed A. Now each navigateClient() call: - Aborts the previous in-flight fetch via AbortController - Checks after every await whether a newer navigation has superseded it - Throws NavigationCancelledError (with .cancelled = true) when stale Callers (push/replace in both hook and singleton, plus popstate) catch the error and emit routeChangeError for cancelled navigations, matching Next.js behavior. routeChangeComplete only fires for navigations that actually render. Also fixes: failed navigations (non-OK response, missing data) now emit routeChangeError instead of silently emitting routeChangeComplete before the hard redirect. * chore: trigger CI * refactor: clarify routeChangeError/hard-nav contract and simplify catch blocks - Add comment to !res.ok path explaining the window.location.href + throw ordering contract: the assignment schedules navigation as a task, so synchronous routeChangeError listeners observe the error before unload. Document the contract requirement: listeners MUST be synchronous. - Simplify all 4 push/replace catch blocks: extract routerEvents.emit() before the instanceof check so the emit is unconditional and the if-branch only determines the return value. Add clarifying comment explaining why cancelled navigations return true (superseded, not failed — matches Next.js behaviour). - Simplify popstate .then() rejection handler: remove redundant if/instanceof guard since both paths emitted identical arguments; add comment noting there is no return-value distinction in a void handler. * test: add signal-aware and stale-first navigation cancellation tests Two new tests for the Pages Router concurrent navigation suite: 1. "abort signal fires when navigation is superseded" — uses a signal-aware fetch mock where the first fetch rejects with AbortError when its signal is aborted. Verifies the AbortError → NavigationCancelledError conversion path end-to-end (i.e. the abort signal integration actually works, not just the assertStillCurrent checkpoint). 2. "stale response arriving first" variant — fetchA (stale) resolves before fetchB (winner). Exercises assertStillCurrent() checkpoints when the stale navigation gets further through the pipeline (past the fetch, into HTML parsing) before being cancelled. Verifies stale data never reaches the DOM. * test: remove Router.events listeners in finally blocks Store each Router.events handler in a named variable before the try block and call Router.events.off() in the finally block. Prevents handlers from accumulating on the module-level routerEvents singleton across the 6 concurrent navigation tests. * fix: address review feedback — defer __NEXT_DATA__ write, extract helper, add hard-nav fallback - Defer window.__NEXT_DATA__ assignment until just before root.render() so a stale navigation can never briefly pollute the global between assertStillCurrent() checkpoints. - Extract runNavigateClient() helper to deduplicate the identical 12-line try/catch block across useRouter().push/replace and Router.push/replace. - Add hard-navigation fallback (window.location.href) for non-cancel errors in both the helper and the popstate handler, fixing a regression where unexpected errors (JSON parse, import failure) left URL and content out of sync. - Add test asserting __NEXT_DATA__ is not stale at the moment routeChangeError fires for a cancelled navigation. * fix: avoid duplicate hard navigation fallback * fix: align popstate hard-nav handling * chore: clarify navigation fallback invariants * chore: tighten navigation regression proof
vinext
This file is overwritten from the repo root README.md during prepack. Edit the root README.md instead.