我的回答
HMR的本质使用fs.watch
创建了个服务器, 与浏览器通过ws协议进行连接, 一旦文件发生变化, 就会通过ws通知到浏览器, 然后通过jsonp的方式进行更新
参考回答
基础概念
- webpack compiler:将js编译成Bundle
- Bundle Server:提供文件在浏览器的访问,实际上就是一个服务器
- HMR Server:将热更新的文件输出给HMR Runtime
- HMR Runtime:会注入到bundle.js中,与HRM Server通过webSocket链接,接收文件变化,并更新对应文件
- bundle.js:构建输出的文件
原理
1.启动阶段
- webpack Compiler将对应文件打包成bundle.js(包含注入的HMR Server),发送给Bundler Server
- 浏览器即可访问服务器的方式去获取bundle.js
2.更新阶段(文件发生变化)
- webpack compiler重新编译,发送给HMR Server
- HMR Server可以知道有哪些资源、哪些模块发生了变化,通知HRM Runtime
-
HMR原理详解
使用webpack-dev-server去启动本地服务,内部实现只要使用了webpack、express、websocket
使用express启动本地服务,当浏览器访问资源时对此响应
- 服务端和客户端使用websocket实现长连接
- webpack监听源文件的变化,即当开发者保存文件时触发webpack的重新编译
- 每次编译都会生成hash值,已改动模块的json文件、已改动模块代码的js文件
- 编译完成后通过socket向客户端推送当前编译的hash戳
- 客户端的websocket监听到有文件改动推送过来的hash戳,会和上一次对比
- 一致就走缓存
- 不一致就通过ajax和jsonp向服务端获取最新资源
- 使用内存文件系统去替换有修改的内容实现局部刷新
1.server端
- 启动webpack-dev-server服务器
- 创建webpack实例
- 创建server服务器
- 添加webpack的done事件回调
- 编译完成向客户端发送消息
- 创建express应用app
- 设置文件系统为内存文件系统
- 添加webpack-dev-middleware中间件
- 中间件负责返回生成的文件
- 启动webpack编译
- 创建http服务器并启动服务
- 使用sockjs在浏览器端和服务端之间建立一个websocket长连接
- 创建socket服务器
2.client端
- webpack-dev-server/client端会监听到此hash消息
- 客户端收到ok消息后会执行reloadApp方法进行更新
- 在reloadApp中会进行判断,是否支持热更新,如果支持的话发生webpackHotUpdate事件,如果不支持就直接刷新浏览器
- 在webpack/hot/dev-server.js会监听webpackHotUpdate事件
- 在check方法里会调用module.hot.check方法
- HotModuleReplacement.runtime请求Manifest
- 通过调用JsonpMainTemplate.runtime的hotDownloadManifest方法
- 调用JsonpMainTemplate.runtime的hotDownloadUpdateChunk方法通过JSONP请求获取最新的模块代码
- 补丁js取回来或会调用JsonpMainTemplate.runtime.js的webpackHotUpdate方法
- 然后会调用HotModuleReplacement.runtime.js的hotAddUpdateChunk方法动态更新模块代码
- 然后调用hotApply方法进行热更新