從smart漫談打包

  • 2019 年 12 月 4 日
  • 筆記

本文作者:IMWeb helondeng 原文出處:IMWeb社區 未經同意,禁止轉載

項目構建遷移到fis體系後,打包的問題就跟著來了。打包的基本方式是:分析依賴,合併文件,解決引入。

CSS處理方式

來源
  • link 引入
  • require 引入
  • 其它模組的同名依賴提取來源
  • 正則匹配link
  • require的方式可以直接通過 file.requires獲取
  • 處理方式略複雜,需要在分析js依賴時,判斷依賴是css文件
打包邏輯

最粗暴的方式是allInOne,全部打成一個包。但是多個頁面的業務中,有重複的程式碼被打到了不同的文件中。這種情況下,打包成2個文件比較合適:一個基礎樣式,一個頁面樣式

common,reset等公共樣式打包成一個文件,Page 級別的樣式打包成一個文件,common級的樣式,每個頁面都引入(載入可以利用快取),頁面級樣式根據自身的依賴引入不同的文件。

問題
  1. 哪些算是公共樣式?

common文件夾下的所有樣式文件?common打包必須要有通用性,確保能夠覆蓋到大部分(甚至全部)頁面,同時又不會太冗餘,給頁面帶來很多不必要的樣式,這裡必須要有一些規則來約束。

  1. 打包的靈活性?

有些業務(活動等)就是單頁面應用,打2個文件的方案真的適用嗎?甚至H5的單頁應用,就是需要直接inline到頁面。

一些嘗試
  1. 定義一個common.scss之類的文件,import一些項目級的css文件,頁面link這個公共的樣式文件。打包處理時,將這個打成一個包,頁面其他的css全部打成另一個包。
  2. common文件夾下存放的就是項目級的css文件,每個Page只關注頁面級的樣式,打包自動將common下的css打包,接入引入問題。
  3. 靈活性可以通過配置的問題解決。
  4. …….

JS打包

JS打包方式多樣性,fis 官方推薦的loader也沒有很好的解決這個問題(PS:在入口函數的注釋里寫著:粗暴的打包方式)。

來源
  • script標籤引入
  • require
  • require.async
依賴方式
  • 同步
  • 非同步
處理方式
  • 同步直接script引入
  • 非同步通過resourceMap載入
奇葩
  • 同步裡面的非同步依賴
  • 非同步裡面的同步、非同步依賴

以上只是問題的一小部分,足見打包場景的複雜和多樣性,但是這裡還是拋磚引玉的做一些簡單的分析。

提取來源

這裡只提取require和require.async,不對script引入做任何處理。從loader的處理方式看,它對script的處理並不成功,需要添加各種ignore注釋,偶爾會打亂script的順序。

打包邏輯
  • 分析每個文件id的依賴(深層分析,依賴的依賴)
  • 依賴和當前文件打包
  • script插入到html中 (同步)
  • 生成resourceMap並插入到html中
問題
  1. 異同步文件的非同步依賴如何處理?

文件的非同步依賴,全部打包到一起,丟到resourceMap中。

  1. 公共庫如何處理?

公共庫單獨打包,定義一個base之類的文件,將項目級的公共庫引入,在html文件中require引入base,其他的文件的打包需要將這部分公共庫排除掉。

其他問題

上面的邏輯也只是解決一些基礎問題,鑒於項目的多樣性、處理方式的多樣性,實際只處理了一小部分的問題,很多例外的情況沒有處理到:

  • require 第3方庫
  • require.async 第3方庫
  • require(模組是變數)
  • vm編譯(vm中if else可以是2個頁面,打包如何處理)
  • ……

fis 提供了packTo的打包方式,這個是最原始的,通過match正則打包成不同的文件,但是如何解決引入文件?打包的文件放到哪個html中?同步非同步?

最後的最後

打包實際針對的是一種業務場景和目錄結構的方案,只是對一些默認的規則集的實現,像packTo這種方式,貌似能夠解決所有的打包場景(業務自己去配置),但這種蠻荒時代的方式真的可用嗎?野蠻生長,沒有內在的規律約束。

在打包之前,就應該規定業務場景和目錄結構,定義使用範圍和邊界,不可能有一種打包方案使用所有的場景。官方的loader只是一種單頁應用的方案。