代码地址请戳这里
HMR 是什么?
Hot Module Replacement 即模块热替换,是指当你的代码修改并保存以后 webpack 将会对代码进行重新打包,并将改动的模块发送到浏览器端,浏览器用新的模块替换掉旧的模块,实现局部更新 hot reload 而非整体的刷新页面 live reload。
基本原理
webpack 构建 bundle 的时候,加入一段 HMR runtime 的 js 和一段与服务器进行沟通的 js 。文件修改会触发 webpack 重新构建,服务器会向浏览器发送更新消息,浏览器通过 jsonp 拉取更新的模块文件,jsonp 回调触发模块热替换逻辑。
实现
- 服务器构建、推送更新消息
- 浏览器模块更新
- 模块更新后页面渲染
构建
构建过程中实现热加载的相关逻辑都在 HotModuleReplacementPlugin 这个 webpack 插件中,这个插件主要处理两部分逻辑:
- 注入 HMR runtime 逻辑
- 找到修改的模块,生成一个补丁 js 文件和更新描述 json 文件
如何找到修改的文件
webpack 在构建 chunk 过程中,会定义一个插件方法 additional-chunk-assets,在这个方法里面通过 md5 对比 hash 修改找到修改的模块,然后通过 hotUpdateChunkTemplate.render 生成一份更新的 js 文件,并且在 assets 中追加一份 json 描述文件说明更新了哪个模块以及更新的 hash。
服务器推送
- 文件更新后首先要打包好更新的文件,还需要告诉浏览器文件修改了可以拉代码了
- webpack 自带一个 dev-server,当开启热加载的时候 webpack-dev-server 会响应客户端发起的 EventStream 请求,然后保持请求不断开,这样服务器就可以在有更新的时候直接把结果 push 到浏览器。
React 热加载
react 热加载主要通过两个工具包来实现
- react-hot-loader 是一个 webpack 的 loader
- react-transform-hmr 是一个 react 的 babel 插件
react热加载的思路: 对每个组件进行一次包裹,组件更新后替换原有组件原型上的 render 方法和其他方法
css hot loader
- 开发环境关闭 extract-text-webpack-plugin
- 开启 style-loader 插件
总结
webpack 诞生于对 Code Splitting 特性的实现,从 webmake 重写为 webpack 。redux 诞生于 React 热加载探索过程中。Gaearon 首先实现了 React 的热加载,然后发现当时使用的 flux 无法热加载,因为 flux 有一个全局的 store ,action 都是通过消息来沟通,当这个对象替换的时候还需要重新绑定事件(flux还在 componentDidMount里面绑定,无法替换)。要实现热加载,就需要对 flux 进行改造,然后一步步删除 flux 中多余的部分,redux(reducer + flux) 就诞生了。redux 里面 reducer 、action 都是一个个纯函数,所以做替换是非常简单的。