記錄:Webpack5把微前端qiankun的配置檔案tree sharking了

語言: CN / TW / HK

故事的開頭

從一個快要下班的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/Peter-/tree/master/chunchao

微前端最核心的原理就是:基座專案通過配置資訊,傳送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/guides/tree-shaking/

結尾

小小的一個問題,看似解決起來簡單,但是對於日常的各種實現原理是都要求很熟悉,才能快速定位問題並且解決,這就是學習原始碼和各種原理的意義

感興趣的朋友可以去我的gitHub,這些原始碼+文章都在 https://github.com/JinJieTan/Peter- 記得給個 star

喜歡的朋友幫 Peter 來一波在看/贊吧~