Samgao0312 / Blog

MIT License
1 stars 1 forks source link

【积点成势】重学Webpack (3) —— webpack热更新 #150

Open Samgao0312 opened 2 years ago

Samgao0312 commented 2 years ago

1、什么是热更新

Webpack的热更新又称热替换(Hot Module Replacement),缩写为HMR。这个机制可以做到不用刷新浏览器而将新变更的模块替换掉旧的模块。

HMR的核心就是客户端从服务端拉取更新后的文件,准确的说是 chunk diff (chunk 需要更新的部分),实际上 WDS 与浏览器之间维护了一个Websocket,当本地资源发生变化时,WDS 会向浏览器推送更新,并带上构建时的 hash,让客户端与上一次资源进行对比。客户端对比出差异后会向 WDS 发起Ajax请求来获取更改内容(文件列表、hash),这样客户端就可以再借助这些信息继续向 WDS 发起 jsonp 请求获取该 chunk 的增量更新。

在 Webpack 中配置开启热模块也非常的简单,只需要添加如下代码即可。

const webpack = require('webpack')
module.exports = {
  // ...
  devServer: {
    // 开启 HMR 特性
    hot: true
    // hotOnly: true
  }
}

需要说明的是,实现热更新还需要去指定哪些模块发生更新时进行 HRM,因为默认情况下,HRM只对css文件有效。

if(module.hot){
    module.hot.accept('./util.js',()=>{
        console.log("util.js更新了")
    })
}

2、实现原理

首先,我们来看一张图: image

上面图中涉及了很多不同的概念,如下:

整个流程,我们可以将它分为两个阶段:启动阶段更新阶段。

由于 socket 服务器在 HMR Runtime 和 HMR Server 之间建立 websocket 链接,当文件发生改动的时候,服务端会向浏览器推送一条消息,消息包含文件改动后生成的 hash 值,如下图的 h 属性,作为下一次热更细的标识。

image

在浏览器接受到这条消息之前,浏览器已经在上一次 socket 消息中已经记住了此时的 hash 标识,这时候我们会创建一个 ajax 去服务端请求获取到变化内容的 manifest 文件。mainfest文件包含重新 build 生成的 hash 值,以及变化的模块,对应上图的 c 属性。浏览器根据 manifest 文件获取模块变化的内容,从而触发 render 流程,实现局部模块更新。

image

3、总结

通过前面的分析,总结 Webpack 热模块的步骤如下: