我的回答

HMR的本质使用fs.watch
创建了个服务器, 与浏览器通过ws协议进行连接, 一旦文件发生变化, 就会通过ws通知到浏览器, 然后通过jsonp的方式进行更新

module.hot.accept的方式进行热更新

参考回答

基础概念

  1. webpack compiler:将js编译成Bundle
  2. Bundle Server:提供文件在浏览器的访问,实际上就是一个服务器
  3. HMR Server:将热更新的文件输出给HMR Runtime
  4. HMR Runtime:会注入到bundle.js中,与HRM Server通过webSocket链接,接收文件变化,并更新对应文件
  5. bundle.js:构建输出的文件

    原理

    1.启动阶段
  • webpack Compiler将对应文件打包成bundle.js(包含注入的HMR Server),发送给Bundler Server
  • 浏览器即可访问服务器的方式去获取bundle.js

2.更新阶段(文件发生变化)

  • webpack compiler重新编译,发送给HMR Server
  • HMR Server可以知道有哪些资源、哪些模块发生了变化,通知HRM Runtime
  • 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方法进行热更新