Skip to content

Commit 37c7762

Browse files
committed
fix(hmr): skip HMR for JSX files with hooks
1 parent 7517103 commit 37c7762

File tree

15 files changed

+154
-1
lines changed

15 files changed

+154
-1
lines changed

packages/common/refresh-utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
export const runtimePublicPath = '/@react-refresh'
22

33
const reactCompRE = /extends\s+(?:React\.)?(?:Pure)?Component/
4-
const refreshContentRE = /\$Refresh(?:Reg|Sig)\$\(/
4+
const refreshContentRE = /\$RefreshReg\$\(/
55

66
// NOTE: this is exposed publicly via plugin-react
77
export const preambleCode = `import { injectIntoGlobalHook } from "__BASE__${runtimePublicPath.slice(

packages/plugin-react-oxc/CHANGELOG.md

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

33
## Unreleased
44

5+
### Skip HMR for JSX files with hooks
6+
7+
The current HMR implementation was trying to all HMR files that contains either hooks or components, but this was working only for components and lead to HMR invalidation for JSX files containing hooks.
8+
9+
The best solution would have been to support HMR for hooks, but in my testing it was sometimes leading to stale updates. So this simple and reliable solution is to skip HMR for these files and have the components handle the updates, like any other hooks file.
10+
511
## 0.1.1 (2025-04-10)
612

713
## 0.1.0 (2025-04-09)

packages/plugin-react-swc/CHANGELOG.md

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

33
## Unreleased
44

5+
### Skip HMR for JSX files with hooks
6+
7+
The current HMR implementation was trying to all HMR files that contains either hooks or components, but this was working only for components and lead to HMR invalidation for JSX files containing hooks.
8+
9+
The best solution would have been to support HMR for hooks, but in my testing it was sometimes leading to stale updates. So this simple and reliable solution is to skip HMR for these files and have the components handle the updates, like any other hooks file.
10+
511
## 3.9.0 (2025-04-15)
612

713
### Make compatible with rolldown-vite

packages/plugin-react/CHANGELOG.md

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

33
## Unreleased
44

5+
### Skip HMR for JSX files with hooks
6+
7+
The current HMR implementation was trying to all HMR files that contains either hooks or components, but this was working only for components and lead to HMR invalidation for JSX files containing hooks.
8+
9+
The best solution would have been to support HMR for hooks, but in my testing it was sometimes leading to stale updates. So this simple and reliable solution is to skip HMR for these files and have the components handle the updates, like any other hooks file.
10+
511
## 4.4.1 (2025-04-19)
612

713
Fix type issue when using `moduleResolution: "node"` in tsconfig [#462](https://github.com/vitejs/vite-plugin-react/pull/462)
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { expect, test } from 'vitest'
2+
import {
3+
editFile,
4+
isServe,
5+
page,
6+
untilBrowserLogAfter,
7+
untilUpdated,
8+
} from '~utils'
9+
10+
test('should render', async () => {
11+
expect(await page.textContent('button')).toMatch('count is 0')
12+
expect(await page.click('button'))
13+
expect(await page.textContent('button')).toMatch('count is 1')
14+
})
15+
16+
if (isServe) {
17+
test('Hook with JSX HMR', async () => {
18+
editFile('src/useButtonHook.tsx', (code) =>
19+
code.replace('count is {count}', 'count is {count}!'),
20+
)
21+
await untilBrowserLogAfter(
22+
() => page.textContent('button'),
23+
'[vite] hot updated: /src/App.tsx',
24+
)
25+
await untilUpdated(() => page.textContent('button'), 'count is 1!')
26+
})
27+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
import '../hook-with-jsx.spec'
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
7+
<title>React hook with JSX</title>
8+
</head>
9+
<body>
10+
<div id="root"></div>
11+
<script type="module" src="/src/index.tsx"></script>
12+
</body>
13+
</html>
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"name": "@vitejs/test-hook-with-jsx",
3+
"private": true,
4+
"type": "module",
5+
"scripts": {
6+
"dev": "vite",
7+
"build": "vite build",
8+
"preview": "vite preview"
9+
},
10+
"dependencies": {
11+
"react": "^19.1.0",
12+
"react-dom": "^19.1.0"
13+
},
14+
"devDependencies": {
15+
"@types/react": "^19.1.2",
16+
"@types/react-dom": "^19.1.2",
17+
"@vitejs/plugin-react": "workspace:*"
18+
}
19+
}
Lines changed: 1 addition & 0 deletions
Loading
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { useButtonHook } from './useButtonHook.tsx'
2+
3+
export function App() {
4+
const button = useButtonHook()
5+
return <div>{button}</div>
6+
}

0 commit comments

Comments
 (0)