Skip to content

Commit 89ec16d

Browse files
authored
fix(react): hmr did not work for components imported with queries with rolldown-vite (#872)
1 parent 54da603 commit 89ec16d

File tree

9 files changed

+87
-9
lines changed

9 files changed

+87
-9
lines changed

packages/plugin-react/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
## Unreleased
44

5+
### HMR did not work for components imported with queries with rolldown-vite ([#872](https://github.com/vitejs/vite-plugin-react/pull/872))
6+
57
### Perf: simplify refresh wrapper generation ([#835](https://github.com/vitejs/vite-plugin-react/pull/835))
68

79
## 5.0.2 (2025-08-28)

packages/plugin-react/src/index.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,8 @@ export default function viteReact(opts: Options = {}): Plugin[] {
144144
// if development is enabled and those properties are already present
145145
development: false,
146146
},
147-
jsxRefreshInclude: include,
148-
jsxRefreshExclude: exclude,
147+
jsxRefreshInclude: makeIdFiltersToMatchWithQuery(include),
148+
jsxRefreshExclude: makeIdFiltersToMatchWithQuery(exclude),
149149
},
150150
}
151151
} else {
@@ -156,8 +156,8 @@ export default function viteReact(opts: Options = {}): Plugin[] {
156156
importSource: opts.jsxImportSource,
157157
refresh: command === 'serve',
158158
},
159-
jsxRefreshInclude: include,
160-
jsxRefreshExclude: exclude,
159+
jsxRefreshInclude: makeIdFiltersToMatchWithQuery(include),
160+
jsxRefreshExclude: makeIdFiltersToMatchWithQuery(exclude),
161161
},
162162
optimizeDeps: {
163163
rollupOptions: { transform: { jsx: { runtime: 'automatic' } } },

playground/react-classic/App.jsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import React, { useState } from 'react'
2+
import WithQuery from './components/WithQuery?qs-should-not-break-plugin-react'
23

34
function App() {
45
const [count, setCount] = useState(0)
@@ -23,6 +24,8 @@ function App() {
2324
Learn React
2425
</a>
2526
</header>
27+
28+
<WithQuery />
2629
</div>
2730
)
2831
}

playground/react-classic/__tests__/react.spec.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,28 @@ test.runIf(isServe)('should hmr', async () => {
1818
expect(await page.textContent('button')).toMatch('count is: 1')
1919
})
2020

21+
test.runIf(isServe)('should hmr files with queries', async () => {
22+
expect(await page.textContent('#WithQuery')).toBe('With Query')
23+
24+
expect(await page.textContent('#WithQuery-button')).toMatch('count is: 0')
25+
await page.click('#WithQuery-button')
26+
expect(await page.textContent('#WithQuery-button')).toMatch('count is: 1')
27+
28+
editFile('components/WithQuery.jsx', (code) =>
29+
code.replace('With Query', 'With Query Updated'),
30+
)
31+
await expect
32+
.poll(() => page.textContent('#WithQuery'))
33+
.toBe('With Query Updated')
34+
// preserve state
35+
expect(await page.textContent('#WithQuery-button')).toMatch('count is: 1')
36+
37+
editFile('components/WithQuery.jsx', (code) =>
38+
code.replace('With Query Updated', 'With Query'),
39+
)
40+
await expect.poll(() => page.textContent('#WithQuery')).toBe('With Query')
41+
})
42+
2143
test.runIf(isServe)(
2244
'should have annotated jsx with file location metadata',
2345
async () => {
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import React, { useState } from 'react'
2+
3+
export default function WithQuery() {
4+
const [count, setCount] = useState(0)
5+
return (
6+
<>
7+
<div id="WithQuery">With Query</div>
8+
<button
9+
id="WithQuery-button"
10+
onClick={() => setCount((count) => count + 1)}
11+
>
12+
count is: {count}
13+
</button>
14+
</>
15+
)
16+
}

playground/react/App.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { useState } from 'react'
22
import Button from 'jsx-entry'
3-
import Dummy from './components/Dummy?qs-should-not-break-plugin-react'
3+
import WithQuery from './components/WithQuery?qs-should-not-break-plugin-react'
44
import { Accordion } from './components/Accordion'
55
import Parent from './hmr/parent'
66
import { JsxImportRuntime } from './hmr/jsx-import-runtime'
@@ -39,7 +39,7 @@ function App() {
3939
</a>
4040
</header>
4141

42-
<Dummy />
42+
<WithQuery />
4343
<Accordion.Root>
4444
<Accordion.Item>First Item</Accordion.Item>
4545
<Accordion.Item>Second Item</Accordion.Item>

playground/react/__tests__/react.spec.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,28 @@ test.runIf(isServe)('should hmr', async () => {
3535
await expect.poll(() => page.textContent('h1')).toMatch('Hello Vite + React')
3636
})
3737

38+
test.runIf(isServe)('should hmr files with queries', async () => {
39+
expect(await page.textContent('#WithQuery')).toBe('With Query')
40+
41+
expect(await page.textContent('#WithQuery-button')).toMatch('count is: 0')
42+
await page.click('#WithQuery-button')
43+
expect(await page.textContent('#WithQuery-button')).toMatch('count is: 1')
44+
45+
editFile('components/WithQuery.jsx', (code) =>
46+
code.replace('With Query', 'With Query Updated'),
47+
)
48+
await expect
49+
.poll(() => page.textContent('#WithQuery'))
50+
.toBe('With Query Updated')
51+
// preserve state
52+
expect(await page.textContent('#WithQuery-button')).toMatch('count is: 1')
53+
54+
editFile('components/WithQuery.jsx', (code) =>
55+
code.replace('With Query Updated', 'With Query'),
56+
)
57+
await expect.poll(() => page.textContent('#WithQuery')).toBe('With Query')
58+
})
59+
3860
test.runIf(isServe)('should not invalidate when code is invalid', async () => {
3961
editFile('App.jsx', (code) =>
4062
code.replace('<div className="App">', '<div className="App"}>'),

playground/react/components/Dummy.jsx

Lines changed: 0 additions & 3 deletions
This file was deleted.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { useState } from 'react'
2+
3+
export default function WithQuery() {
4+
const [count, setCount] = useState(0)
5+
return (
6+
<>
7+
<div id="WithQuery">With Query</div>
8+
<button
9+
id="WithQuery-button"
10+
onClick={() => setCount((count) => count + 1)}
11+
>
12+
count is: {count}
13+
</button>
14+
</>
15+
)
16+
}

0 commit comments

Comments
 (0)