前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >热更新(HMR)相关原理介绍

热更新(HMR)相关原理介绍

作者头像
前端知知
发布2022-09-29 19:15:15
7160
发布2022-09-29 19:15:15
举报
文章被收录于专栏:前端知知前端知知

在有些项目中,我们会遇到某些页面由特别多的模块组成,比如m1,m2,m3...mn

在开发工程中,如果我们修改了其中一个模块,页面都是重新加载,那么之前填写的数据都清空了。测试整体流程又需要重新填写数据,过程比较繁琐。那能否实现某个模块更新而又不清空其他模块的数据呢,其实就是webpack 实现的热更新功能。

定义

热更新(HMR: Hot Module Replacement)指当对代码修改并保存后,webpack将会对代码进行重新打包,并将改动的模块发送到浏览器端,浏览器用新的模块替换掉旧的模块,去实现局部更新页面。我们看下面的一个例子。

与监听代码变更刷新整个页面不同,HMR具有以下两个特征:

  • 不需要刷新页面,
  • 可以保存应用的当前状态

实现原理

要实现更新,需要解决两个问题,一个是服务端能将更新资源实时推送给浏览器;另一个是浏览器实现局部更新。

1.通知浏览器端文件发生改变

在开发中通常使用的http协议,但是HTTP 协议有一个缺陷:通信只能由客户端发起。我们也可以通过轮询来实现,但是效率低下,而且浪费资源。这个时候 websoket[1] 应运而生。websocket的最大特点是服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,实现双向通信息;在webpack 中,就是使用websocket ,以下是具体实现:

代码语言:javascript
复制
// server.js
createSocketServer() {
 // 实现一个websocket长链接
    const io = socket(this.server);
    io.on("connection", (socket) => {
    console.log("a new client connect server");

    this.clientSocketList.push(socket);
    socket.on("disconnect", () => {
        let num = this.clientSocketList.indexOf(socket);
        this.clientSocketList = this.clientSocketList.splice(num, 1);
    });
    // 向客户端发送最新的一个编译hash
    socket.emit('hash', this.currentHash);
        // 再向客户端发送一个ok
        socket.emit('ok');
    });
}

代码语言:javascript
复制
// client/index.js
const onSocketMessage = {
 hash(hash) {
        console.log("hash",hash);
        currentHash = hash;// 获取最新hash
    },
 ok() {
        console.log("ok");  
        reloadApp();// 开始热更新
    },
 connect() {
        console.log("client connect successful");
    }
};

2.浏览器端实现更新

在浏览器端收到服务端资源更新通知后,会进行以下步骤:

  • 使用XHR 拉取更新的模块和文件hash
代码语言:javascript
复制
let hotDownloadManifest = () => {
    return new Promise((resolve, reject) => {
        let xhr = new XMLHttpRequest();
        let hotUpdatePath = `${lastHash}.hot-update.json`
        xhr.open("get", hotUpdatePath);
        xhr.onload = () => {
            let hotUpdate = JSON.parse(xhr.responseText);
            // {"h":"58ddd9a7794ab6f4e750","c":{"main":true}}
            resolve(hotUpdate);
        };
        xhr.onerror = (error) => {
            reject(error);
        }
        xhr.send();
    })
}

  • 根据获取的hash 和chunkId拉取最新的js 代码,此时使用的是JSONP,可以即刻执行js代码。
代码语言:javascript
复制
let hotDownloadUpdateChunk = (chunkID) => {
    let script = document.createElement("script")
    script.charset = "utf-8";
    //chunkID.xxxlasthash.hot-update.js
    script.src = `${chunkID}.${lastHash}.hot-update.js`
    document.head.appendChild(script);
}

  • webpackHotUpdate实现热更新
代码语言:javascript
复制
window.webpackHotUpdate = (chunkID, moreModules) => {
      // 循环新拉来的模块
    Object.keys(moreModules).forEach(moduleID => {
        // 1、通过__webpack_require__.c 模块缓存可以找到旧模块
        let oldModule = __webpack_require__.c[moduleID];

        // 2、更新__webpack_require__.c,利用moduleID将新的拉来的模块覆盖原来的模块
        let newModule = __webpack_require__.c[moduleID] = {
            i: moduleID,
            l: false,
            exports: {},
            hot: hotCreateModule(moduleID),
            parents: oldModule.parents,
            children: oldModule.children
        };

        // 3、执行最新编译生成的模块代码
        moreModules[moduleID].call(newModule.exports, newModule, newModule.exports, __webpack_require__);
        newModule.l = true;

        // 4、让父模块中存储的_acceptedDependencies执行
        newModule.parents && newModule.parents.forEach(parentID => {
            let parentModule = __webpack_require__.c[parentID];
            parentModule.hot._acceptedDependencies[moduleID] && parentModule.hot._acceptedDependencies[moduleID]()
        });
    })
}

总结

本文主要讲了热更新的实现要点:使用websoket 进行通信;使用jsonp拉取更新模块执行。如果想了解更多,欢迎读者去阅读相关源码。

[1]阮一峰,WebSocket 教程: http://www.ruanyifeng.com/blog/2017/05/websocket.html

[2]https://zhuanlan.zhihu.com/p/138446061

[3]https://juejin.cn/post/6844904020528594957#heading-59

[4]https://segmentfault.com/a/1190000020310371

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-06-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端知知 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 定义
  • 实现原理
    • 1.通知浏览器端文件发生改变
      • 2.浏览器端实现更新
      • 总结
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档