Skip to content

chore: update vite-plus and related packages to 0.1.13-alpha.5#1

Draft
fengmk2 wants to merge 1 commit into
mainfrom
test-vite-plus-alpha
Draft

chore: update vite-plus and related packages to 0.1.13-alpha.5#1
fengmk2 wants to merge 1 commit into
mainfrom
test-vite-plus-alpha

Conversation

@fengmk2
Copy link
Copy Markdown
Owner

@fengmk2 fengmk2 commented Mar 20, 2026

No description provided.

@fengmk2 fengmk2 closed this Mar 20, 2026
@fengmk2 fengmk2 reopened this Mar 20, 2026
@gemini-code-assist
Copy link
Copy Markdown

Summary of Changes

Hello, 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 vite-plus and its related ecosystem packages to their latest alpha version, 0.1.13-alpha.5. This ensures the project benefits from the newest features, bug fixes, and performance improvements from these core dependencies. Corresponding documentation has been adjusted to guide users on the updated command behaviors.

Highlights

  • Vite+ Package Updates: Updated vite-plus and its core components (vite-plus-core, vite-plus-test) to version 0.1.13-alpha.5.
  • Tooling Dependency Upgrades: Upgraded underlying tooling dependencies including oxfmt to 0.41.0, oxlint to 1.56.0, cac to 7.0.0, and @oxc-project packages to 0.120.0.
  • Documentation Refinements: Revised AGENTS.md documentation to reflect changes in Vite+ command usage, specifically for vp test, vp lint, and clarified package.json script execution.

🧠 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 Assist

The 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 /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

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 .gemini/ folder in the base of the repository. Detailed instructions can be found here.

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

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

fengmk2 pushed a commit that referenced this pull request Apr 29, 2026
…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>
fengmk2 pushed a commit that referenced this pull request May 19, 2026
…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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant