webpack treeshking的三個(gè)要點(diǎn)

場(chǎng)景介紹

最近做一個(gè)需求的時(shí)候,想引入lodash來(lái)簡(jiǎn)化一些邏輯處理,我只用到了get、isArray等幾個(gè)函數(shù),但打包出的bundle卻增加了69kb。說(shuō)明webpack處理時(shí)把lodash整個(gè)都給打包進(jìn)去了。

使用webpack-bundle-analyzer分析bundle的結(jié)果:

image

webpack從2.0開(kāi)始加入了treeshking的功能,但是這里明顯沒(méi)有觸發(fā)treesking。經(jīng)過(guò)查閱文檔和實(shí)踐,解決了這個(gè)問(wèn)題。

先看下成果:

image

treeshking的原理

webpack的treeshking是基于 es module的靜態(tài)分析,能夠在編譯期間就確定哪些模塊用到了哪些模塊沒(méi)用到,并且配合解構(gòu)賦值還能確定哪些export用到了,哪些export沒(méi)用到。然后對(duì)用到的部分和沒(méi)用到的部分進(jìn)行標(biāo)記,在壓縮階段就可以刪除標(biāo)記出的沒(méi)有用到的部分,從而達(dá)到treeshking的目的。

觸發(fā)treeshking的三個(gè)要點(diǎn)

根據(jù)treeshking的原理,想要觸發(fā)treesking需要滿足3個(gè)條件:

1. 使用es module的模塊規(guī)范、使用解構(gòu)賦值

treeshking建立在es module靜態(tài)分析的基礎(chǔ)之上,所以代碼必須使用esm的規(guī)范。業(yè)務(wù)代碼一般都會(huì)使用esm,但是引入的第三方依賴就不一定了。比如lodash就是commonjs規(guī)范的,直接使用lodash是不會(huì)觸發(fā)treeshking的,解決方案就是使用lodash的esm版本lodash-es。

package.json中的main字段是node package的入口,但是是commonjs規(guī)范的。想要使用treeshking的功能必須使用esm的入口,所以rollup(最早的treeshking實(shí)現(xiàn))提出了module字段的提案,在這里配置es module的入口,這種約定雖然還沒(méi)有成為規(guī)范,但已經(jīng)被很多包所實(shí)現(xiàn)了。比如vue的package.json:

image

也有的包是esm規(guī)范的和commonsjs規(guī)范的分成了兩個(gè)包,比如lodash和lodash-es。

總之,業(yè)務(wù)代碼和第三方依賴都需要使用esm的規(guī)范。

然后引入的方式需要使用解構(gòu)賦值的方式,

import { get } from 'lodash';

這種寫法才可以在編譯期間就能確定用到了哪些export,而

import _ from 'lodash';

這種寫法無(wú)法在編譯期間確定用到了哪部分,所以也無(wú)法進(jìn)行treeshking。關(guān)于這點(diǎn)我做過(guò)測(cè)試,有興趣的同學(xué)也可以試下。(分別使用兩種引入方式,使用webpack-bundle-analyzer 分析打包出的bundle中l(wèi)odash這個(gè)模塊的大?。?/p>

2. 開(kāi)啟 optimization.usedExports

編譯時(shí)可以分析出解構(gòu)寫法引入的esm模塊,哪些export用到了,哪些模塊沒(méi)有用到。然后就需要分別進(jìn)行標(biāo)記,開(kāi)啟標(biāo)記的配置項(xiàng)就是 optimization.usedExports 。

標(biāo)記類似這樣:

/* harmony export (immutable) */ __webpack_exports__["xxx"] = xxxx;

/* unused harmony export xxx */

unused harmony export標(biāo)記的部分就是需要?jiǎng)h掉的。

3. 使用壓縮的插件

在編譯期間對(duì)不同模塊標(biāo)記之后,在壓縮時(shí)就可以刪掉沒(méi)用到的部分,任何一個(gè)壓縮的plugin都可以做到這個(gè)。

其實(shí)上面的2、3兩步,也就是開(kāi)啟optimization.usedExports和使用壓縮的插件,在webpack4的mode設(shè)置為production時(shí),已經(jīng)默認(rèn)開(kāi)啟了,所以開(kāi)發(fā)者只需要關(guān)心業(yè)務(wù)代碼和第三方包的模塊規(guī)范是不是es module,以及有沒(méi)有使用解構(gòu)賦值的引入方式。

treeshking的其他注意事項(xiàng)

1. 有副作用的模塊不能被treeshking

treeshking只是建立在某個(gè)es module的某一些export有沒(méi)有被用到的基礎(chǔ)上的,但是有一些代碼會(huì)有副作用,比如在window上掛一個(gè)變量、寫本地文件等,這種代碼雖然沒(méi)有export一些內(nèi)容,但也是不能被treeshking掉的。對(duì)于這些文件需要過(guò)濾掉,配置的方式就是在package.json中添加sideEffects字段,因?yàn)閣ebpack的模塊包括圖片、字體文件、css文件等,這些模塊都是需要配置的。

2. treeshking只能做到export級(jí)別

如果一些模塊導(dǎo)出了一個(gè)對(duì)象,用到這個(gè)模塊的地方只使用了某幾個(gè)方法,其余的方式是不能被treeshking的。原因也是因?yàn)榫幾g期間的靜態(tài)分析只能對(duì)es module的相關(guān)語(yǔ)法做分析,是不會(huì)真正去執(zhí)行代碼的。

所以為了更好的配合treeshking,能夠?qū)懗煞稚⒌膃xport的就不要封裝成對(duì)象,這樣能夠配置treeshking打包成最小的bundle。

總結(jié)

treeshking是減小打包的bundle size很重要的一個(gè)手段,但觸發(fā)treeshking是有條件的,首先需要代碼是es module規(guī)范的并且使用解構(gòu)賦值的方式引入,第二要開(kāi)始o(jì)ptimization.usedExports來(lái)標(biāo)記使用和未使用的模塊,第三是使用壓縮的插件進(jìn)行刪除未使用代碼。 webpack4的mode設(shè)置為production之后,我們只需要關(guān)心第一點(diǎn)就好了。

treeshking是有限制的,副作用的代碼不能treeshking,只能對(duì)export進(jìn)行treeshking。

了解了treeshking的原理和觸發(fā)條件,以及treeshking的限制,我們才能針對(duì)性的優(yōu)化代碼來(lái)達(dá)到最小的bundle size。當(dāng)然達(dá)到最優(yōu)可能還需要結(jié)合code spliting等其他方式。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容