故事的開頭
從一個快要下班的BUG開始,由於原部門同事想要基於一個專案再拆分出幾個專案,我們本來用的是qiankun(基座模式)的微前端模式,再拆分其實是比較簡單的
只是這次順便在拆分之前升級了webpack5,升級也是比較簡單,這裡一筆帶過
實施的過程沒有親自操作
問題來了,在子應用升級了webpack5以後,本地通過基座載入除錯時候,突然啟動不了了
復現問題
臨近下班,這個事情要解決,先復現
發現network皮膚通過基座載入子應用時候,出現了一個js檔案404
這裡面很蹊蹺,因為子應用單獨可以啟動,子應用被基座家載入時候只有一個js檔案404了,而且是一個非同步載入的js,那麼可以判斷,肯定是載入邏輯這塊出了問題
在子應用中除錯,開啟public-path檔案:
if (window.__POWERED_BY_QIANKUN__) {
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
發現這些程式碼在通過微前端基座模式載入時候,竟然沒有執行!!!是整個程式碼都沒有被執行
這個js檔案是通過入口index.tsx檔案頂部引入的
已經定位到了問題,就不怕。
核心問題是:當時發現子應用的__webpack_publicPath__這個變數沒有被修改,所以造成了請求的host不對,非同步載入的js檔案404了
由於在排查這個問題之前,我在群裡說了一句,有問題大家要一起看,這樣都能學到一些東西,還好我說了這句話,拉上幾個同事一起來聽。
其中一個同事說了一句,會不會是被webpack5給tree sharking了
我感覺是,然後讓他們看看自己是怎麼配置這塊的,於是同事提出建議
在package.json
中的sideEffects
欄位,加上這個檔案
然後再次啟動專案,就解決這個問題了,public-path正常被載入了
看似簡單的解決
看似簡單的解決,需要先定位問題,這會用到以下幾點:
熟悉微前端qiankun的原理
熟悉webpack的原理以及webpack動態懶載入實現的原理
熟悉webpack的__webpack_pulicPath__屬性的意義
知道tree sharking
瞭解webpack5的tree sharking配置
逐個原理講解
微前端原理
可以看我之前的手寫微前端文章+原始碼:https://github.com/JinJieTan/...
微前端最核心的原理就是:基座專案通過配置資訊,傳送fetch請求,將子應用的資源全部拿到後渲染成dom節點插入到容器節點中。然後劫持路由變化事件,先在基座觸發,再派發給其他子應用
webpack非同步程式碼分割原理
同步和非同步程式碼都會被打包成不同的js檔案,由於非同步載入的js檔案其實是通過網路請求拿到後插入到頁面中,這個非同步請求的字首,其實是可以通過__webpack__pulicPath__
這個變數來設定的
這也是最早的webpack5聯邦模組實現思路,可以動態載入遠端js檔案,只要控制這個字首變數__webpack_pulicPath__
即可
微前端+非同步程式碼分割,核心思想是:動態的設定__webpack__publicPath__
webpack5的tree sharking配置
tree shaking 是一個術語,通常用於描述移除 JavaScript 上下文中的未引用程式碼(dead-code)。它依賴於 ES2015 模組語法的 靜態結構 特性,例如 import 和 export。這個術語和概念實際上是由 ES2015 模組打包工具 rollup 普及起來的。
webpack 2 正式版本內建支援 ES2015 模組(也叫做 harmony modules)和未使用模組檢測能力。新的 webpack 4 正式版本擴充套件了此檢測能力,通過 package.json 的 "sideEffects" 屬性作為標記,向 compiler 提供提示,表明專案中的哪些檔案是 "pure(純正 ES2015 模組)",由此可以安全地刪除檔案中未使用的部分。
以上是官網文件介紹
sideEffects 和 usedExports(更多被認為是 tree shaking)是兩種不同的優化方式。
sideEffects 更為有效 是因為它允許跳過整個模組/檔案和整個檔案子樹。
usedExports 依賴於 terser 去檢測語句中的副作用。它是一個 JavaScript 任務而且沒有像 sideEffects 一樣簡單直接。而且它不能跳轉子樹/依賴由於細則中說副作用需要被評估。儘管匯出函式能運作如常,但 React 框架的高階函式(HOC)在這種情況下是會出問題的
現在回到剛才我們被tree sharking的程式碼:
if (window.__POWERED_BY_QIANKUN__) {
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
這個程式碼在上下文中其實是沒有被引用的,只有在程式碼編譯後,非同步的程式碼js檔案被載入時才能用到__webpack_public_path__
這個變數,所以就被清除了程式碼
那麼為了解決這個問題,我們需要在 package.json 中新增 "sideEffects" 屬性。
它類似於 /#__PURE__/ 但是作用於模組的層面,而不是程式碼語句的層面。它表示的意思是(指"sideEffects" 屬性):“如果被標記為無副作用的模組沒有被直接匯出使用,打包工具會跳過進行模組的副作用分析評估。”。
跳過public-path檔案到副作用分析評估,直接打包它,就解決了這個問題
webpack的tree-sharking文件:https://webpack.docschina.org...
結尾
小小的一個問題,看似解決起來簡單,但是對於日常的各種實現原理是都要求很熟悉,才能快速定位問題並且解決,這就是學習原始碼和各種原理的意義
感興趣的朋友可以去我的gitHub,這些原始碼+文章都在https://github.com/JinJieTan/Peter-
記得給個star
喜歡的朋友幫Peter
來一波在看/贊吧~