webpack热更新原理

核心流程

Webpack HMR 特性的执行过程并不复杂:

  1. 使用 webpack-dev-server (后面简称 WDS)托管静态资源,同时以 Runtime 方式向主chunk注入一段处理 HMR 逻辑的客户端代码;
  2. 浏览器加载页面后,与 WDS 建立 WebSocket 连接;
  3. Webpack 监听到文件变化后,增量构建发生变更的模块,并通过 WebSocket 发送 hash 事件;
  4. 浏览器接收到 hash 事件后,请求 manifest 资源文件,确认增量变更范围;
  5. 浏览器加载发生变更的增量模块;
  6. Webpack 运行时触发变更模块的 module.hot.accept 回调,执行代码变更逻辑;

hmr运行时代码

import './a.js'
if(module.hot) {
    module.hot.accept('./a.js', () => {
        console.log('捕获到a.js变化')
        let el = document.getElementById('a')
        if(el) {
            el.parentNode.removeChild(el)
        }
    })
}

webapck热更新和vite的区别

  • webpack热更要重新构建,意思就是重新打包,性能会随项目规模大而变慢。
  • vite本身基于unbundle的思想,利用的是type=module的js加载原理,某个文件改动很容易的确认出hrm的边界,也不需要重新构建整个项目,直接更新单个文件即可。

webpack

  • 当基于打包器启动时,编辑文件后将重新构建文件本身。显然我们不应该重新构建整个包,因为这样更新速度会随着应用体积增长而直线下降。
  • 一些打包器的开发服务器将构建内容存入内存,这样它们只需要在文件更改时使模块图的一部分失活,但它也仍需要整个重新构建并重载页面。这样代价很高,并且重新加载页面会消除应用的当前状态,所以打包器支持了动态模块热重载(HMR):允许一个模块 “热替换” 它自己,而对页面其余部分没有影响。这大大改进了开发体验 - 然而,在实践中我们发现,即使是 HMR 更新速度也会随着应用规模的增长而显著下降。

vite改进

  • 在 Vite 中,HMR 是在原生 ESM 上执行的。当编辑一个文件时,

Vite 只需要精确地使已编辑的模块与其最近的 HMR 边界之间的链失效(大多数时候只需要模块本身),使 HMR 更新始终快速,无论应用的大小。

  • Vite 同时利用 HTTP 头来加速整个页面的重新加载(再次让浏览器为我们做更多事情):源码模块的请求会根据 304 Not Modified 进行协商缓存,而依赖模块请求则会通过 Cache-Control: max-age=31536000,immutable 进行强缓存,因此一旦被缓存它们将不需要再次请求。