摘要:原理踩坑起因最近在做框架的熱更新,記錄一下的原理和小坑。文件系統接收更改并通知。運行時通過請求這些更新。類似的問題還有很多,事件綁定手動插入并且沒有銷毀的定時器等,記得把這些副作用一起干掉。參考官方文檔原理分析與實現
webpack hot-module-replacement 原理&踩坑 起因
最近在做san框架的熱更新,記錄一下webpack HMR的原理和小坑。
什么是HMR?熱更新是webpack的一個特性,通過無刷新實現代碼更新。
在HMR之前,大多數開發體驗是live reload,保存后自動刷新瀏覽器,已經是比刀耕火種的年代強很多了,但是自從某天在油管上看到dan神的redux時間穿梭,瞬間被驚艷到(當然,HMR已經是這之前很久就出現了)。
HMR大幅提高了開發體驗,只更新變更內容,調整樣式迅速,避免了大部分的網絡請求、瀏覽器重新渲染、app解析編譯顯示,讓我們來看下他是如何做到的。
hmr基本法 概念compile: webpack的核心。js編譯、拆包。
hmr-server: 建立連接并完成模塊熱更新的推送。
bundle-server: 靜態服務器。
bundle.js: client端。
hmr-runtime: 注入到bundle.js中的代碼。
熱更新開啟后,當webpack打包時,會向client端注入一段HMR runtime代碼,同時server端(webpack-dev-server或是webpack-hot-middware)啟動了一個HMR服務器,它通過websocket和注入的runtime進行通信。
當webpack檢測到文件修改后,會重新構建,并通過ws向client端發送更新消息,瀏覽器通過jsonp拉取更新過的模塊,回調觸發模塊熱更新邏輯。
1.修改了一個或多個文件。
2.文件系統接收更改并通知Webpack。
3.Webpack重新編譯構建一個或多個模塊,并通知HMR服務器進行了更新。
4.HMR Server使用websockets通知HMR Runtime需要更新。HMR運行時通過HTTP請求這些更新(jsonp)。
5.HMR運行時替換更新中的模塊,如果確定這些模塊無法更新,則觸發整個頁面刷新(這是個大坑。。)。
// webpack/hot/dev-server if(module.hot) { var lastHash; //__webpack_hash__是每次編譯的hash值是全局的 //Only available with the HotModuleReplacementPlugin or the ExtendedAPIPlugin var upToDate = function upToDate() { return lastHash.indexOf(__webpack_hash__) >= 0; }; var check = function check() { // check([autoApply], callback: (err: Error, outdatedModules: Module[]) => void // If autoApply is truthy the callback will be called with all modules that were disposed. apply() is automatically called with autoApply as options parameter.(傳入哪些代碼已經被更新的模塊) //If autoApply is not set the callback will be called with all modules that will be disposed on apply(). (不是true那么傳入的是哪些需要被apply處理的模塊) module.hot.check(true).then(function(updatedModules) { //檢查所有要更新的模塊,如果沒有模塊要更新那么回調函數就是null if(!updatedModules) { console.warn("[HMR] Cannot find update. Need to do a full reload!"); console.warn("[HMR] (Probably because of restarting the webpack-dev-server)"); window.location.reload(); return; } //如果還有更新 if(!upToDate()) { check(); } require("./log-apply-result")(updatedModules, updatedModules); //已經被更新的模塊都是updatedModules if(upToDate()) { console.log("[HMR] App is up to date."); } }).catch(function(err) { var status = module.hot.status(); //如果報錯直接全局reload if(["abort", "fail"].indexOf(status) >= 0) { console.warn("[HMR] Cannot apply update. Need to do a full reload!"); console.warn("[HMR] " + err.stack || err.message); window.location.reload(); } else { console.warn("[HMR] Update failed: " + err.stack || err.message); } }); }; var hotEmitter = require("./emitter"); //獲取MyEmitter對象 hotEmitter.on("webpackHotUpdate", function(currentHash) { lastHash = currentHash; if(!upToDate() && module.hot.status() === "idle") { //調用module.hot.status方法獲取狀態 console.log("[HMR] Checking for updates on the server..."); check(); } }); console.log("[HMR] Waiting for update signal from WDS..."); } else { throw new Error("[HMR] Hot Module Replacement is disabled."); }
正常情況下,hmr只會更新模塊,不會觸發頁面刷新。
但是當bundle.js中的代碼拋出異常時,如果開發者沒有手動接收并處理,這個錯誤會冒泡到webpack-hmr-runtime中。
runtime接收error后會console.log一些信息并立即刷新,通常情況下是沒辦法看到那些log的,因為太快了。
// vue-hot-reload-api.js // 不得不說,這個一開始確實沒搞懂是為啥要包一層 // 自己實現的時候才知道,當有error彈出時 // 如果不手動這樣接住error,webpack會接到然后立即location.reload() // 根本來不及看reload之前給出的提示 // 所以要手動處理下error function tryWrap (fn) { return function (id, arg) { try { fn(id, arg) } catch (e) { console.error(e) console.warn("Something went wrong during Vue component hot-reload. Full reload required.") } } }
所以開發者需要自定義一個類似的高階函數手動處理下錯誤,防止看不到錯誤信息而刷新。
副作用模塊的熱更新是好事,但是老模塊仍然有可能在client端留下了痕跡。試想一個組件被熱更新后,如果不處理之前的組件,那么新老兩個組件都會在瀏覽器中出現。
所以別忘了在module.hot.accept中清除掉舊的組件。
類似的問題還有很多,事件綁定、手動插入并且沒有銷毀的dom、定時器等,記得把這些副作用一起干掉。
如果做不到的話,老老實實刷新你的瀏覽器吧。
參考webpack官方文檔
?Understanding Webpack HMR
webpack-dev-server原理分析與HMR實現
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/84825.html
摘要:踩坑入門系列一二添加三目錄重構再談路由陸續更新個人對于腳手架的有一種執念,如果搭建出來就是一個首頁標簽跳轉,實在不是我這個處女座的風格,因此第二步我就想引用框架,相信很多使用的開發者用的也都是這個框架吧。 Next.js踩坑入門系列 (一) Hello Next.js (二) 添加Antd && CSS (三) 目錄重構&&再談路由 陸續更新... 個人對于腳手架的UI有一種執...
摘要:構建構建就是把源代碼轉換成發布到線上的可執行代碼,包括如下內容。自動刷新監聽本地源代碼的變化,自動重新構建刷新瀏覽器。自動發布更新完代碼后,自動構建出線上發布代碼并傳輸給發布系統。將文件放入到項目中,在中新建一個放字體圖標的文件夾。 項目地址 github.com/wudiufo/Web… 知識點概覽: Loader,HMR ,Create React App, Caching, Plug...
摘要:結論得到了開發者社區的廣泛認可,盡管它的安裝過程非常艱難,之所以受到歡迎的原因很大程度取決于它提供的靈活性,以及良好的谷歌背景,而有一個小型的社區,增長略微緩慢。 數人云之前分享了《聊聊調度框架,K8S、Mesos、Swarm 一個都不能少》那么你是否仍在Docker和Kubernetes選擇上陷入了困擾?所以不要擔心,因為這也是很多人的苦惱,這兩者都是非常優秀的容器服務,至于那種更好...
摘要:源碼解析起因最近在搞框架的熱加載方案,自然是少不了向成熟的框架學習偷窺。這將銷毀并重建整個組件包括子組件。通過使用說明可以看出,暴露的接口還是很清晰的,下面來看下具體源碼實現。 Vue-hot-reload-api 源碼解析 起因 最近在搞san框架的熱加載方案,自然是少不了向成熟的框架學習(偷窺ing)。熱加載方案基本也只是主流框架在做,且做的比較成熟,大部分應用開發者并不會接觸到這...
閱讀 2312·2021-11-17 09:33
閱讀 843·2021-10-13 09:40
閱讀 574·2019-08-30 15:54
閱讀 778·2019-08-29 15:38
閱讀 2417·2019-08-28 18:15
閱讀 2475·2019-08-26 13:38
閱讀 1842·2019-08-26 13:36
閱讀 2129·2019-08-26 11:36