webpack热更新原理
核心流程
Webpack HMR 特性的执行过程并不复杂:
- 使用
webpack-dev-server
(后面简称 WDS)托管静态资源,同时以Runtime
方式向主chunk注入一段处理HMR
逻辑的客户端代码; - 浏览器加载页面后,与
WDS
建立WebSocket
连接; - Webpack 监听到文件变化后,增量构建发生变更的模块,并通过
WebSocket
发送hash
事件; - 浏览器接收到 hash 事件后,请求
manifest
资源文件,确认增量变更范围; - 浏览器加载发生变更的增量模块;
- 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 进行强缓存,因此一旦被缓存它们将不需要再次请求。