HMR

205 阅读2分钟

HMR(hot module replacement)

推荐雪凌老师好文

优点

  1. 保留应用程序状态
  2. 只变更修改的内容,节省开发时间
  3. 在源代码中修改js/css,可以立马体现在浏览器中。相当于在浏览器devtools直接修改

对应插件

HotModulePlacementPlugin

热更新原理

  1. 我们一般使用webpack-dev-server(WDS)通过nodejs-Express启动一个开发服务,webpack内部实现一个watch,文件发生修改后重新打包并放入内存。
  2. WDS依赖中间件webpack-dev-middleware和webpack之间交互。主要通过调用webpack暴露的API(compiler.watch)对代码进行监控
  3. WDS和浏览器之间建立了websocket长连接。socket注册了两个监听事件:hash(提供最新一次的hash值)和ok(进行热更新检测),主要是用来将webpack编译打包的各个阶段状态消息告知浏览器
// 通过websoket给客户端发消息 
_sendStats() {
    this.sockWrite(sockets, 'hash', stats.hash);
    this.sockWrite(sockets, 'ok');
}
  1. 如果文件变化了,没有配置热更新,WDS会通知浏览器进行刷新(location.reload)

  2. 如果有热更新

    5.1.当本地资源更新后,WDS向浏览器推送更新消息,并带上构建的hash值

    5.2.客户端向server发送ajax请求,server返回一个json,里面包含了所有要更新的模块的hash值

    5.3.获取到需要更新的列表后,客户端再次发送jsonp请求,利用script脚本,获取替换最新的更新模块代码

  3. 如果热更新失败,回退到live reload操作,就是直接location.reload

配置
方法一

利用 devServer.hot = true

    module.exports = {
        //...
        devServer: {
            hot: true
        }
    }

注意:必须有webpack.HotModuleReplacementPlugin才能完全启用HMR。如果webpack或webpack-dev-server是通过--hot选项启动的。那么这个插件会自动被添加。

{
    "start": "webpack-dev-server --hot --open"
}
方法二

利用plugin中添加依赖HotModuleReplacementPlugin插件。这里和方法一差不多一个意思

plugins: [
    //...
    new webpack.HotModuleReplacementPlugin()
]
方法三 react-hot-loader

这个loader也是官方推荐 利用 react-hot-loader导入AppContainer组件。这里主要记住这个loader就好.

引入这个loader,需要配合react-app-rewire-hot-loader

import { AppContainer } from "react-hot-loader"
const render = Component => {
    ReactDOM.render(
        <Provider store={store}>
            <AppContainer>
                <Component/>
            </AppContainer>
        </Provider>
    ),
    document.getElementById("root")
}

    render(App);
    if (module.hot) {
        module.hot.accept("./App", () => {
            const nextApp = require("./App").default;
            render(nextApp);
        })
    }