From 099643760f99d30ab77014173a62152eed918eb2 Mon Sep 17 00:00:00 2001
From: sapphi-red <49056869+sapphi-red@users.noreply.github.com>
Date: Tue, 12 Aug 2025 20:56:27 +0900
Subject: [PATCH 1/3] fix(react): refreshWrapper was injected twice for class
components when using babel plugins and rolldown-vite
---
packages/plugin-react/src/index.ts | 3 ++-
playground/compiler/__tests__/compiler.spec.ts | 1 +
playground/compiler/src/App.tsx | 2 ++
playground/compiler/src/ClassComponent.tsx | 7 +++++++
4 files changed, 12 insertions(+), 1 deletion(-)
create mode 100644 playground/compiler/src/ClassComponent.tsx
diff --git a/packages/plugin-react/src/index.ts b/packages/plugin-react/src/index.ts
index 87d00b167..6184084a5 100644
--- a/packages/plugin-react/src/index.ts
+++ b/packages/plugin-react/src/index.ts
@@ -324,7 +324,8 @@ export default function viteReact(opts: Options = {}): Plugin[] {
})
if (result) {
- if (!useFastRefresh) {
+ // refresh wrapper is added later for rolldown-vite
+ if (!useFastRefresh || isRolldownVite) {
return { code: result.code!, map: result.map }
}
return addRefreshWrapper(
diff --git a/playground/compiler/__tests__/compiler.spec.ts b/playground/compiler/__tests__/compiler.spec.ts
index 742b6f37a..0889e0bd4 100644
--- a/playground/compiler/__tests__/compiler.spec.ts
+++ b/playground/compiler/__tests__/compiler.spec.ts
@@ -5,6 +5,7 @@ test('should render', async () => {
expect(await page.textContent('button')).toMatch('count is 0')
expect(await page.click('button'))
expect(await page.textContent('button')).toMatch('count is 1')
+ expect(await page.textContent('.class-component')).toMatch('ClassComponent')
})
test.runIf(isServe)('should hmr', async () => {
diff --git a/playground/compiler/src/App.tsx b/playground/compiler/src/App.tsx
index 3cdc1d623..07f8d0add 100644
--- a/playground/compiler/src/App.tsx
+++ b/playground/compiler/src/App.tsx
@@ -1,5 +1,6 @@
import { useState } from 'react'
import './App.css'
+import { ClassComponent } from './ClassComponent'
export function App() {
const [count, setCount] = useState(0)
@@ -18,6 +19,7 @@ export function App() {
Click on the Vite and React logos to learn more
+
>
)
}
diff --git a/playground/compiler/src/ClassComponent.tsx b/playground/compiler/src/ClassComponent.tsx
new file mode 100644
index 000000000..c0f0e39a4
--- /dev/null
+++ b/playground/compiler/src/ClassComponent.tsx
@@ -0,0 +1,7 @@
+import { Component } from 'react'
+
+export class ClassComponent extends Component {
+ public render() {
+ return ClassComponent
+ }
+}
From 275d2ee807f96bc8e79294df3f1ce1b65c0e8a0b Mon Sep 17 00:00:00 2001
From: Hiroshi Ogawa
Date: Thu, 14 Aug 2025 09:38:01 +0900
Subject: [PATCH 2/3] refactor: move condition
---
packages/plugin-react/src/index.ts | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/packages/plugin-react/src/index.ts b/packages/plugin-react/src/index.ts
index 6184084a5..3a4cdbc51 100644
--- a/packages/plugin-react/src/index.ts
+++ b/packages/plugin-react/src/index.ts
@@ -255,6 +255,7 @@ export default function viteReact(opts: Options = {}): Plugin[] {
const isJSX = filepath.endsWith('x')
const useFastRefresh =
+ !isRolldownVite &&
!skipFastRefresh &&
!ssr &&
(isJSX ||
@@ -262,7 +263,7 @@ export default function viteReact(opts: Options = {}): Plugin[] {
? importReactRE.test(code)
: code.includes(jsxImportDevRuntime) ||
code.includes(jsxImportRuntime)))
- if (useFastRefresh && !isRolldownVite) {
+ if (useFastRefresh) {
plugins.push([
await loadPlugin('react-refresh/babel'),
{ skipEnvCheck: true },
@@ -324,8 +325,7 @@ export default function viteReact(opts: Options = {}): Plugin[] {
})
if (result) {
- // refresh wrapper is added later for rolldown-vite
- if (!useFastRefresh || isRolldownVite) {
+ if (!useFastRefresh) {
return { code: result.code!, map: result.map }
}
return addRefreshWrapper(
From aa1f1cc4b1a5d35973387c26de839db850317a2f Mon Sep 17 00:00:00 2001
From: Hiroshi Ogawa
Date: Thu, 14 Aug 2025 10:03:19 +0900
Subject: [PATCH 3/3] chore: changelog
---
packages/plugin-react/CHANGELOG.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/packages/plugin-react/CHANGELOG.md b/packages/plugin-react/CHANGELOG.md
index c1dc40979..131a1fc9e 100644
--- a/packages/plugin-react/CHANGELOG.md
+++ b/packages/plugin-react/CHANGELOG.md
@@ -2,6 +2,8 @@
## Unreleased
+### Fix `RefreshRuntime` being injected twice for class components on rolldown-vite ([#708](https://github.com/vitejs/vite-plugin-react/pull/708))
+
## 5.0.0 (2025-08-07)
## 5.0.0-beta.0 (2025-07-28)