mirror of
https://github.com/cloudflare/vinext.git
synced 2026-05-09 08:25:34 +02:00
[PR #467] [CLOSED] fix: React 19 dev-mode compatibility with Vite module runner #591
Labels
No labels
enhancement
enhancement
good first issue
help wanted
nextjs-tracking
nextjs-tracking
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
starred/vinext#591
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
📋 Pull Request Information
Original PR: https://github.com/cloudflare/vinext/pull/467
Author: @benfavre
Created: 3/11/2026
Status: ❌ Closed
Base:
main← Head:fix/react19-dev-mode-compat📝 Commits (1)
ef149f7fix: React 19 dev-mode compatibility with Vite module runner📊 Changes
3 files changed (+198 additions, -0 deletions)
View changed files
📝
packages/vinext/src/index.ts(+6 -0)➕
packages/vinext/src/plugins/patch-react-server-dom.ts(+125 -0)➕
packages/vinext/src/plugins/strip-react-type-imports.ts(+67 -0)📄 Description
Problem
React 19's
react-server-dom-webpackdevelopment builds include aggressive error/stack reconstruction logic that crashes in Vite's module runner. Everyvinextuser running React 19 in dev mode hits these crashes — they block the dev server from serving any page.Crash 1:
debugStacknull vs undefinedReact's code uses
null !== task.debugStack(strict equality), but in Vite's module runnertask.debugStackisundefined(notnull).undefined !== nullistrue, so the guard passes andparseStackTrace(undefined, 1)crashes onundefined.stack.Crash 2:
parseStackTracewith undefined errorCalled with
undefinederror objects in certain code paths.Crash 3:
console.createTaskin module runnerV8's
console.createTask()devtools API behaves differently in Vite's module runner context.Crash 4:
buildFakeCallStackwith undefined stackCalled with
undefinedstack argument, crashes during stack frame reconstruction.Crash 5:
resolveErrorDevstack reconstructionFull stack reconstruction using
buildFakeCallStack+console.createTaskcrashes without proper element ownership metadata (vinext's__wrapper,@vitejs/plugin-rsc's Resources lack_debugStack/_debugTask).Crash 6: "without development properties"
Framework internals create elements without dev metadata. Production builds ignore this; dev builds throw.
Crash 7:
Named export 'ReactNode' not foundesbuild (Vite's default TS transform) cannot determine that
import { ReactNode } from "react"is type-only without full TypeScript type information. It preserves the import, and Vite's module runner fails because the pre-bundled CJSreactmodule only has runtime exports.Solution
Two new Vite plugins, registered in vinext's plugin array:
Plugin 1:
vinext:patch-react-server-domApplies 6 targeted string-replacement patches to
react-server-dom-webpackdev builds at transform time:null !== task.debugStack→null != task.debugStacknullandundefinedparseStackTrace(error, skipFrames)[]whenerror == nullsupportsCreateTask = !!console.createTaskfalsebuildFakeCallStack(response, stack, ...)innerCallwhen!stackresolveErrorDev(response, errorInfo)throw Error("...without development properties...")void 0Targets both standalone
react-server-dom-webpackand the vendor copy in@vitejs/plugin-rsc/dist/vendor/react-server-dom/.Plugin 2:
vinext:strip-react-type-importsMaintains the complete set of React 19 runtime exports. For
import { ... } from "react"statements, strips any specifier not in the runtime set:Handles edge cases:
import type { ... }→ skipped entirelyimport { type ReactNode, useState }→ inlinetypeannotation respectedimport { ReactNode as RN }→ aliases resolved correctlyimport { ReactNode }→ replaced with comment placeholderChanges
packages/vinext/src/plugins/patch-react-server-dom.tspackages/vinext/src/plugins/strip-react-type-imports.tspackages/vinext/src/index.tsReproduction
Any app using React 19 with vinext in development mode:
Risk
Low. Both plugins:
.development.in filename)enforce: "pre"so they run before other transformsThe
strip-react-type-importsplugin is conservative — it only strips names that are not in the React 19 runtime export list. If React adds new runtime exports in the future, the allowlist needs to be updated.🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.