從smart漫談打包
- 2019 年 12 月 4 日
- 筆記
本文作者:IMWeb helondeng 原文出處:IMWeb社區 未經同意,禁止轉載
項目構建遷移到fis體系後,打包的問題就跟著來了。打包的基本方式是:分析依賴,合併文件,解決引入。
CSS處理方式
來源
- link 引入
- require 引入
- 其它模組的同名依賴提取來源
- 正則匹配link
- require的方式可以直接通過 file.requires獲取
- 處理方式略複雜,需要在分析js依賴時,判斷依賴是css文件
打包邏輯
最粗暴的方式是allInOne,全部打成一個包。但是多個頁面的業務中,有重複的程式碼被打到了不同的文件中。這種情況下,打包成2個文件比較合適:一個基礎樣式,一個頁面樣式。
common,reset等公共樣式打包成一個文件,Page 級別的樣式打包成一個文件,common級的樣式,每個頁面都引入(載入可以利用快取),頁面級樣式根據自身的依賴引入不同的文件。
問題
- 哪些算是公共樣式?
common文件夾下的所有樣式文件?common打包必須要有通用性,確保能夠覆蓋到大部分(甚至全部)頁面,同時又不會太冗餘,給頁面帶來很多不必要的樣式,這裡必須要有一些規則來約束。
- 打包的靈活性?
有些業務(活動等)就是單頁面應用,打2個文件的方案真的適用嗎?甚至H5的單頁應用,就是需要直接inline到頁面。
一些嘗試
- 定義一個common.scss之類的文件,import一些項目級的css文件,頁面link這個公共的樣式文件。打包處理時,將這個打成一個包,頁面其他的css全部打成另一個包。
- common文件夾下存放的就是項目級的css文件,每個Page只關注頁面級的樣式,打包自動將common下的css打包,接入引入問題。
- 靈活性可以通過配置的問題解決。
- …….
JS打包
JS打包方式多樣性,fis 官方推薦的loader也沒有很好的解決這個問題(PS:在入口函數的注釋里寫著:粗暴的打包方式)。
來源
- script標籤引入
- require
- require.async
依賴方式
- 同步
- 非同步
處理方式
- 同步直接script引入
- 非同步通過resourceMap載入
奇葩
- 同步裡面的非同步依賴
- 非同步裡面的同步、非同步依賴
以上只是問題的一小部分,足見打包場景的複雜和多樣性,但是這裡還是拋磚引玉的做一些簡單的分析。
提取來源
這裡只提取require和require.async,不對script引入做任何處理。從loader的處理方式看,它對script的處理並不成功,需要添加各種ignore注釋,偶爾會打亂script的順序。
打包邏輯
- 分析每個文件id的依賴(深層分析,依賴的依賴)
- 依賴和當前文件打包
- script插入到html中 (同步)
- 生成resourceMap並插入到html中
問題
- 異同步文件的非同步依賴如何處理?
文件的非同步依賴,全部打包到一起,丟到resourceMap中。
- 公共庫如何處理?
公共庫單獨打包,定義一個base之類的文件,將項目級的公共庫引入,在html文件中require引入base,其他的文件的打包需要將這部分公共庫排除掉。
其他問題
上面的邏輯也只是解決一些基礎問題,鑒於項目的多樣性、處理方式的多樣性,實際只處理了一小部分的問題,很多例外的情況沒有處理到:
- require 第3方庫
- require.async 第3方庫
- require(模組是變數)
- vm編譯(vm中if else可以是2個頁面,打包如何處理)
- ……
fis 提供了packTo的打包方式,這個是最原始的,通過match正則打包成不同的文件,但是如何解決引入文件?打包的文件放到哪個html中?同步非同步?
最後的最後
打包實際針對的是一種業務場景和目錄結構的方案,只是對一些默認的規則集的實現,像packTo這種方式,貌似能夠解決所有的打包場景(業務自己去配置),但這種蠻荒時代的方式真的可用嗎?野蠻生長,沒有內在的規律約束。
在打包之前,就應該規定業務場景和目錄結構,定義使用範圍和邊界,不可能有一種打包方案使用所有的場景。官方的loader只是一種單頁應用的方案。