如何使用React Fast Refresh
react-refresh
是react官方实现的热替换方案,用于替换其他的方案,如react-hot-loader
等。在项目中使用react-refresh(webpack)
在babel配置中,需要添加babel插件
react-refresh/babel
。添加全局代码。
// global
if (
process.env.NODE_ENV !== 'production'
&& typeof window !== 'undefined'
&& !window.$RefreshInstall$
&& module.hot
) {
const ReactRefresh = require('react-refresh/runtime');
ReactRefresh.injectIntoGlobalHook(window);
window.$RefreshReg$ = () => {};
window.$RefreshSig$ = () => (type) => type;
window.$RefreshTime$ = null;
window.$RefreshInstall$ = true;
}
在组件代码的头和尾添加代码。
/* 代码头部添加 */
let __$prevRefreshReg$__;
let __$prevRefreshSig$__;
if (
process.env.NODE_ENV !== 'production'
&& typeof window !== 'undefined'
&& module.hot
) {
__$prevRefreshReg$__ = window.$RefreshReg$;
__$prevRefreshSig$__ = window.$RefreshSig$;
const ReactRefresh = require('react-refresh/runtime');
window.$RefreshReg$ = (type, id) => {
const fullId = module.id + ' ' + id;
ReactRefresh.register(type, fullId);
}
window.$RefreshSig$ = ReactRefresh.createSignatureFunctionForTransform;
}
// ====================
// Your Code
// ====================
/* 代码尾部添加 */
if (
process.env.NODE_ENV !== 'production'
&& typeof window !== 'undefined'
&& module.hot
) {
const ReactRefresh = require('react-refresh/runtime');
window.$RefreshReg$ = __$prevRefreshReg$__;
window.$RefreshSig$ = __$prevRefreshSig$__;
module.hot.accept();
if (window.$RefreshTime$ === null) {
window.$RefreshTime$ = setTimeout(() => {
window.$RefreshTime$ = null;
ReactRefresh.performReactRefresh();
}, 30);
}
}
这段代码必须在被
react-refresh/babel
编译后的代码之前,否则不生效。所以在webpack中,可以通过开发loader,来添加这段代码。
function ReactRefreshLoader(source, sourcemap) {
const callback = this.async();
let sourceData = source;
if (source.includes('= $RefreshSig$()')) {
sourceData = `${ ReactRefreshPrev }\n\n${ source }\n\n${ ReactRefreshEnd }`;
}
callback(null, sourceData, sourcemap);
}
module.exports = ReactRefreshLoader;
也可以通过
string-replace-loader
来注入这段代码。module.exports = {
module: {
rules: [
{
test: /^.*\.jsx?$/i,
use: [
{
loader: 'string-replace-loader',
options: {
search: /^(\s|.)*$/,
replace(match) {
if (match.includes('= $RefreshSig$()')) {
return `${ ReactRefreshPrev }\n\n${ match }\n\n${ ReactRefreshEnd }`;
}
return match;
}
}
},
{
loader: 'babel-loader',
options: {
presets: [
['@babel/preset-react', {
runtime: 'automatic',
development: true
}]
],
plugins: ['react-refresh/babel'],
exclude: /node_modules/
}
}
]
}
]
}
};