Vite/Rollup 模块热更新

以下是关于 Vite/Rollup 模块热更新(HMR)原理的深度技术解析,从底层机制到高级实现全覆盖:


一、HMR 核心原理框架

1. 基础架构三要素
  • 客户端运行时(HMR Runtime)
    浏览器中的消息监听与模块更新执行器,通过 WebSocket 接收更新通知
  • 服务端驱动器(HMR Engine)
    文件变动监听 → 差异编译 → 更新消息推送的完整链路
  • 模块依赖图谱(Module Graph)
    记录模块间的动态/静态依赖关系,实现精准更新
2. 工作流程
文件系统 HMR Server 编译器 客户端 检测文件变更 增量编译 生成热更新包 通过WebSocket推送消息 执行模块替换(保留应用状态) 文件系统 HMR Server 编译器 客户端

二、Vite HMR 深度实现

1. 基于 ESM 的即时更新
  • 原生模块系统优势
    利用浏览器原生 import 机制实现按需加载,无需打包即可更新
    // 客户端接收更新后执行的典型代码
    import.meta.hot.accept('./module.js', (newModule) => {
      newModule.updatedFunction() // 执行新模块逻辑
    });
    
2. 核心模块解析
  • 中间件架构
    vite/src/node/server/index.ts 中的 HMR 服务入口
  • 模块热更新协议
    自定义消息格式示例:
    {
      "type": "update",
      "updates": [
        {
          "type": "js-update",
          "path": "/src/App.vue",
          "timestamp": 1627987312023
        }
      ]
    }
    
3. 关键源码路径
  • 服务端监听
    vite/src/node/server/moduleGraph.ts(模块依赖图维护)
  • 客户端响应
    vite/src/client/client.ts(WebSocket 消息处理)

三、Rollup 的 HMR 实现机制

1. 插件化实现
  • 依赖官方插件
    @rollup/plugin-hot 实现 HMR 基本功能
    // rollup.config.js
    import hot from '@rollup/plugin-hot';
    export default {
      plugins: [hot({})]
    };
    
2. 生命周期扩展
  • 自定义 Hooks
    通过 this.emitFile 触发资源更新
    function handleUpdate() {
      this.emitFile({
        type: 'asset',
        source: newContent,
        fileName: 'updated.js'
      });
    }
    
3. 与 Vite 的集成差异
  • 编译时处理
    Rollup 侧重打包时的模块替换策略
  • 运行时耦合
    Vite 直接利用浏览器能力实现细粒度更新

四、HMR 协议层详解

1. 消息类型
类型 作用 触发条件
connected 建立 WebSocket 连接 连接建立时
update 通知模块更新 文件修改
full-reload 强制整页刷新 HTML 模板修改或配置变更
prune 清理无效模块缓存 依赖关系变更时
2. 更新策略矩阵
模块类型 更新策略 状态保持方案
CSS 替换