热更新傻傻分不清:Webapck HMR vs React-Hot-Loader

简介: 大家好,我是海怪。最近发现接手的项目里一直有用 react-hot-loader 这个库,然后我就想:Webpack 不是已经有了一个 HMR(Hot Module Replacement) 的玩意了么?还要这个 loader 干啥的?然后搜到了这篇文章:Blogged Answers: Webpack HMR vs React-Hot-Loader这是一篇关于 HMR 和 react-hot-loader 的对比总结,里面讲得还比较清楚,下面给大家分享一下。

image.png

大家好,我是海怪。

最近发现接手的项目里一直有用 react-hot-loader 这个库,然后我就想:Webpack 不是已经有了一个 HMR(Hot Module Replacement) 的玩意了么?还要这个 loader 干啥的?

然后搜到了这篇文章:Blogged Answers: Webpack HMR vs React-Hot-Loader

这是一篇关于 HMR 和 react-hot-loader 的对比总结,里面讲得还比较清楚,下面给大家分享一下。


前言


很多人在构建 React 热更新的时候经常被 Webpack 的 HMR 搞蒙逼。一个经常容易把人搞蒙的点就是:以为要用 react-hot-loader 来打开 HMR,然而事实并不是这样,下面我就来对比一下他们的不同点。


HMR


Hot Module Replacement(HMR) 其实是 Webpack 自带的功能,通过

module.hot.accept 来实现。它的原理是:当项目里的文件被重新编译的时候,在 HMR 注册的一回调就会被执行:


  • 除了项目里的入口文件,你要把 HMR client 代码也要作为入口文件。当然,这部分的 client 代码占很小一块,它只是负责打开 WebSocket,并连接上 Webpack dev server
  • 入口调用 module.hot.accept("./someFileName", callbackToRunWhenThatFileIsRecompiled)
  • Webpack dev server 会自动监听文件变化,当保存的时候自动重新编译
  • 重新编译后,发消息通知 client,告诉它哪些文件重新编译了,以及最新版本的代码
  • client 会根据重新编译的文件路径来执行 module.hot.accept()回调函数


关于最后一点的 回调函数 要如何实现完全在于你自己。不过,一般的实现方式都是重新 import 变更的文件,并更换掉变更的代码部分,比如 React 组件、Redux 的 reducer 之类的。


如果你只要用这种 "plain HMR" 的话,只需要写一两行的 module.hot.accept() 就完事了:一个用来更新整个 React 根组件,另一个用来更新根 Reducer 文件。

可以看到,上面并没有使用 react-hot-loader 这个玩意!!只需要 Webpack 就可以实现了。


react-hot-loader


react-hot-loader 也是使用了 Webpack 的 HMR API,但是在实现方式上更复杂和强大!


RHL(react-hot-laoder) 会用一个 "proxy" Component(代理组件)包裹你的组件代码。这些 Proxy Component 会更细粒度地调用 module.hot.accept() API 来抓取每个组件的更新,而不会让这些更新 “冒泡” 到根组件。


同时,这些 Proxy Component 还会拥有自己的状态管理机制,来管理被包裹的真实 React 组件。所以,当你代码改了之后,组件的状态还是会保留下来,而不会重新 “刷新”。


文章总结


RHL 还是挺好的...当它没报错的时候。但是,热更新这样的使用场景有太多的边界 case 了,RHL 也不可能囊括这么多 case,所以在使用的时候也会出现很多问题。


比如更改构建配置就可能使得 RHL 不能正常工作。这也是为什么 Dan Abramov 不再继续去搞 RHL,而是在 Create-React-App 里提供一个更稳定、持续、公开的配置环境作为基线,方便之后实现更“聪明”的热更新机制。


我自己来说还是不推荐使用 RHL,而使用原生的 "plain HMR" 就好了。虽然使用 "plain HMR" 在热更新的时候不会保留原来组件的状态,但是它的工作方式更简单粗暴,没那么多花里胡哨的东西。当然 Redux 也对 "plain HMR" 非常友好的,因为在热更新的时候 Redux 的状态一直都会在那,所以 React 组件在重新渲染的时候还是可以使用上次的 Redux 状态。


我的想法


当然上面这篇文章是 17 年写的,现在 Webpack 已经将 module.hot.accept 内置到配置中了,使用上也不用自己调用 API 了。而且 react-hot-loader 也发展了比较久了,很多问题也解决了不少。


个人觉得如果 react-hot-loader 还是值得一试的,如果没有太多问题的情况下。。实在不行就用原生的 HMR 喽。


不过目前发现 react-router 的 v6.x 版本和 react-hot-loader 不太兼容。刚不是说 react-hot-loader 会包一层 Proxy 组件么?在使用

<Routes>
    <Route></Route>
</Routes>
复制代码

的时候 Route 被包裹了 Proxy Component,而 v6.x 的 Routes 组件只能允许 Route 作为自己的儿子组件,所以会报: Error: [ProxyFacade] is not a component. All component children of must be a or <React.Fragment>


相关文章
|
2月前
|
前端开发 JavaScript
React项目路由懒加载lazy、Suspense,使第一次打开项目页面变快
本文介绍了在React项目中实现路由懒加载的方法,使用React提供的`lazy`和`Suspense`来优化项目首次加载的速度。通过将路由组件改为懒加载的方式,可以显著减少初始包的大小,从而加快首次加载速度。文章还展示了如何使用`Suspense`组件包裹`Switch`来实现懒加载过程中的fallback效果,并提供了使用前后的加载时间对比,说明了懒加载对性能的提升作用。
130 2
React项目路由懒加载lazy、Suspense,使第一次打开项目页面变快
|
5月前
|
前端开发
react怎么做图片报错处理
react怎么做图片报错处理
68 1
|
11月前
|
SQL 资源调度 前端开发
VUE3(三十四)项目启动sass报错
我有个不是很好的习惯,每天启动前端项目的时候,都会把项目中使用到的组件更新到最新的版本。其实这样是非常不好的。为什么呢?新版本除了修复之前的问题,也有可能会带来新的问题。 正常的做法大概是,等新版本发布了一段时间之后,再去更新,这样就相对保险一丢丢。 而且,目前前端项目中组件依赖太多,各个组件之间,难免会有兼容性的问题。今天在将组件更新到最新版本之后,启动项目,就遇到了问题。 报错如下: bash 复制代码 ERROR in ./src/pages/porder/index.scss (./node_modules/css-loader/dist/cjs.js!./node_modules/s
274 1
|
Web App开发 前端开发 JavaScript
UMD 被淘汰了吗?不考虑的 UMD 的库如何在纯 UMD 前端项目中运行?
UMD 被淘汰了吗?不考虑的 UMD 的库如何在纯 UMD 前端项目中运行?
229 0
|
前端开发
#yyds干货盘点 【React工作记录三十一】dva.js初识
#yyds干货盘点 【React工作记录三十一】dva.js初识
96 0
#yyds干货盘点 【React工作记录三十一】dva.js初识
|
存储 前端开发
#yyds干货盘点 【React工作记录二十九】react中使用的富文本编辑器braft-editor使用
#yyds干货盘点 【React工作记录二十九】react中使用的富文本编辑器braft-editor使用
146 0
#yyds干货盘点 【React工作记录二十九】react中使用的富文本编辑器braft-editor使用
|
缓存 JavaScript
本想搞清楚ESM和CJS模块的互相转换问题,没想到写完我的问题更多了
本来只是好奇打包工具是如何转换ESM和CJS模块的,没想到带着这个问题阅读完编译的代码后,我的问题更多了。
382 0
|
前端开发 JavaScript API
咱就是说,瞧瞧这React的Hooks的由来
咱就是说,瞧瞧这React的Hooks的由来
126 0
咱就是说,瞧瞧这React的Hooks的由来
|
前端开发 程序员 API
再谈 babel 7.18.0 引发的问题
本文约 3800 字,阅读时长约 20min,有一定阅读门槛。阅读开始前你需要了解的
1331 0
再谈 babel 7.18.0 引发的问题
|
前端开发 中间件
挑战21天手写前端框架 day7 使用 Socket 实现 esbuild 的热加载服务 hmr
挑战21天手写前端框架 day7 使用 Socket 实现 esbuild 的热加载服务 hmr
460 0
挑战21天手写前端框架 day7 使用 Socket 实现 esbuild 的热加载服务 hmr