Skip to content

Commit db9d3f4

Browse files
feat: add reactRefreshHost option to support module federation HMR
1 parent c02385d commit db9d3f4

File tree

7 files changed

+66
-1
lines changed

7 files changed

+66
-1
lines changed

packages/common/refresh-utils.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export function addRefreshWrapper<M extends { mappings: string }>(
2121
map: M | string | typeof avoidSourceMapOption,
2222
pluginName: string,
2323
id: string,
24+
reactRefreshHost = '',
2425
): { code: string; map: M | null | string } {
2526
const hasRefresh = refreshContentRE.test(code)
2627
const onlyReactComp = !hasRefresh && reactCompRE.test(code)
@@ -70,7 +71,8 @@ if (import.meta.hot && !inWebWorker) {
7071
}
7172

7273
const sharedHead = removeLineBreaksIfNeeded(
73-
`import * as RefreshRuntime from "${runtimePublicPath}";
74+
`import * as RefreshRuntime from "${reactRefreshHost}${runtimePublicPath}";
75+
7476
const inWebWorker = typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope;
7577
7678
`,

packages/plugin-react-swc/CHANGELOG.md

+12
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,18 @@
22

33
## Unreleased
44

5+
### Add option `reactRefreshHost`
6+
7+
Add option `reactRefreshHost` to set React refresh runtime url prefix.
8+
This is useful in module federation context to enable HMR by setting the host url on a Vite config which is serving a remote app.
9+
See full discussion here: https://github.com/module-federation/vite/issues/183#issuecomment-2751825367
10+
11+
```ts
12+
export default defineConfig({
13+
plugins: [react({ reactRefreshHost: 'http://localhost:3000' })],
14+
})
15+
```
16+
517
## 3.9.0-beta.2 (2025-04-09)
618

719
## 3.9.0-beta.0 (2025-04-09)

packages/plugin-react-swc/README.md

+10
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,16 @@ react({
9393
})
9494
```
9595

96+
### reactRefreshHost
97+
98+
The `reactRefreshHost` option is only necessary in a module federation context. It allows HMR to work between a remote & host server. In your remote vite config you would add your host origin:
99+
100+
```js
101+
react({ reactRefreshHost: 'http://localhost:3000' })
102+
```
103+
104+
Under the hood this simply updates the react refresh url from "/@react-refresh" to "http://localhost:3000/@react-refresh" to ensure you get only one Fast Refresh runtime in the whole application.
105+
96106
### useAtYourOwnRisk_mutateSwcOptions
97107

98108
The future of Vite is with OXC, and from the beginning this was a design choice to not exposed too many specialties from SWC so that Vite React users can move to another transformer later.

packages/plugin-react-swc/src/index.ts

+10
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,14 @@ type Options = {
5858
* Exclusion of node_modules should be handled by the function if needed.
5959
*/
6060
parserConfig?: (id: string) => ParserConfig | undefined
61+
/**
62+
* React refresh runtime url prefix.
63+
* Useful in module federation context to enable HMR by
64+
* setting the host url on a vite config which is serving a remote app.
65+
* @example
66+
* reactRefreshHost: 'http://localhost:3000'
67+
*/
68+
reactRefreshHost?: string
6169
/**
6270
* The future of Vite is with OXC, and from the beginning this was a design choice
6371
* to not exposed too many specialties from SWC so that Vite React users can move to
@@ -78,6 +86,7 @@ const react = (_options?: Options): PluginOption[] => {
7886
: undefined,
7987
devTarget: _options?.devTarget ?? 'es2020',
8088
parserConfig: _options?.parserConfig,
89+
reactRefreshHost: _options?.reactRefreshHost,
8190
useAtYourOwnRisk_mutateSwcOptions:
8291
_options?.useAtYourOwnRisk_mutateSwcOptions,
8392
}
@@ -152,6 +161,7 @@ const react = (_options?: Options): PluginOption[] => {
152161
result.map!,
153162
'@vitejs/plugin-react-swc',
154163
id,
164+
options.reactRefreshHost,
155165
)
156166
},
157167
},

packages/plugin-react/CHANGELOG.md

+12
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,18 @@
22

33
## Unreleased
44

5+
### Add option `reactRefreshHost`
6+
7+
Add option `reactRefreshHost` to set React refresh runtime url prefix.
8+
This is useful in module federation context to enable HMR by setting the host url on a Vite config which is serving a remote app.
9+
See full discussion here: https://github.com/module-federation/vite/issues/183#issuecomment-2751825367
10+
11+
```ts
12+
export default defineConfig({
13+
plugins: [react({ reactRefreshHost: 'http://localhost:3000' })],
14+
})
15+
```
16+
517
## 4.4.0-beta.1 (2025-04-09)
618

719
## 4.4.0-beta.0 (2025-04-09)

packages/plugin-react/README.md

+10
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,16 @@ This option does not enable _code transformation_. That is handled by esbuild.
9494

9595
Here's the [complete list of Babel parser plugins](https://babeljs.io/docs/en/babel-parser#ecmascript-proposalshttpsgithubcombabelproposals).
9696

97+
### reactRefreshHost
98+
99+
The `reactRefreshHost` option is only necessary in a module federation context. It allows HMR to work between a remote & host server. In your remote vite config you would add your host origin:
100+
101+
```js
102+
react({ reactRefreshHost: 'http://localhost:3000' })
103+
```
104+
105+
Under the hood this simply updates the react refresh url from "/@react-refresh" to "http://localhost:3000/@react-refresh" to ensure you get only one Fast Refresh runtime in the whole application.
106+
97107
## Middleware mode
98108

99109
In [middleware mode](https://vite.dev/config/server-options.html#server-middlewaremode), you should make sure your entry `index.html` file is transformed by Vite. Here's an example for an Express server:

packages/plugin-react/src/index.ts

+9
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,14 @@ export interface Options {
4949
babel?:
5050
| BabelOptions
5151
| ((id: string, options: { ssr?: boolean }) => BabelOptions)
52+
/**
53+
* React refresh runtime url prefix.
54+
* Useful in module federation context to enable HMR by
55+
* setting the host url on a vite config which is serving a remote app.
56+
* @example
57+
* reactRefreshHost: 'http://localhost:3000'
58+
*/
59+
reactRefreshHost?: string
5260
}
5361

5462
export type BabelOptions = Omit<
@@ -263,6 +271,7 @@ export default function viteReact(opts: Options = {}): PluginOption[] {
263271
result.map!,
264272
'@vitejs/plugin-react',
265273
id,
274+
opts.reactRefreshHost
266275
)
267276
}
268277
},

0 commit comments

Comments
 (0)