最近作一個需求的時候,想引入lodash來簡化一些邏輯處理,我只用到了get、isArray等幾個函數,但打包出的bundle卻增長了69kb。說明webpack處理時把lodash整個都給打包進去了。javascript
使用webpack-bundle-analyzer分析bundle的結果:css
webpack從2.0開始加入了treeshking的功能,可是這裏明顯沒有觸發treesking。通過查閱文檔和實踐,解決了這個問題。html
先看下成果:vue
webpack的treeshking是基於 es module的靜態分析,可以在編譯期間就肯定哪些模塊用到了哪些模塊沒用到,而且配合解構賦值還能肯定哪些export用到了,哪些export沒用到。而後對用到的部分和沒用到的部分進行標記,在壓縮階段就能夠刪除標記出的沒有用到的部分,從而達到treeshking的目的。java
根據treeshking的原理,想要觸發treesking須要知足3個條件:node
treeshking創建在es module靜態分析的基礎之上,因此代碼必須使用esm的規範。業務代碼通常都會使用esm,可是引入的第三方依賴就不必定了。好比lodash就是commonjs規範的,直接使用lodash是不會觸發treeshking的,解決方案就是使用lodash的esm版本lodash-es。webpack
package.json中的main字段是node package的入口,可是是commonjs規範的。想要使用treeshking的功能必須使用esm的入口,因此rollup(最先的treeshking實現)提出了module字段的提案,在這裏配置es module的入口,這種約定雖然尚未成爲規範,但已經被不少包所實現了。好比vue的package.json:web
也有的包是esm規範的和commonsjs規範的分紅了兩個包,好比lodash和lodash-es。npm
總之,業務代碼和第三方依賴都須要使用esm的規範。json
而後引入的方式須要使用解構賦值的方式,
import { get } from 'lodash';
複製代碼
這種寫法才能夠在編譯期間就能肯定用到了哪些export,而
import _ from 'lodash';
複製代碼
這種寫法沒法在編譯期間肯定用到了哪部分,因此也沒法進行treeshking。關於這點我作過測試,有興趣的同窗也能夠試下。(分別使用兩種引入方式,使用webpack-bundle-analyzer 分析打包出的bundle中lodash這個模塊的大小)
編譯時能夠分析出解構寫法引入的esm模塊,哪些export用到了,哪些模塊沒有用到。而後就須要分別進行標記,開啓標記的配置項就是 optimization.usedExports 。
標記相似這樣:
/* harmony export (immutable) */ __webpack_exports__["xxx"] = xxxx;
/* unused harmony export xxx */
複製代碼
unused harmony export標記的部分就是須要刪掉的。
在編譯期間對不一樣模塊標記以後,在壓縮時就能夠刪掉沒用到的部分,任何一個壓縮的plugin均可以作到這個。
其實上面的二、3兩步,也就是開啓optimization.usedExports和使用壓縮的插件,在webpack4的mode設置爲production時,已經默認開啓了,因此開發者只須要關心業務代碼和第三方包的模塊規範是否是es module,以及有沒有使用解構賦值的引入方式。
treeshking只是創建在某個es module的某一些export有沒有被用到的基礎上的,可是有一些代碼會有反作用,好比在window上掛一個變量、寫本地文件等,這種代碼雖然沒有export一些內容,但也是不能被treeshking掉的。對於這些文件須要過濾掉,配置的方式就是在package.json中添加sideEffects字段,由於webpack的模塊包括圖片、字體文件、css文件等,這些模塊都是須要配置的。
若是一些模塊導出了一個對象,用到這個模塊的地方只使用了某幾個方法,其他的方式是不能被treeshking的。緣由也是由於編譯期間的靜態分析只能對es module的相關語法作分析,是不會真正去執行代碼的。
因此爲了更好的配合treeshking,可以寫成分散的export的就不要封裝成對象,這樣可以配置treeshking打包成最小的bundle。
treeshking是減少打包的bundle size很重要的一個手段,但觸發treeshking是有條件的,首先須要代碼是es module規範的而且使用解構賦值的方式引入,第二要開始optimization.usedExports來標記使用和未使用的模塊,第三是使用壓縮的插件進行刪除未使用代碼。 webpack4的mode設置爲production以後,咱們只須要關心第一點就行了。
treeshking是有限制的,反作用的代碼不能treeshking,只能對export進行treeshking。
瞭解了treeshking的原理和觸發條件,以及treeshking的限制,咱們才能針對性的優化代碼來達到最小的bundle size。固然達到最優可能還須要結合code spliting等其餘方式。