diff --git a/e2e/cases/preact/prefresh-context/index.test.ts b/e2e/cases/preact/prefresh-context/index.test.ts
new file mode 100644
index 0000000000..ac483ccaf6
--- /dev/null
+++ b/e2e/cases/preact/prefresh-context/index.test.ts
@@ -0,0 +1,61 @@
+import fs from 'node:fs';
+import path from 'node:path';
+import { dev, rspackOnlyTest } from '@e2e/helper';
+import { expect, test } from '@playwright/test';
+
+rspackOnlyTest(
+ 'HMR should work properly with `createContext`',
+ async ({ page }) => {
+ // HMR cases will fail in Windows
+ if (process.platform === 'win32') {
+ test.skip();
+ }
+
+ const root = __dirname;
+ const compFilePath = path.join(root, 'src/test-temp-B.jsx');
+ const compSourceCode = `const B = (props) => {
+ return
B: {props.count}
;
+};
+
+export default B;
+`;
+
+ fs.writeFileSync(compFilePath, compSourceCode, 'utf-8');
+
+ const rsbuild = await dev({
+ cwd: root,
+ page,
+ });
+
+ const a = page.locator('#A');
+ const b = page.locator('#B');
+
+ await expect(a).toHaveText('A: 0');
+ await expect(b).toHaveText('B: 0');
+
+ await a.click({ clickCount: 5 });
+ await expect(a).toHaveText('A: 5');
+ await expect(b).toHaveText('B: 5');
+
+ // simulate a change to component B's source code
+ fs.writeFileSync(
+ compFilePath,
+ compSourceCode.replace('B:', 'Beep:'),
+ 'utf-8',
+ );
+
+ await page.waitForFunction(() => {
+ const aText = document.querySelector('#A')!.textContent;
+ const bText = document.querySelector('#B')!.textContent;
+
+ return (
+ // the state (count) of A should be kept
+ aText === 'A: 5' &&
+ // content of B changed to `Beep: 5` means HMR has taken effect
+ bText === 'Beep: 5'
+ );
+ });
+
+ await rsbuild.close();
+ },
+);
diff --git a/e2e/cases/preact/prefresh-context/rsbuild.config.ts b/e2e/cases/preact/prefresh-context/rsbuild.config.ts
new file mode 100644
index 0000000000..314619547e
--- /dev/null
+++ b/e2e/cases/preact/prefresh-context/rsbuild.config.ts
@@ -0,0 +1,13 @@
+import { pluginPreact } from '@rsbuild/plugin-preact';
+
+export default {
+ plugins: [
+ pluginPreact({
+ exclude: [
+ /node_modules/,
+ // exclude Rsbuild internal HMR client
+ /packages\/core\/dist/,
+ ],
+ }),
+ ],
+};
diff --git a/e2e/cases/preact/prefresh-context/src/A.jsx b/e2e/cases/preact/prefresh-context/src/A.jsx
new file mode 100644
index 0000000000..913235820f
--- /dev/null
+++ b/e2e/cases/preact/prefresh-context/src/A.jsx
@@ -0,0 +1,34 @@
+import { createContext } from 'preact';
+import { useContext, useState } from 'preact/hooks';
+import B from './test-temp-B';
+
+const MyContext = createContext();
+
+export const MyProvider = ({ children }) => {
+ const [value, setValue] = useState(0);
+ return (
+
+ {children}
+
+ );
+};
+
+const App = () => {
+ const { value, setValue } = useContext(MyContext);
+ return (
+ <>
+
+
+ >
+ );
+};
+
+export default () => {
+ return (
+
+
+
+ );
+};
diff --git a/e2e/cases/preact/prefresh-context/src/index.js b/e2e/cases/preact/prefresh-context/src/index.js
new file mode 100644
index 0000000000..3d08df867a
--- /dev/null
+++ b/e2e/cases/preact/prefresh-context/src/index.js
@@ -0,0 +1,4 @@
+import { h, render } from 'preact';
+import A from './A';
+
+render(h(A), document.getElementById('root'));
diff --git a/packages/plugin-preact/package.json b/packages/plugin-preact/package.json
index 964d7b652d..a295a72a54 100644
--- a/packages/plugin-preact/package.json
+++ b/packages/plugin-preact/package.json
@@ -28,7 +28,8 @@
"dependencies": {
"@prefresh/core": "^1.5.2",
"@prefresh/utils": "^1.2.0",
- "@rspack/plugin-preact-refresh": "^1.1.0"
+ "@rspack/plugin-preact-refresh": "^1.1.0",
+ "@swc/plugin-prefresh": "^3.0.3"
},
"devDependencies": {
"@rsbuild/core": "workspace:*",
diff --git a/packages/plugin-preact/src/index.ts b/packages/plugin-preact/src/index.ts
index 46a19b4d45..965e0ad9f5 100644
--- a/packages/plugin-preact/src/index.ts
+++ b/packages/plugin-preact/src/index.ts
@@ -68,6 +68,11 @@ export const pluginPreact = (
tools: {
swc: {
jsc: {
+ experimental: {
+ plugins: usePrefresh
+ ? [[require.resolve('@swc/plugin-prefresh'), {}]]
+ : undefined,
+ },
parser: {
syntax: 'typescript',
// enable supports for JSX/TSX compilation
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index ad7702043b..ea9eac4ea8 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -864,6 +864,9 @@ importers:
'@rspack/plugin-preact-refresh':
specifier: ^1.1.0
version: 1.1.0(@prefresh/core@1.5.2(preact@10.24.3))(@prefresh/utils@1.2.0)
+ '@swc/plugin-prefresh':
+ specifier: ^3.0.3
+ version: 3.0.3
devDependencies:
'@rsbuild/core':
specifier: workspace:*
@@ -3289,6 +3292,9 @@ packages:
'@swc/helpers@0.5.13':
resolution: {integrity: sha512-UoKGxQ3r5kYI9dALKJapMmuK+1zWM/H17Z1+iwnNmzcJRnfFuevZs375TA5rW31pu4BS4NoSy1fRsexDXfWn5w==}
+ '@swc/plugin-prefresh@3.0.3':
+ resolution: {integrity: sha512-HXRBKFwGcUuEgPsYz4tEfZ97nM0V8raDvn322tSx7vBWSxN+XdtJx4xtoIlLZNr+YSV/NXV9UpfskQZ1Dfa9bQ==}
+
'@swc/plugin-remove-console@3.0.3':
resolution: {integrity: sha512-Q7Gp0KzjBgXSJA2jOcAraJ2I/phK/RnpZDWewgqSPsElFe/Pdo3A+w2FVCEoXAd3rUtPbrav1kjpBrGmeFBpFQ==}
@@ -9975,6 +9981,10 @@ snapshots:
dependencies:
tslib: 2.6.2
+ '@swc/plugin-prefresh@3.0.3':
+ dependencies:
+ '@swc/counter': 0.1.3
+
'@swc/plugin-remove-console@3.0.3':
dependencies:
'@swc/counter': 0.1.3