最近有個專案(就叫他 P 專案)做了一次 UI 視覺統一。
之前是個小專案用的是預設主題 theme-d
,這次需求還針對性的釋出了一套 theme-p
主題。
然後出事故了,更新了主題之後我們的 dialog
顯示異常了。
使用控制檯檢視樣式
通過檢視樣式我們發現都是 UI 的樣式,並沒有我們手動覆蓋的樣式。
但是這裡有一個異常點有四個生效的樣式,正常情況是隻會有一個。但是這裡我忽略了這個問題,我以為只是有多餘的引入,或者沒有 externals
、peerDependencies
導致有多個。
看上去樣式是生效了只不過效果不對,我就懷疑 theme-p
有問題,但是在文件站顯示是正常的。
那我們只能想辦法去排查這個錯誤樣式是誰引入進來的。
通過控制變數法
因為樣式在頁面中都顯示 style,沒有辦法從檔名切入,所以這裡我先採用了控制變數法。
main.ts
程式碼全部註釋掉main.ts
初始一個新的頁面,頁面中只渲染 dialog。- 檢視效果,dialog 效果同
theme-p
文件站。 main.ts
放開原始程式碼。- 檢視效果,dialog 效果詭異。這個時候判斷問題出在
main.ts
中。 main.ts
註釋掉一半,觀察效果。- 如果效果異常,重複步驟6,再註釋掉一半。
- 當效果正常時,復原一半。
- 只到最後只保留下一行有問題的程式碼
- 進入到檔案中,重複步驟6。
最後就能定位到錯誤程式碼行。你以為故事就結束了?這裡詭異的是我定位到了好幾個位置
- 第一次我定位到三方依賴中(沒完全定位,估計是被快取忽悠了)
- 第二次定位到了
import {dialog} from 'ui';
中 - 另一個同事定位到了我們的業務元件庫中(ui-p)。這裡也很重要,但是他介入定位比較晚,不然我們排查速度還能更快一點。
這裡其實對於解決問題的幫助不太大。而且我們專案依賴巢狀嚴重,導致耗時嚴重。
大膽猜測
在我兩次定位之後,我知道這樣是無法分析出問題了,然後我給了幾個大膽的猜測。
- 沒有
externals
,所以載入了新的樣式,導致樣式權重異常。這裡的特徵是產物中會有 css 程式碼 - 有
externals
,所以載入了新的樣式,導致樣式權重異常。這裡的特徵是會有明確的require()
- 有地方
import 'ul.css'
- 沒有按需引入
在我給出猜測的時候我已經有了預感,就是因為 ui-p
用的是預設主題,並且做了 externals
,加上我們做了非同步元件,所以導致主題衝突。
加上另一個同事分析到了在 ui-p
中,所以我們接下來就是驗證是否是 ui-p
的問題。
斷點除錯
是的你沒聽錯,樣式也可以“斷點除錯”。
- 我們在
node_modules
先給dialog.css
加了一行程式碼body{background: red}
。 - 然後通過
Chrome-Devetools
中的search
來查詢到body{background: red}
所在的檔案 - 然後對程式碼進行斷點除錯
- 之後可以看到堆疊資訊,發現堆疊中有
ui-p
控制變數
把所有 ui-p 元件都幹掉,發現 dialog 也正常了
解決 ui-p
和主應用主題不同問題
- 升級
ui-p
為theme-p
主題 - 還原
p
為theme-d
主題 - 移除
ui-p
ui-p
做名稱空間
各個方案都有問題,我們選擇了名稱空間。
你以為到這裡就結束了嗎?並沒有,我將做完名稱空間的包放入專案中。還!是!有!問!題!
完了,不止一個 ui-p
,接下來就重複上述的操作咯。
但是這次排查出來結果比較離譜,顯示是 common.js 載入。這使我懷疑上了另一個位置 splitChunks
異常
修改 splitChunks
策略
因為使用了 all
所以導致 async
和 initial
被合併了。這個使用 initial
其實會異常的大,因為裡面有 async
的程式碼.
所以我們只需要改成 initial
重新編譯即可。✿✿ヽ(°▽°)ノ✿ 成功了,我果然是最靚的仔。
這個時候成功條件變為了兩個,那我們需要看看是不是隻是 splitChunks 的問題,萬幸的是必須兩個都完成,才可以解決問題(我的時間沒有浪費 ?)
覆盤
- 做名稱空間是必須的
splitChunks
應該不是必須的,只不過 dialog 並不在我的 async 中,所以我是正常的。- 排查方法還需要繼續調研。上述方案比較低效
還有什麼方法可以檢視引入 css 的地方嘛?
這裡問了幾個同事,但是大家並沒有做過,也希望知道的老鐵可以留言哈
- webpack 是否可以?
- babel 是否可以?
- cli 的 --report 是否可以?
- 控制檯的斷點除錯是否可以?
- 壓縮前的程式碼是否有一些描述?
externals
,這是我能想到的一個位置。- 預設的會把程式碼包含在產物中
externals
會變成require()
語句。
externals 排查
yarn build --target lib --name myLib --report
通過把調整構建目標,打出了 lib 版本的資源,的確是查到了。
但是看到之後我迷糊了,因為又是 ui-p
。這裡我就徹底蒙了,因為我們專案是 monorepo
的,所以我在想是不是依賴的問題,但是我最後還是沒找到問題點。
專案&截圖
我把我在群裡的彙報截圖貼過來,感興趣可以看一下,專案的話暫時不提供復現 demo 了。