如何使用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/ } } ] } ] } };