热更新是啥?热更新,是指 Hot Module Replacement,缩写为 HMR。
微信小程序的开发工具,没有提供类似 Webpack 热更新的机制,所以在本地开发时,每次修改了代码,预览页面都会刷新,于是之前的路由跳转状态、表单中填入的数据,都没了。
而如果有类似 Webpack 热更新的机制存在,则是修改了代码,不会导致刷新,而是保留现有的数据状态,只将模块进行更新替换。也就是说,既保留了现有的数据状态,又能看到代码修改后的变化。
很美好,但是想想就觉得是一件肯定不简单的事情。
了解下热更新是怎么配置的。为 Webpack 开发环境开启热更新,要做两件事:
1、使用 HotModuleReplacementPlugin 插件
2、打开 webpack-dev-server 的热更新开关
HotModuleReplacementPlugin 插件是 Webpack 自带的,在 webpack.config.js 加入就好:
// webpack.config.js
module.exports = {
// ...
plugins: [
webpack.HotModuleReplacementPlugin(),
// ...
]
}
打开 webpack-dev-server 的热更新开关:
// webpack.config.js
module.exports = {
// ...
devServer: {
hot: true,
// ...
}
}
下面通过例子来进一步解释热更新机制。如果你之前对 Webpack 热更新的体验,是 Vue 通过 vue-loader 提供给你的,也就是说你在自己的代码中从没有写过或者见到过类似:
import './client';
let root = document.getElementById('root');
function render() {
let title = require('./title').default;
root.innerHTML = title;
}
render();
if (module.hot) {
module.hot.accept(['./title'], () => {
render();
});
}
Webpack 将热更新相关接口以 module.hot 暴露到模块中,在使用前,最好判断下当前的环境是否支持热更新,也就是上面看到的这样的代码。
所以,在热更新的机制中,其实是以这种“声明”的方式告知 Webpack,哪些模块的更新是被处理的,哪些模块的更新又不被处理。当然对于要处理的模块的更新,自行在 module.hot.accept() 的第二个参数即回调函数中进行处理,会在声明的模块被替换后执行。
此外,除了声明其他模块更新的处理,模块也可以声明自身更新的处理,也是同样的接口,不传参数即可:
1、module.hot.accept() 告诉 Webpack,当前模块更新不用刷新
2、module.hot.decline() 告诉 Webpack,当前模块更新时一定要刷新
而且,依赖同一个模块的不同模块,可以有各自不同的声明,这些声明可能是冲突的,比如有的允许依赖模块更新,有的不允许,Webpack 怎么协调这些呢?
Webpack 的实现机制有点类似 DOM 事件的冒泡机制,更新事件先由模块自身处理,如果模块自身没有任何声明,才会向上冒泡,检查使用方是否有对该模块更新的声明,以此类推。如果最终入口模块也没有任何声明,那么就刷新页面了。这也就是为什么在上一个例子中,虽然开启了热更新,但是模块修改后仍旧刷新页面的原因,因为没有任何模块对更新进行处理。
当然,像我们在使用 Vue 或 React 进行开发时,vue-loder 等插件已经帮我们做了这些事情,并且对于 *.vue
文件在更新时要如果进行处理,很多细节也只有 vue-loader 内部比较清楚,我们就放心使用好了。