自动查找接收模块的更新

  1. // main.js
  2. import "./style.css";
  3. import { render } from "./renderA";
  4. render();
  5. // 判断是否有 hot,因为生产版本没有 hot
  6. if (import.meta.hot) {
  7. import.meta.hot.accept();
  8. }
  1. // renderA.js
  2. export function render() {
  3. document.querySelector("#app").innerHTML = `
  4. <h1>Hello Vite!</h1>
  5. <a href="https://vitejs.dev/guide/features.html" target="_blank">
  6. Documentation
  7. </a>
  8. `;
  9. }
  • 当我们修改了 renderA 模块,vite 会自动查找我们引入的模块是否有更新,有更新会执行模块中被调用方法
  • 当我们修改了 renderA 模块中的 render 方法,由于在 main.js 中被引用,vite 检测到了 renderA 更新,main.js 会重新执行 render 方法

    只更新我们想更新的模块

    ```javascript // main.js import “./style.css”;

import { render } from “./renderA”;

render();

// 判断是否有 hot,因为生产版本没有 hot if (import.meta.hot) { // 如果模块没有被热更新接受,就会走刷新页面 import.meta.hot.accept([‘./style.css’]); }

  1. - 当我们 `accept` 函数中传入了数组,指定的引用更新时会进行热更新,没有指定的引用更新时会进行页面刷新
  2. - 当我们 修改了 `renderA` 模块,由于我们没有指定处理这个模块的热更新,所以页面会刷新
  3. <a name="c3G6s"></a>
  4. # 处理我们想更新的模块
  5. ```javascript
  6. // main.js
  7. import "./style.css";
  8. import { render } from "./renderA";
  9. render();
  10. // 判断是否有 hot,因为生产版本没有 hot
  11. if (import.meta.hot) {
  12. // 如果模块没有被热更新接受,就会走刷新页面
  13. import.meta.hot.accept(["./renderA"], ([newA]) => {
  14. newA.render(); // 读取代码中的方法
  15. });
  16. }
  • 如果 accept 中只接收一个数组,那这个时候只会接受这个数组引用模块的更新,文件本身不会进行更新,需要在文件本身进行更新的处理
  • accept(["./renderA"] 接受了 renderA 模块的更新,但是 main.js 本身不会更新,需要通过回调来处理更新

    处理 side effect

    问题

    如果我们不是通过暴露函数,通过外面引用执行,而是直接在模块中执行某些行为,就会产生副作用,造成不可控制,内存溢出等等 ``javascript // renderA.js export function render() { document.querySelector("#app").innerHTML =

    Hello Vite!

    Documentation `; }

let index = 1; // side effet setInterval(() => { console.log(index++); }, 1000);


- 我们在 `renderA` 模块中定义了定时器,在 `main.js` 中引用这个模块,就会自动执行定时器,导致我们无法控制此定时器
<a name="p6oGc"></a>
## 处理
在模块中监听模块的卸载
```javascript
let index = 0;
// side effet
const timer = setInterval(() => {
  console.log(index++);
}, 1000);

if (import.meta.hot) {
  // 当模块被卸载时
  import.meta.hot.dispose(() => {
    if (timer) clearInterval(timer);
  });
}

保留当前状态

问题

当我们修改代码时,不想让我们操作过的数据重新开始,就需要保留状态

let timer = null;
let index = 0;
export function render() {
  timer = setInterval(() => {
    index++;
    document.querySelector("#app").innerHTML = `
      <h1>Hello Vite!</h1>
      <a href="https://vitejs.dev/guide/features.html" target="_blank">
        documentation${index}
      </a>
    `;
  }, 1000);
}

if (import.meta.hot) {
  // 当模块被卸载时
  import.meta.hot.dispose(() => {
    if (timer) clearInterval(timer);
  });
}
  • 每次页面刷新,index 都会被重置为 0 的状态,如果我们想保留 index 值,就需要做一些保留状态的处理

    处理

    import.meta.hot.data 保存同一个模块中,热更新之前的状态 ```javascript let timer = null; // 需要判断是否有cache和getIndex let index = import.meta.hot.data?.cache?.getIndex() ?? 0;

export function render() { timer = setInterval(() => { index++; document.querySelector(“#app”).innerHTML = <h1>Hello Vite!</h1> <a href="https://vitejs.dev/guide/features.html" target="_blank"> 11Documentation${index} </a>; }, 1000); }

if (import.meta.hot) { // data本身无法修改,只能在data中添加内容 // import.meta.hot.data.index = index; 直接赋值是个原始类型,初始化时赋值为0,后面一直为0 import.meta.hot.data.cache = { // 赋值对象时一个引用类型 getIndex() { return index; }, }; // 当模块被卸载时 import.meta.hot.dispose(() => { if (timer) clearInterval(timer); }); }

<a name="Mwpkg"></a>
# 主模块 热更新和强制刷新
```javascript
// main.js
import "./style.css";

import { render } from "./renderA";

render();

// 判断是否有 hot,因为生产版本没有 hot
if (import.meta.hot) {
  // 如果模块没有被热更新接受,就会走刷新页面
  import.meta.hot.accept(["./renderA"], ([newA]) => {
    // console.log(import.meta.hot.data);
    newA.render(); // 读取代码中的方法
  });
}
  • 此时我们在 main 中修改代码,是会刷新页面的,如果想让 main 也保持热更新,需要做如下处理

    // 判断是否有 hot,因为生产版本没有 hot
    if (import.meta.hot) {
    // 如果模块没有被热更新接受,就会走刷新页面
    import.meta.hot.accept(["./renderA"], ([newA]) => {
      // console.log(import.meta.hot.data);
      newA.render(); // 读取代码中的方法
    });
    import.meta.hot.accept(() => {}); // 保证 main.js 修改时,不重新刷新页面,也进行热更新
    }
    
  • 如果想让 main 页面强制刷新,可以使用如下方法

    import.meta.hot.decline()
    
    // 判断是否有 hot,因为生产版本没有 hot
    if (import.meta.hot) {
    // 如果模块没有被热更新接受,就会走刷新页面
    import.meta.hot.accept(["./renderA"], ([newA]) => {
      // console.log(import.meta.hot.data);
      newA.render(); // 读取代码中的方法
    });
    // import.meta.hot.accept(() => {}); // 保证 main.js 修改时,不重新刷新页面,也进行热更新
    import.meta.hot.decline();
    }
    

    强制在 accept 之后,浏览器刷新

    // 判断是否有 hot,因为生产版本没有 hot
    if (import.meta.hot) {
    // 如果模块没有被热更新接受,就会走刷新页面
    import.meta.hot.accept(["./renderA"], ([newA]) => {
      // console.log(import.meta.hot.data);
      if (newA.index > 15) { // 如果大于 5
        import.meta.hot.invalidate(); // 强制在 accept 之后,浏览器刷新
      } else {
        newA.render(); // 读取代码中的方法
      }
    });
    import.meta.hot.accept(() => {}); // 保证 main.js 修改时,不重新刷新页面,也进行热更新
    // import.meta.hot.decline();
    }