Webpack 熱更新機(jī)制

熱更新是啥?熱更新,是指 Hot Module Replacement,縮寫為 HMR。
微信小程序的開發(fā)工具,沒有提供類似 Webpack 熱更新的機(jī)制,所以在本地開發(fā)時(shí),每次修改了代碼,預(yù)覽頁面都會(huì)刷新,于是之前的路由跳轉(zhuǎn)狀態(tài)、表單中填入的數(shù)據(jù),都沒了。
而如果有類似 Webpack 熱更新的機(jī)制存在,則是修改了代碼,不會(huì)導(dǎo)致刷新,而是保留現(xiàn)有的數(shù)據(jù)狀態(tài),只將模塊進(jìn)行更新替換。也就是說,既保留了現(xiàn)有的數(shù)據(jù)狀態(tài),又能看到代碼修改后的變化。
很美好,但是想想就覺得是一件肯定不簡單的事情。
了解下熱更新是怎么配置的。為 Webpack 開發(fā)環(huán)境開啟熱更新,要做兩件事:
1、使用 HotModuleReplacementPlugin 插件
2、打開 webpack-dev-server 的熱更新開關(guān)
HotModuleReplacementPlugin 插件是 Webpack 自帶的,在 webpack.config.js 加入就好:
// webpack.config.jsmodule.exports = {// ...plugins: [webpack.HotModuleReplacementPlugin(),// ...]}
打開 webpack-dev-server 的熱更新開關(guān):
// webpack.config.jsmodule.exports = {// ...devServer: {hot: true,// ...}}
下面通過例子來進(jìn)一步解釋熱更新機(jī)制。如果你之前對 Webpack 熱更新的體驗(yàn),是 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 將熱更新相關(guān)接口以 module.hot 暴露到模塊中,在使用前,最好判斷下當(dāng)前的環(huán)境是否支持熱更新,也就是上面看到的這樣的代碼。
所以,在熱更新的機(jī)制中,其實(shí)是以這種“聲明”的方式告知 Webpack,哪些模塊的更新是被處理的,哪些模塊的更新又不被處理。當(dāng)然對于要處理的模塊的更新,自行在 module.hot.accept() 的第二個(gè)參數(shù)即回調(diào)函數(shù)中進(jìn)行處理,會(huì)在聲明的模塊被替換后執(zhí)行。
此外,除了聲明其他模塊更新的處理,模塊也可以聲明自身更新的處理,也是同樣的接口,不傳參數(shù)即可:
1、module.hot.accept() 告訴 Webpack,當(dāng)前模塊更新不用刷新
2、module.hot.decline() 告訴 Webpack,當(dāng)前模塊更新時(shí)一定要刷新
而且,依賴同一個(gè)模塊的不同模塊,可以有各自不同的聲明,這些聲明可能是沖突的,比如有的允許依賴模塊更新,有的不允許,Webpack 怎么協(xié)調(diào)這些呢?
Webpack 的實(shí)現(xiàn)機(jī)制有點(diǎn)類似 DOM 事件的冒泡機(jī)制,更新事件先由模塊自身處理,如果模塊自身沒有任何聲明,才會(huì)向上冒泡,檢查使用方是否有對該模塊更新的聲明,以此類推。如果最終入口模塊也沒有任何聲明,那么就刷新頁面了。這也就是為什么在上一個(gè)例子中,雖然開啟了熱更新,但是模塊修改后仍舊刷新頁面的原因,因?yàn)闆]有任何模塊對更新進(jìn)行處理。
當(dāng)然,像我們在使用 Vue 或 React 進(jìn)行開發(fā)時(shí),vue-loder 等插件已經(jīng)幫我們做了這些事情,并且對于 *.vue 文件在更新時(shí)要如果進(jìn)行處理,很多細(xì)節(jié)也只有 vue-loader 內(nèi)部比較清楚,我們就放心使用好了。
