chore: update vite-plus and related packages to 0.1.13-alpha.5#1
chore: update vite-plus and related packages to 0.1.13-alpha.5#1fengmk2 wants to merge 1 commit into
Conversation
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request performs a routine maintenance update, bringing Highlights
🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request updates vite-plus and its related packages to version 0.1.13-alpha.5. The changes include version bumps in pnpm-lock.yaml and pnpm-workspace.yaml, and updates to the AGENTS.md documentation. The documentation changes accurately reflect the new version's features, such as the removal of the vp check command and improved guidance on running scripts and type-aware linting. The changes are consistent and appear correct.
…oudflare#875) * fix(app-router): hard-navigate to browser URL on non-ok RSC fetch Client-side RSC navigation fetch passes non-ok responses (404, 500, etc.) directly to createFromFetch. The HTML error body is parsed as an RSC stream, producing a cryptic "Connection closed" error, and the outer catch hard-navigates to the same URL that just failed — risking a reload loop and surfacing an opaque diagnostic. Non-ok responses are not RSC payloads and must not reach createFromFetch. Next.js handles this identically in fetch-server-response.ts:211 with a hard ("MPA") navigation to the browser-facing URL stripped of flight markers. Add a !navResponse.ok guard after the stale-navigation check in the navigation loop: hard-navigate to currentHref (the browser URL without .rsc suffix). The existing finally block handles settlePendingBrowserRouterState and clearPendingPathname on this return path, so no additional bookkeeping is required. Add a !rscResponse.ok guard in readInitialRscStream so the initial hydration fallback path reloads instead of attempting RSC parsing on an HTML error body. Return a never-resolving ReadableStream so the caller does not proceed into createFromReadableStream before the reload takes effect. E2E tests verify: 404 RSC nav hard-navs to the non-.rsc URL; 500 (simulated via page.route interception) hard-navs without logging an RSC parse error; the final URL never contains .rsc. * fix(app-router): break reload loop when initial RSC fetch is persistently non-ok readInitialRscStream reloads on a non-ok RSC response so the server can render the correct error page as HTML. That assumes the next HTTP response will differ, which is not guaranteed: if the RSC endpoint is persistently broken while the HTML document is served successfully (mismatched server handler, upstream gating, intercepted requests in tests), the reload fetches the same HTML, the post-hydration RSC fetch gets the same non-ok, and the page reloads forever. Guard the reload with a sessionStorage key scoped to the current path. The first non-ok response sets the key and reloads. The second non-ok response for the same path clears the key and throws, letting the outer bootstrap catch surface the error instead of triggering another reload. A successful RSC response clears the key so a later unrelated failure on the same path still gets one reload attempt. Tighten the Playwright test that covers the 500 hard-nav path: after the hard navigation settles, wait and assert both URL stability and a bounded intercept hit count. A runaway reload loop would fail the hit count assertion. * fix(app-router): harden initial RSC recovery and cover non-RSC content-types Five review follow-ups to the non-ok RSC fetch guard. sessionStorage.getItem / setItem / removeItem can throw SecurityError in strict-mode iframes, storage-disabled browsers, and some Safari private- browsing configurations. The unguarded calls in readInitialRscStream crashed hydration in exactly those environments — worse than the original bug. Wrap every access in readReloadFlag / writeReloadFlag / clearReloadFlag helpers that swallow the exception and fall through to the "no prior attempt" branch. Replace the throw after a looped reload with console.error plus a never-resolving ReadableStream. main() is invoked as `void main()` with no outer catch, so a throw here surfaced as an unhandled promise rejection and fired window.onerror reporting hooks instead of leaving the SSR'd DOM visible as the comment promised. Returning a stream that never produces data halts hydration cleanly; the server-rendered HTML stays on screen, client components simply never hydrate. Clear the reload flag when readInitialRscStream enters the embedded-RSC branch. The embed branch runs when the server successfully rendered the page, so any prior flag is stale — without this clear, the flag could persist across a hard-reload of the same path and skip the one legitimate recovery attempt the user should get. Cover the non-RSC content-type case on both the initial-hydration fetch and the client-side navigation fetch. Next.js's equivalent guard (fetch-server-response.ts:211) is `!isFlightResponse || !res.ok || !res.body`; the previous commit only covered `!res.ok`. A proxy or CDN that returns 200 with a rewritten Content-Type (`text/html` instead of `text/x-component`) would still reach createFromFetch and throw the exact stream-parse error these guards exist to prevent. Check for a Content-Type starting with `text/x-component` before parsing. Tighten the Playwright hit-count assertion from <= 3 to <= 2. With the guard in place the expected sequence is exactly two hits (the triggering client RSC nav fetch plus one post-reload fetch that aborts); any extra hit signals an unnecessary reload worth catching. * test(app-router): narrow RSC error filter to stream-parse diagnostics The test's console-error filter matched any message containing "RSC navigation error", which also captures an unrelated pre-existing hydration race: when page.evaluate calls __VINEXT_RSC_NAVIGATE__ before the AppRouter useLayoutEffect has committed, getBrowserRouterState throws "Browser router state is not initialized". That race has nothing to do with the stream-parse bug this PR fixes — the outer catch still hard-navigates to the target URL correctly — but the broad filter treated it as a failure, producing a flaky test that only passed on retry (seen on commit 6071901: failed first attempt, passed retry #1). My earlier commit's tighter hit-count assertion did not mask the flakiness; it just happened to hit the race on more retries. Replace the string list with an isRscStreamParseError helper that matches only the concrete diagnostics createFromFetch emits when handed an HTML body (Connection closed, createFromFetch / createFromReadableStream stack frames, Failed to parse RSC, Unexpected token). The pre-fix path produces exactly these messages, so the test still proves the fix; the hydration race no longer false-positives. * fix(app-router): abort hydration bootstrap when recovery cannot restore RSC Address the half-hydrated-state side effect of the previous commit's recovery path. When readInitialRscStream hits a persistent failure, the returned never-resolving stream let main() continue past the await and still assign window.__VINEXT_RSC_ROOT__, window.__VINEXT_HYDRATED_AT, and window.__VINEXT_RSC_NAVIGATE__. External probes (test helpers, analytics, Sentry hydration hooks) saw a hydrated page, user clicks on Links triggered __VINEXT_RSC_NAVIGATE__, and the resulting fetch rendered into a root that was suspended on a never-resolving initial-elements promise, so every navigation also hung. None of those globals should exist when hydration was deliberately aborted. Change readInitialRscStream's return type to ReadableStream | null and have recoverFromBadInitialRscResponse return null on the abort path (second attempt on the same path). main() now early-returns when the stream is null, leaving only the server-rendered HTML visible and no hydration globals for external code to observe. Add a console.warn on the first attempt before window.location.reload(). One-shot (the sessionStorage flag keeps it from repeating) but makes production reload behavior traceable rather than a mystery. Pin the invariant that makes the hard-nav destination correct after a server-side redirect hop: the inline redirect branch keeps currentHref in sync with history across hops, so window.location.href = currentHref on a !ok / !isFlight response is safe. Comment flags this for future refactors. Tighten the test's RSC stream-parse filter to require an RSC-context co-marker for generic strings ("Connection closed", "Unexpected token"), so a benign third-party JSON.parse diagnostic cannot false-positive. Rewrite the hit-count comment to match the assertion (<= 2 is the real bound; hydration timing can make the prefetch race yield 1 hit). * fix(app-router): tighten RSC error hygiene around hydration and unload - recoverFromBadInitialRscResponse now returns null from both branches so main() aborts the hydration bootstrap in the reload-pending case too. The never-resolving ReadableStream sentinel would let main() proceed past readInitialRscStream and register __VINEXT_RSC_ROOT__ / __VINEXT_RSC_NAVIGATE__ during the brief window before the reload takes effect, briefly exposing a half-hydrated surface to external probes. - Track isPageUnloading via a pagehide listener and suppress the "[vinext] RSC navigation error" diagnostic when the catch fires because a hard-nav or anchor click aborted an in-flight RSC fetch. Mirrors the Next.js isPageUnloading pattern — the page is already going away, so the log is just noise. * test(app-router): tighten RSC fetch error suite - Replace the fixed 1500ms stability wait with waitForLoadState("networkidle"). Tracking actual request activity avoids flaky wall-clock behavior in CI; a reload loop keeps the network busy so the wait times out and still surfaces the regression. - Drop the third test. Its "URL does not contain .rsc" assertion is strictly weaker than the first test's exact URL match on the non-.rsc destination. * fix(app-router): reset isPageUnloading on pageshow for bfcache restore Without a pageshow handler, a bfcache-restored document resumes with isPageUnloading stuck at true, causing the navigation catch to silently swallow every subsequent RSC error for the lifetime of that tab. Pair the listeners to match Next.js' fetch-server-response.ts. Also tighten the RSC fetch-errors spec with a >= 1 lower bound on the .rsc hit count so a future regression that skips the client nav fetch entirely still fails the test instead of trivially satisfying <= 2. * refactor(app-router): unify recoveryFromBadInitialRscResponse return and fix test listener ordering Collapse the two branches of recoverFromBadInitialRscResponse onto a single return null at the end of the function, so the "always returns null" invariant is structural rather than duplicated. A future refactor that wanted to return a sentinel from one branch would have to move the return, which is a visible edit — not a silent divergence. Register the Playwright console listener before page.goto in both rsc-fetch-errors specs so errors during initial page hydration are captured, matching the invariant the tests rely on elsewhere. * refactor(app-router): hard-nav to response URL and isolate hydration bootstrap On an RSC nav that hits a non-ok/wrong-content-type response, prefer the post-redirect response URL (navResponseUrl ?? navResponse.url) over the original currentHref so a redirect-to-error chain lands the user directly on the failing destination instead of bouncing off the redirect source and re-following the same 3xx. Matches Next.js' doMpaNavigation(responseUrl.toString()). Falls back to currentHref when no response URL is available. Extract the post-null-check body of main() into a synchronous bootstrapHydration helper. The null-branch structurally cannot reach any __VINEXT_RSC_* assignment now — a future refactor that interposes async work between the stream read and the globals is a visible change to the helper or its caller, not a silent invariant break. Tighten the /about.rsc intercept glob to an anchored regex so a hypothetical future self-prefetch from /about cannot inflate aboutRscHits past the <= 2 bound. Note the dual-guard coverage (status 500 + text/html) on the fulfill body so maintainers don't drop either half. * fix(app-router): add !body parity guard and preserve trailingSlash on hard-nav Add the missing `!rscResponse.body` branch to readInitialRscStream so the initial-hydration path guards on all three conditions Next.js checks in fetch-server-response.ts (`!ok || !isFlightResponse || !body`), not just the first two. A 200 with valid text/x-component but a null body (e.g. 204-shaped responses, edge workers that return headers without piping) now triggers the reload/abort recovery instead of parsing an empty stream and throwing downstream. Preserve the trailing slash when stripping .rsc from the hard-nav target. toRscUrl normalizes `/foo/` to `/foo.rsc` before the fetch, so the response URL loses the slash; stripping `.rsc` gave `/foo` and sites with trailingSlash:true incurred an extra 308 to the canonical `/foo/` form. Now restored when currentHref had one. * feat(app-router): preserve hash on hard-nav and cover redirect-chain path Preserve the fragment from the user's clicked href on the hard-nav target — a .rsc response URL never carries a fragment, so dropping it would silently strip /foo#section down to /foo. Small ergonomic win over Next.js' doMpaNavigation, which has the same gap. Add an e2e test for the redirect-chain hard-nav path (/redirect-src → 307 → /about.rsc → 500). Verifies the address bar lands on /about (the post-redirect URL) rather than /redirect-src (the original request), exercising the navResponseUrl ?? navResponse.url branch the previous round introduced. Also pin the embedded-RSC assumption in the existing 500-route test by snapshotting the .rsc hit count before and after networkidle and asserting no additional hits — so a future change that makes the embed path conditional surfaces as a count change rather than a networkidle timeout. * chore(app-router): drop dead !body throw and tighten redirect-chain test Remove the unreachable `if (!rscResponse.body) throw new Error(...)` at the bottom of readInitialRscStream. The new !body guard added earlier in the function returns via recoverFromBadInitialRscResponse before this branch is reached, so the throw was stale belt-and-suspenders. Tighten the redirect-chain e2e test: - Capture every main-frame navigation URL via framenavigated and assert /redirect-src never appears, so a regression that dropped the navResponseUrl ?? navResponse.url branch is caught even though the final URL would still converge to /about via the server's 307 replay. - Pin the Playwright redirect-intercept assumption — the test relies on Playwright re-entering the route table on the 307 follow-up so both handlers fire in sequence; a future mocker migration that follows redirects transparently would silently skip the /about.rsc intercept. * fix(app-router): abort hydration when sessionStorage cannot persist reload guard If sessionStorage is denied (strict-mode iframe, enterprise-locked browser policy), the reload-loop guard's setItem silently no-ops and every subsequent getItem returns null — turning the recovery path into an infinite reload loop on a persistently broken .rsc endpoint. Verify the write by reading it back and, if it didn't persist, abort hydration immediately so the user sees the server-rendered HTML instead. Hoist `new URL(currentHref, window.location.origin)` to a single `origUrl` binding in the hard-nav target builder — the same href was parsed twice for trailing-slash detection and hash extraction. --------- Co-authored-by: Claude <noreply@anthropic.com>
…ecognizedActionError (cloudflare#1206) * fix(shims): add unstable_catchError, unstable_rethrow, unstable_isUnrecognizedActionError Unblocks 18 build failures in the Next.js deploy suite: - `unstable_catchError` (12 failures) — added to `shims/error.tsx`. App Router error-boundary HOC ported from Next.js's `client/components/catch-error.tsx`. Implements the same `getDerivedStateFromError` predicate that re-throws Next.js navigation signals (redirect, notFound, …) and renders the user fallback with an `ErrorInfo` value otherwise. `unstable_retry` throws a clear "not yet implemented" error (tracked as follow-up). - `unstable_rethrow` (3 failures) — added to `shims/navigation.ts` and re-exported from `shims/navigation.react-server.ts`. Ported from Next.js's `client/components/unstable-rethrow.{ts,server,browser}.ts`. Specialized to the internal-error categories vinext actually emits (redirect + HTTP access fallback); recurses through `error.cause` for wrapped errors. - `unstable_isUnrecognizedActionError` (3 failures) — added to `shims/navigation.ts` along with the `UnrecognizedActionError` class. Ported 1:1 from `client/components/unrecognized-action-error.ts`. The react-server condition exports a throwing stub matching Next.js's `navigation.react-server.ts`. Also adds `isRedirectError` and `isNextRouterError` helpers to `navigation.ts` (used internally by `unstable_rethrow`) and updates `next-shims.d.ts` so the new exports type-check for users. * fix(shims): document isRedirectError divergence and dedupe error-boundary copy Addresses two /bigbonk review observations on cloudflare#1206: 1. **Document the permissive prefix match.** The public `isRedirectError` in `shims/navigation.ts` does `digest.startsWith("NEXT_REDIRECT;")` while Next.js's `client/components/redirect-error.ts` does full 4-segment validation (type ∈ {push, replace}, non-empty destination, status ∈ {303, 307, 308}). The divergence is intentional — vinext emits 3-part and 4-part digests whereas Next.js's validator targets its 5-part canary digests — but now that the predicate is reachable from the public `next/navigation` surface via `unstable_rethrow`, it gets a prominent JSDoc block explaining the difference, the consequence (malformed digests return true here, false in Next.js), and a link to the Next.js source. 2. **Consolidate duplicate `isRedirectError`.** `shims/error-boundary.tsx` had its own private copy with the same prefix-match logic. Replaced the duplicate with an import from `./navigation.js`, matching the pattern already used by `shims/error.tsx` (`import { isNextRouterError } from "./navigation.js"`). The `RedirectBoundary` call site casts to the file-local `RedirectError` type to preserve access to the optional `handled` field — this is safe by construction (every error matching the prefix predicate is produced by vinext's `redirect()` / `permanentRedirect()` helpers, which yield `Error` instances). No behavior change. `vp check` + `vp test run tests/shims.test.ts tests/error-boundary.test.ts` (916 tests) pass. * fix(shims): drop unused getErrorDigest export After consolidating shims/error-boundary.tsx onto the public isRedirectError from shims/navigation.ts, the only remaining caller of getErrorDigest is inside utils/navigation-signal.ts itself. Knip flags the export as unused, which fails the Check job in CI. Convert getErrorDigest to a file-local function. No behavior change. * fix(shims): extend unstable_rethrow + make unstable_retry functional Parity audit findings on PR cloudflare#1206 (post /bigbonk APPROVED) revealed two gaps from a thorough re-read of Next.js's error-rethrow surface and `unstable_catchError` test fixtures. ## 1. `unstable_rethrow` — added missing error categories Next.js's server-side `unstable_rethrow` rethrows seven error categories (client-side rethrows two). vinext was only handling #1 (`isNextRouterError`). The canonical user-facing fixture (`test/e2e/app-dir/app-static/lib/fetch-retry.js`) breaks if any of the other categories are not propagated. Added the two categories vinext can plausibly encounter: - `BailoutToCSRError` + `isBailoutToCSRError` — thrown by `next/dynamic` with `ssr: false`. Lives in shared (non-server) code so third-party libraries and accidentally-bundled Next.js internals can produce it. Ported 1:1 from https://github.com/vercel/next.js/blob/canary/packages/next/src/shared/lib/lazy-dynamic/bailout-to-csr.ts - `DynamicServerError` + `isDynamicServerError` — thrown by Next.js's `cookies()`/`headers()` when called in a static render context. vinext doesn't construct it itself but exposes the class so user code, action wrappers, and accidental Next.js-internal bundles can interoperate. Ported 1:1 from https://github.com/vercel/next.js/blob/canary/packages/next/src/client/components/hooks-server-context.ts The remaining four server-only categories (`isDynamicPostpone`, `isPostpone`, `isHangingPromiseRejectionError`, `isPrerenderInterruptedError`) are tied to Next.js's PPR / prerender controller machinery that vinext does not implement. User code cannot construct them in normal use; they're deferred as a follow-up (documented inline). A test pins this intentional gap. ## 2. `unstable_catchError.unstable_retry` — made functional The previous implementation threw a generic "not yet implemented" error in both server and client contexts. Now matches Next.js's App Router branch: on the client, calls `appRouterInstance.refresh()` inside `React.startTransition` and resets the boundary. On the server, throws a clear "client-only" error (refresh is meaningless during SSR setup). Pages Router's exact error message (`unstable_retry() can only be used in the App Router. Use reset() in the Pages Router.`) is not yet dispatched because vinext's boundary doesn't read `PagesRouterContext`; documented in the JSDoc as a parity follow-up. ## Test coverage Added 8 new test cases covering: - `BailoutToCSRError` + predicate (canonical digest, foreign-object detection, negative cases) - `DynamicServerError` + predicate (same shape) - `unstable_rethrow` propagates both new categories (re-throw identity) - `unstable_rethrow` does NOT match the four uncovered server-only categories (pins the intentional gap) - `unstable_catchError.getDerivedStateFromError` accepts `null` / `undefined` thrown values (ported from test/e2e/app-dir/catch-error/throw-null and throw-undefined fixtures) - `unstable_retry` throws "client-only" on the server - `unstable_retry` on the client calls `appRouterInstance.refresh()` + resets via setState Also added `isRedirectError` / `isNextRouterError` / new predicates JSDoc note that these are vinext-only extensions (Next.js does NOT export them from `next/navigation` — confirmed by reading `packages/next/src/client/components/navigation.ts` end-to-end). `vp test run tests/shims.test.ts tests/error-boundary.test.ts tests/app-router.test.ts tests/app-rsc-errors.test.ts` — 1274 tests pass. `vp check` clean. * fix(shims): drop redundant typeof check in isDynamicServerError Bonk-review observation on cloudflare#1206: the predicate was checking `typeof digest === "string" && digest === _DYNAMIC_SERVER_USAGE_DIGEST`, where the `===` against a string literal already requires the operand to be a string. Drop the redundant guard for consistency with `isBailoutToCSRError` above. Non-blocking cleanup; no behavior change.
No description provided.