Skip to content
On this page

vite(HMR)

很久之前,我们是通过 live reload 也就是自动刷新页面的方式来解决的。不过随着前端工程的日益庞大,开发场景也越来越复杂,这种live reload的方式在诸多的场景下却显得十分鸡肋,简单来说就是模块局部更新+状态保存的需求在live reload的方案没有得到满足

深入 HMR API

HMR 的技术我们就可以实现局部刷新状态保存

ts
interface ImportMeta {
  readonly hot?: {
    readonly data: any;
    accept(): void;
    accept(cb: (mod: any) => void): void;
    accept(dep: string, cb: (mod: any) => void): void;
    accept(deps: string[], cb: (mods: any[]) => void): void;
    prune(cb: () => void): void;
    dispose(cb: (data: any) => void): void;
    decline(): void;
    invalidate(): void;
    on(event: string, cb: (...args: any[]) => void): void;
  };
}

模块更新时逻辑: hot.accept

用来接受模块更新

  • 接受自身模块的更新
  • 接受某个子模块的更新
  • 接受多个子模块的更新 相当于拦截了代码变动导致页面刷新,而且将怎么刷新的过程交给我们

1. 接受自身更新

import.meta.hot.accept((mod) => mod.render())

2. 接受依赖模块的更新

// main.ts
import { render } from './render';
import './state';
render();
+if (import.meta.hot) {
+  import.meta.hot.accept('./render.ts', (newModule) => {
+    newModule.render();
+  })
+}

3. 接受多个子模块的更新

// main.ts
import { render } from './render';
import { initState } from './state';
render();
initState();
if (import.meta.hot) {
  import.meta.hot.accept(['./render.ts', './state.ts'], (modules) => {
    // 自定义更新
    const [renderModule, stateModule] = modules;
    if (renderModule) {
      renderModule.render();
    }
    if (stateModule) {
      stateModule.initState();
    }
  })
}

模块销毁时逻辑: hot.dispose

// state.ts
let timer: number | undefined;
if (import.meta.hot) {
  import.meta.hot.dispose(() => {
    if (timer) {
      clearInterval(timer);
    }
  })
}
export function initState() {
  let count = 0;
  timer = setInterval(() => {
    let countEle = document.getElementById('count');
    countEle!.innerText =  ++count + '';
  }, 1000);
}

共享数据: hot.data 属性

if (import.meta.hot) {
import.meta.hot.accept((mod) => mod.state());
}
let timer = null;
import.meta.hot.dispose(() => {
    clearInterval(timer);
});
export function state() {
    let num = import.meta.hot.data?.num || 0;
    const counter = document.querySelector("#counter");
    timer = setInterval(() => {
        counter.innerHTML = "" + num--;
        import.meta.hot.data.num = num;
}, 1000);
}

其他

1. import.meta.hot.invalidate()

强制页面刷新

自定义事件

图片.png