/
fast-refresh.ts
113 lines (99 loc) · 2.94 KB
/
fast-refresh.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import fs from 'node:fs'
import path from 'node:path'
import { createRequire } from 'node:module'
export const runtimePublicPath = '/@react-refresh'
const _require = createRequire(import.meta.url)
const reactRefreshDir = path.dirname(
_require.resolve('react-refresh/package.json'),
)
const runtimeFilePath = path.join(
reactRefreshDir,
'cjs/react-refresh-runtime.development.js',
)
export const runtimeCode = `
const exports = {}
${fs.readFileSync(runtimeFilePath, 'utf-8')}
function debounce(fn, delay) {
let handle
return () => {
clearTimeout(handle)
handle = setTimeout(fn, delay)
}
}
exports.performReactRefresh = debounce(exports.performReactRefresh, 16)
export default exports
`
export const preambleCode = `
import RefreshRuntime from "__BASE__${runtimePublicPath.slice(1)}"
RefreshRuntime.injectIntoGlobalHook(window)
window.$RefreshReg$ = () => {}
window.$RefreshSig$ = () => (type) => type
window.__vite_plugin_react_preamble_installed__ = true
`
const header = `
import RefreshRuntime from "${runtimePublicPath}";
let prevRefreshReg;
let prevRefreshSig;
if (import.meta.hot) {
if (!window.__vite_plugin_react_preamble_installed__) {
throw new Error(
"@vitejs/plugin-react can't detect preamble. Something is wrong. " +
"See https://github.com/vitejs/vite-plugin-react/pull/11#discussion_r430879201"
);
}
prevRefreshReg = window.$RefreshReg$;
prevRefreshSig = window.$RefreshSig$;
window.$RefreshReg$ = (type, id) => {
RefreshRuntime.register(type, __SOURCE__ + " " + id)
};
window.$RefreshSig$ = RefreshRuntime.createSignatureFunctionForTransform;
}`.replace(/\n+/g, '')
const timeout = `
if (!window.__vite_plugin_react_timeout) {
window.__vite_plugin_react_timeout = setTimeout(() => {
window.__vite_plugin_react_timeout = 0;
RefreshRuntime.performReactRefresh();
}, 30);
}
`
const checkAndAccept = `
function isReactRefreshBoundary(mod) {
if (mod == null || typeof mod !== 'object') {
return false;
}
let hasExports = false;
let areAllExportsComponents = true;
for (const exportName in mod) {
hasExports = true;
if (exportName === '__esModule') {
continue;
}
const desc = Object.getOwnPropertyDescriptor(mod, exportName);
if (desc && desc.get) {
// Don't invoke getters as they may have side effects.
return false;
}
const exportValue = mod[exportName];
if (!RefreshRuntime.isLikelyComponentType(exportValue)) {
areAllExportsComponents = false;
}
}
return hasExports && areAllExportsComponents;
}
import.meta.hot.accept(mod => {
if (isReactRefreshBoundary(mod)) {
${timeout}
} else {
import.meta.hot.invalidate();
}
});
`
const footer = `
if (import.meta.hot) {
window.$RefreshReg$ = prevRefreshReg;
window.$RefreshSig$ = prevRefreshSig;
${checkAndAccept}
}`
export function addRefreshWrapper(code: string, id: string): string {
return header.replace('__SOURCE__', JSON.stringify(id)) + code + footer
}