隨著專案的日漸迭代,專案整體的程式碼量也會越來越多,從而導致專案體積越來越大;在Webpack時代,很多人會對歷史專案(巨型專案)感到頭疼,因為往往巨型專案在本地開發偵錯的時候會因為原生程式碼的修改觸發HMR熱更新過載頁面,然而這一過程在Webpack的執行機制中顯得很慢,並且是隨著專案越大,熱更新的速度也會越慢;
Webpack熱更新慢的問題可以通過 babel-plugin-dynamic-import-node 外掛來得到明顯改善,或者通過手動實現動態按需載入(修改entry為當前專案中需要編譯的部分或模組)亦可大幅提升熱更新速度;
熱更新構建主要流程
在Webpack中,我們的每一次ctrl+s操作,都會觸發熱更新;此時熱更新構建的一個過程應該是此時的終端顯示Compiling......執行重新構建並打包,並生成新的hash值,啟動Webpack-dev-server服務與瀏覽器通過WebSocket建立連線;此時的hash值會作為下一次編譯生成的檔案的字首,以此類推;每次修改會觸發重新編譯,然後發出兩次請求;
首先看json檔案,發出請求返回的結果中有一個c引數和一個h引數,c代表的是本次熱更新要對應的是c模組,h代表的是本次熱更新重新編譯的過程中新生成的hash值,將作為下一次熱更新請求編譯後生成的檔案字首使用;
js檔案,是修改之後重新編譯生成打包後的程式碼,重新對檔案進行下載及網路資源載入;
Vite中熱更新構建過程也是類似,Vite是在本地啟動Vite Server服務,通過WebSocket與瀏覽器進行連線通訊,並加入了WebSocket的定時心跳檢測機制,拿到已修改更新的檔案路徑以及時間戳標識,然後再次帶上這個時間戳作為引數去重新請求該檔案修改後的版本,防止快取;
熱更新邊界
熱更新邊界即熱更新邊緣,定義了處於極值或者特殊情況的時候該如何去處理熱更新;
正常來說我們Vue檔案會正常熱更新,因為Vue底層部分對熱更新進行了自定義邏輯處理,重新定義了熱更新的處理方式;但是當我們修改js檔案或者ts檔案,並且這個js或者ts檔案剛好被.vue檔案所參照,這個時候會怎麼處理?
js或者ts檔案修改之後,Vite會去對這個vue檔案進行熱更新,並重新載入該元件;此時,.vue檔案就是熱更新邊界;
當js或者ts檔案被修改之後,會沿著依賴樹一直往上尋找依賴關係,直到查詢到最近的一個可以熱更新的模組,這個最近的一個熱更新模組叫熱更新邊界;
但是又有一種特殊情況,比如我們修改main.ts或者main.js的時候,因為是入口檔案,找不到最近的可以熱更新的模組,這個時候Vite就不知道如何去執行熱更新了,只能是通過重新整理頁面來解決;
Vite熱更新為什麼比Webpack熱更新快?
Webpack熱更新執行機制:
Webpack會遍歷你的應用程式中的所有檔案,並啟動一個開發伺服器(Webpack-dev-server),然後將整個程式碼渲染到開發環境中。從entry入口檔案開始,將其依賴的資原始檔通過loader打包成一個資料夾,然後通過server傳遞到使用者端執行;也正是因為這樣的執行機制,也必將導致專案程式碼量增多,應用體積增大之後,Webpack熱更新需要等待較久的時間才能反映到瀏覽器中;
Vite熱更新執行機制:
Vite會在本地啟動一個Vite Server服務,對於第三方依賴使用了速度更快的esbuild預構建,對於業務程式碼使用原生的ESM,存取這個服務,現代瀏覽器基本都已支援的import/export等語法可用來直接載入對應模組的伺服器端資源,繞過了構建打包過程,對請求的模組進行實時按需編譯,熱更新時僅需重新請求改動過的模組即可,繞過了Webpack熱更新全域性依賴與業務程式碼全部重新編譯的過程;
使用keep-alive元件導致熱更新對ts檔案失效,如何解決?
使用keep-alive元件實現頁面級快取,會導致熱更新失效;個人理解是:因為vue框架底層原始碼部分對Vite熱更新有特殊處理邏輯(import.meta.hot.accept Api用於傳入一個回撥函數,來定義該模組修改後,需要怎麼去熱更新,此Api一般提供給框架或者工具庫的作者使用,業務程式碼中可不用關注),而ts檔案是沒有熱更新邏輯的,所以會沿著依賴樹一直往上尋找,往上找到一個可以熱更新的模組對其進行熱更新即可;keep-alive頁面快取和熱更新概念衝突,在開發環境中我們可以判斷捨棄掉keep-alive快取,而在生產環境中我們可以捨棄熱更新,達到解決問題的目的;
解決方案:
Vite劣勢:
有好必有壞,Vite目前的機制是會大幅提高熱更新的速度,解決Webpack機制中的巨型專案熱更新等待過久的問題,提高開發效率;但是同時也正是因為Vite的執行機制,直接瀏覽器按需向伺服器端請求資源,這就造成了Vite專案的首屏載入沒有Webpack快,因為Vite首屏的時候會發出大量的請求去拿到資原始檔從而渲染頁面,而Webpack不需要;同時懶載入效能方面,Vite也沒有Webpack好;但是首屏渲染這個問題只是第一次載入的時候會比較慢,Vite對第三方依賴做了快取處理,第二次之後的頁面載入速度提升很多;總體來說,Vite是優大於劣;