我的回答
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方法进行热更新
 
