隨著前端應用包含的模組數量日益增長,程式碼打包的耗時也越來越長。公司很多專案打包耗時超過了10秒,對於一般人來說超過10秒的等待是比較難受的,雖然後續增量編輯的速度很快。於是我想結合實際開發環境提升一下首次打包的速度。
1. 實際開發環境
我碰到大多數處於維護狀態的網站都有一下幾個特性:
- 模組數量龐大
- 模組中主要分為js模組和css模組,並且less模組最後使用
extract-text-webpack-plugin
打包出單獨的css檔案 - webpack入口檔案包含了js和less,所以每次打包都需要處理js和less模組
- 許多需求只涉及到js模組的修改,並不涉及樣式修改。反之亦然。
2. 優化思路
既然許多情況下編譯less模組不是必須的,那在這些情況下單獨編譯js模組就能大幅提升webpack的效能。畢竟less的編譯、以及css的抽出都非常消耗時間。
3. 優化步驟
優化包含以下兩步:
- 區分編譯目標,單獨編譯js? 還是單獨編輯css? 還是js+css?
- 入口檔案分離js和css
3.1 區分編譯目標
這一步比較簡單,我們需要使用cross-env
這個外掛,例如下面兩條編譯命令區分了編譯js和編譯js+css。
{
"scripts": {
"build:js": "cross-env ctarget=all webpack",
"biuld:js+css": "cross-env ctarget=js webpack"
}
}
複製程式碼
這樣我們就可以在webpack配置檔案中通過process.env.ctarget
區分當前編譯目標了。
3.2 分離js和css
這一步需要通過webpack的loader來實現,可以使用現有的輪子string-replace-loader
。
這個loader可以在編譯階段修改程式碼,並且可以使用正規表示式進行替換。可以使用它來載入js檔案,然後刪除部分程式碼。下面的例子的作用是刪除js檔案中所有的less程式碼匯入。
{
module: {
rules: [
{
test: /.js$/,
use: (function(){
var list = ['這裡可以加上其他需要的loader'];
// 更具編譯目標刪除less的匯入
if (process.env.ctarget === 'js') {
list.push({
loader: 'string-replace-loader',
options: {
search: '^.+?require\\(.+(\\.less).+$',
replace: '',
flags: 'm'
}
})
}
return list;
})()
}
]
}
}
複製程式碼
這裡在使用string-replace-loader
一定要加上flags: 'm'
,否則無法進行多行匹配。
如果要單獨打包css我們可以寫一個和
string-replace-loader
作用相反的loader,只保留樣式部分而刪除其他js程式碼。
4. 效果
經過實際測試,這個優化可以節省50%的時間。當然具體到每一個專案還要看js和css模組數量的比例。