Skip to content

Commit 4544e97

Browse files
feat: update refresh utils for React Router 7 support (#363)
Co-authored-by: 翠 / green <green@sapphi.red>
1 parent d88c581 commit 4544e97

File tree

3 files changed

+42
-18
lines changed

3 files changed

+42
-18
lines changed

packages/plugin-react/src/fast-refresh.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,17 @@ if (import.meta.hot && !inWebWorker) {
5858
window.$RefreshReg$ = prevRefreshReg;
5959
window.$RefreshSig$ = prevRefreshSig;
6060
}`
61-
const sharedFooter = `
61+
const sharedFooter = (id: string) => `
6262
if (import.meta.hot && !inWebWorker) {
6363
RefreshRuntime.__hmr_import(import.meta.url).then((currentExports) => {
64-
RefreshRuntime.registerExportsForReactRefresh(__SOURCE__, currentExports);
64+
RefreshRuntime.registerExportsForReactRefresh(${JSON.stringify(
65+
id,
66+
)}, currentExports);
6567
import.meta.hot.accept((nextExports) => {
6668
if (!nextExports) return;
67-
const invalidateMessage = RefreshRuntime.validateRefreshBoundaryAndEnqueueUpdate(currentExports, nextExports);
69+
const invalidateMessage = RefreshRuntime.validateRefreshBoundaryAndEnqueueUpdate(${JSON.stringify(
70+
id,
71+
)}, currentExports, nextExports);
6872
if (invalidateMessage) import.meta.hot.invalidate(invalidateMessage);
6973
});
7074
});
@@ -76,15 +80,13 @@ export function addRefreshWrapper(code: string, id: string): string {
7680
functionHeader.replace('__SOURCE__', JSON.stringify(id)) +
7781
code +
7882
functionFooter +
79-
sharedFooter.replace('__SOURCE__', JSON.stringify(id))
83+
sharedFooter(id)
8084
)
8185
}
8286

8387
export function addClassComponentRefreshWrapper(
8488
code: string,
8589
id: string,
8690
): string {
87-
return (
88-
sharedHeader + code + sharedFooter.replace('__SOURCE__', JSON.stringify(id))
89-
)
91+
return sharedHeader + code + sharedFooter(id)
9092
}

packages/plugin-react/src/refreshUtils.js

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,14 @@ function debounce(fn, delay) {
77
}
88

99
/* eslint-disable no-undef */
10-
const enqueueUpdate = debounce(exports.performReactRefresh, 16)
10+
const hooks = []
11+
window.__registerBeforePerformReactRefresh = (cb) => {
12+
hooks.push(cb)
13+
}
14+
const enqueueUpdate = debounce(async () => {
15+
if (hooks.length) await Promise.all(hooks.map((cb) => cb()))
16+
exports.performReactRefresh()
17+
}, 16)
1118

1219
// Taken from https://github.com/pmmmwh/react-refresh-webpack-plugin/blob/main/lib/runtime/RefreshUtils.js#L141
1320
// This allows to resister components not detected by SWC like styled component
@@ -25,36 +32,51 @@ function registerExportsForReactRefresh(filename, moduleExports) {
2532
}
2633
}
2734

28-
function validateRefreshBoundaryAndEnqueueUpdate(prevExports, nextExports) {
29-
if (!predicateOnExport(prevExports, (key) => key in nextExports)) {
35+
function validateRefreshBoundaryAndEnqueueUpdate(id, prevExports, nextExports) {
36+
const ignoredExports = window.__getReactRefreshIgnoredExports?.({ id }) ?? []
37+
if (
38+
predicateOnExport(
39+
ignoredExports,
40+
prevExports,
41+
(key) => key in nextExports,
42+
) !== true
43+
) {
3044
return 'Could not Fast Refresh (export removed)'
3145
}
32-
if (!predicateOnExport(nextExports, (key) => key in prevExports)) {
46+
if (
47+
predicateOnExport(
48+
ignoredExports,
49+
nextExports,
50+
(key) => key in prevExports,
51+
) !== true
52+
) {
3353
return 'Could not Fast Refresh (new export)'
3454
}
3555

3656
let hasExports = false
3757
const allExportsAreComponentsOrUnchanged = predicateOnExport(
58+
ignoredExports,
3859
nextExports,
3960
(key, value) => {
4061
hasExports = true
4162
if (exports.isLikelyComponentType(value)) return true
4263
return prevExports[key] === nextExports[key]
4364
},
4465
)
45-
if (hasExports && allExportsAreComponentsOrUnchanged) {
66+
if (hasExports && allExportsAreComponentsOrUnchanged === true) {
4667
enqueueUpdate()
4768
} else {
48-
return 'Could not Fast Refresh. Learn more at https://github.com/vitejs/vite-plugin-react/tree/main/packages/plugin-react#consistent-components-exports'
69+
return `Could not Fast Refresh ("${allExportsAreComponentsOrUnchanged}" export is incompatible). Learn more at https://github.com/vitejs/vite-plugin-react/tree/main/packages/plugin-react#consistent-components-exports`
4970
}
5071
}
5172

52-
function predicateOnExport(moduleExports, predicate) {
73+
function predicateOnExport(ignoredExports, moduleExports, predicate) {
5374
for (const key in moduleExports) {
5475
if (key === '__esModule') continue
76+
if (ignoredExports.includes(key)) continue
5577
const desc = Object.getOwnPropertyDescriptor(moduleExports, key)
56-
if (desc && desc.get) return false
57-
if (!predicate(key, moduleExports[key])) return false
78+
if (desc && desc.get) return key
79+
if (!predicate(key, moduleExports[key])) return key
5880
}
5981
return true
6082
}

playground/react/__tests__/react.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ if (!isBuild) {
7878
code.replace('An Object', 'Updated'),
7979
),
8080
[
81-
'[vite] invalidate /hmr/no-exported-comp.jsx: Could not Fast Refresh. Learn more at https://github.com/vitejs/vite-plugin-react/tree/main/packages/plugin-react#consistent-components-exports',
81+
'[vite] invalidate /hmr/no-exported-comp.jsx: Could not Fast Refresh ("Foo" export is incompatible). Learn more at https://github.com/vitejs/vite-plugin-react/tree/main/packages/plugin-react#consistent-components-exports',
8282
'[vite] hot updated: /hmr/no-exported-comp.jsx',
8383
'[vite] hot updated: /hmr/parent.jsx',
8484
'Parent rendered',
@@ -103,7 +103,7 @@ if (!isBuild) {
103103
code.replace('context provider', 'context provider updated'),
104104
),
105105
[
106-
'[vite] invalidate /context/CountProvider.jsx: Could not Fast Refresh. Learn more at https://github.com/vitejs/vite-plugin-react/tree/main/packages/plugin-react#consistent-components-exports',
106+
'[vite] invalidate /context/CountProvider.jsx: Could not Fast Refresh ("CountContext" export is incompatible). Learn more at https://github.com/vitejs/vite-plugin-react/tree/main/packages/plugin-react#consistent-components-exports',
107107
'[vite] hot updated: /context/CountProvider.jsx',
108108
'[vite] hot updated: /App.jsx',
109109
'[vite] hot updated: /context/ContextButton.jsx',

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy