携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第29天,点击查看活动详情
自动查找接收模块的更新
// main.js
import "./style.css";
import { render } from "./renderA";
render();
// 判断是否有 hot,因为生产版本没有 hot
if (import.meta.hot) {
import.meta.hot.accept();
}
// renderA.js
export function render() {
document.querySelector("#app").innerHTML = `
<h1>Hello Vite!</h1>
<a href="https://vitejs.dev/guide/features.html" target="_blank">
Documentation
</a>
`;
}
- 当我们修改了
renderA
模块,vite 会自动查找我们引入的模块是否有更新,有更新会执行模块中被调用方法 - 当我们修改了
renderA
模块中的render
方法,由于在main.js
中被引用,vite 检测到了renderA
更新,main.js
会重新执行render
方法
只更新我们想更新的模块
// main.js
import "./style.css";
import { render } from "./renderA";
render();
// 判断是否有 hot,因为生产版本没有 hot
if (import.meta.hot) {
// 如果模块没有被热更新接受,就会走刷新页面
import.meta.hot.accept(['./style.css']);
}
- 当我们
accept
函数中传入了数组,指定的引用更新时会进行热更新,没有指定的引用更新时会进行页面刷新 - 当我们 修改了
renderA
模块,由于我们没有指定处理这个模块的热更新,所以页面会刷新
处理我们想更新的模块
// main.js
import "./style.css";
import { render } from "./renderA";
render();
// 判断是否有 hot,因为生产版本没有 hot
if (import.meta.hot) {
// 如果模块没有被热更新接受,就会走刷新页面
import.meta.hot.accept(["./renderA"], ([newA]) => {
newA.render(); // 读取代码中的方法
});
}
- 如果
accept
中只接收一个数组,那这个时候只会接受这个数组引用模块的更新,文件本身不会进行更新,需要在文件本身进行更新的处理 accept(["./renderA"]
接受了renderA
模块的更新,但是main.js
本身不会更新,需要通过回调来处理更新
处理 side effect
问题
如果我们不是通过暴露函数,通过外面引用执行,而是直接在模块中执行某些行为,就会产生副作用,造成不可控制,内存溢出等等
// renderA.js
export function render() {
document.querySelector("#app").innerHTML = `
<h1>Hello Vite!</h1>
<a href="https://vitejs.dev/guide/features.html" target="_blank">
Documentation
</a>
`;
}
let index = 1;
// side effet
setInterval(() => {
console.log(index++);
}, 1000);
- 我们在
renderA
模块中定义了定时器,在main.js
中引用这个模块,就会自动执行定时器,导致我们无法控制此定时器
处理
在模块中监听模块的卸载
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
保存同一个模块中,热更新之前的状态
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);
});
}
主模块 热更新和强制刷新
// 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();
}