• 中文
  • ENGLISH
前端代碼打包優化
2018/03/08

本文作者:天尹

前端資源打包在每個項目中都會有涉及,每位開發者都希望打包是用最少的時間構建出最小的代碼,這不僅能提高團隊中的效率,也能提高頁面的訪問性能,以下會從如何優化構建速度和優化構建輸出代碼來說明一些方法。
圖片來自webpack官網log

1. 速度優化

日常開發打包配置大家都是習慣用腳手架等的默認配置,沒問題,沒毛病,跑的好好的,就沒這么在意。對于一些強迫癥的患者,還是會有點不爽的, 比如速度,比如最終打包出來的資源大小等等。

1.1 本地構建或者服務端構建

1.1.1 本地構建

開發完后本地構建,然后通過push到cnd同步資源。可能是傳統大家喜歡做的思路,沒毛病,也挺好用的。
不足點:加重了倉庫的體積,對于倉庫中的語義化的npm包,本地構建不能實時享受到包的更新。
優點: 適合于多人項目合作初期,或者依賴的一個三方包也處于一個不斷迭代的過程,每個人開發的過程中僅僅打包自己的頁面,互相不干擾

1.1.2 服務端構建

服務端構建,大致就是當資源push的時候,會在一臺構建機器上面跑類似ci的服務,同時也會有打包的服務
優缺點基本就是本地的相反,但是還是比較推薦這樣的方案

1.2 如何來優化

1.2.1 配置差異化

粗暴點其實大家可能希望這個配置可以自動化生成,而且可以僅有一份來做,思路是沒錯,但是其實應該做一些區分
功能
本地開發
線上發布
壓縮代碼
需要
babel-polyfill
一般不需要
看業務需求
分離樣式
需要
刪除console.log
需要
css Prefix
需要
OccurrenceOrderPlugin
需要
DedupePlugin
需要
Babel present轉碼
需要
其實比較合理的方式應該是用環境變量來區分進行不同環境下不同的配置,ps:設置環境變量為了在window兼容,可以使用cross-env 來設置
以上的對比沒有進行測試,感興趣的同學可以試試看,在老的基礎上修改會有多少的優化。
總結起來就是本地開發只求速度快,能少處理一點是一點

1.2.2 常見方式

可以在社區中看到很多相關類似的文章來做webpack的優化,各種各樣的提速,可能都知道,但是懶得做,但其實一旦完成后,帶來的受益是巨大的。
externals
這可能是最暴力最提速的方法之一,把其中的一些庫從中忽略掉,如果extern react了,需要注意的是最好把相關的一些react-addons-transition-group也給extern掉,否則有可能會出現依然打入多份react的問題,因為react-addons-transition-group這樣的包里面代碼是類似如下方式,externals并不能排除
module.exports = require('react/lib/ReactTransitionGroup');
Dll
將一些可預見性的庫從中抽離,預打包,可以極大的提速,當時還是有蠻多需要注意的,比如同樣的包最好全局只有一份,預打包后不能享受到語義化版本的資源跟新,需要結合實際問題來看是否需要。
HappyPack
常用套路加速
const os = require('os');

HappyPack.ThreadPool({size: os.cpus().length })
一些配置
設置一些alias,同時可以適當設置一些loaders中的exclude等
設置css-loader版本號
提速特別明顯
"css-loader": "^0.14.5",
相關Issue
替換scss-loader 為fast-sass-loader
相比起來比scss-loader速度更快
不用webpack自帶的uglfiyJS
用自帶的uglfiyJS來做壓縮速度比較慢,這邊有倆思路,但原理應該是一樣的
  1. 造個新輪子多核并行去壓縮js和css
這個方案優化一般來說可以提速一半左右
js和scss的分離
這個可以優化本地開發過程中的rebuild速度,盡量讓scss文件和js文件分離,如果使用了一些ui庫,可以引用UI庫的css文件,而不是scss文件,省去每次的scss build過程

1.3 其他

  1. 對于打包webpack可能是一個功能大而全的工具,除此之外還有很多類似于rollup或者是browserify,要看具體場景來使用,殺雞可能選個更合適的刀會更好,不要盲目選擇都是用一把刀。后續待嘗試后詳細再補相關的一些其他打包方案。
  2. 優化永無止境

2. 代碼優化

2.1 精簡node_modules

現在開發基本都是使用npm或者yarns進行依賴管理,隨便引入幾個依賴就會使得最終打包的結構臃腫,再加上開發者可能對依賴的包并沒有特別統一管理,需要什么就引入什么,不會去關心互相之間的關系。
上圖僅僅是說明node_modules管理的時候出現的包的量一個圖,可以說是非常的形象。圖片來自文章What’s really wrong with node_modules and why this is your fault,文章推薦一看
注:npm包開發者應該保證包里面僅只有需要的代碼,比如測試等等的資源最好都忽略掉,這樣也可以省去不少開支,細節后續會整理一篇新的文章。

2.1.1 方法1:同樣功能使用同樣的包

多人開發常會遇到使用三方庫,部分人使用deep-extend,但是后面可能又有人用lodash,這樣一來一回,會出現同樣功能的包會引用多個的問題。對于這個情況不會導致bug,但是會造成node_modules增多且package.json依賴混亂,當然代碼大小也會有相應的損失。
解決方式
查看倉庫的package.json,比如
{
    "deep-extend": "^0.4.1",
    "lodash.clonedeep": "^4.5.0",
}
如上倆個庫都是想做深拷貝,可以選擇只使用其一即可,推薦

2.1.2 方法2:同一個包盡量不存在多個版本

大部分情況這樣僅只會加重代碼的體積等,但是在少數的場景下,比如使用了前端組件庫;
舉個例子,項目中依賴了倆組件A和B,A依賴了某UI庫C的1.0.0的input,而B依賴了C中的2.0.0的input,最終頁面上會同時存在倆版本的input,這里存在一個隱患(如果倆組件有Dom節點結構調整發生樣式變化,這個時候無論是使用1.0.0或者是2.0.0的樣式其實都不合適),所以這個問題也需要多關注的,特別是前端的UI庫,最好習慣性的排查下較為好。必須最好做下
解決方式
打開chrome調試工具,查看node_modules,對于UI的庫,仔細翻翻,不能有多版本的庫,對于其他庫則可以佛系排查;如果發現某個庫A出現了多次,可以使用npm ls A來查看是在什么地方多次引用到了,然后再定位到具體細節的包查看

2.1.3 方法3:分析代碼依賴

使用webpack的使用BundleAnalyzerPlugin或者是用自帶的功能輸出json,進行分析,排查為什么最后輸出的資源這么大的原因

2.2 抽離公用資源

比較適合那些整站的開發,將各個頁面公用的資源抽離出來,這樣在頁面的訪問過程中瀏覽器可以很好的將這些通用資源緩存,類似使用dll存在本地工程中,還可以使得打包加速,下面以dll為例
做法
  1. 配置好項目所要打的dll資源,一般選擇的是一些三方的庫,具體看項目的需求
  2. 預先打好dll的資源放到項目的某個自定目錄中(甚至可以直接打成生產環境的版本省去后續的壓縮)
  3. 本地構建或者服務端構建任務結束后,將打好的dll資源拷貝到build目錄下面
注意點
  1. 如果使用服務端構建請務必保持本地的npm版本和服務端構建上面的版本一致,不同的npm的版本可能會導致manifest.json的里面內容不一致,因為dll存的是路徑
  2. 最好解決下同一個庫多版本的問題,否則dll中就會打進去多版本的庫,因為dll存路徑不同的版本的版本號是不一致的

2.3 其他

2.3.1 使用babel-preset-env

官方也是推薦使用它來代替babel-preset-2015,根據業務所需要適配的瀏覽器去選擇合適的,否則使用多余的轉碼會是的代碼轉碼后更大,同時對于browsers的設置,也可以跟postCss進行統一

2.3.2 區分好大包小包的問題

一些組件庫或者是lodash
import { isEmpty } from 'lodash';

import isEmpty from 'lodash/isEmpty';
所產生的結果是不一樣的。除非使用一個轉碼的工具來支持;vscode用戶建議裝一個Import Cost

2.3.3 升級打包工具webpack

升級到webpack3,有tree shaking、Scope Hoisting都對代碼有著不錯的優化

2.3.4 優化樣式

  1. prefix這類的工作交給postCss來完成,同樣是根據業務的需求去做相關的prefix的處理,不多不少
  2. 精簡樣式,去除沒必要的樣式

訂閱我們
体彩20选5开奖结果查询