1. Terser
1.1 Terser介紹和安裝
什么是Terser呢梯啤?
- Terser是一個JavaScript的解釋(Parser)颈墅、Mangler(絞肉機)/Compressor(壓縮機)的工具集;
- 早期我們會使用 uglify-js來壓縮茫舶、丑化我們的JavaScript代碼械巡,但是目前已經(jīng)不再維護,并且不支持ES6+的語法奇适;
- Terser是從 uglify-es fork 過來的坟比,并且保留它原來的大部分API以及適配 uglify-es和uglify-js@3等;
也就是說嚷往,Terser可以幫助我們壓縮、丑化我們的代碼柠衅,讓我們的bundle變得更小皮仁。
因為Terser是一個獨立的工具,所以它可以單獨安裝:
# 全局安裝
npm install terser -g
# 局部安裝
npm install terser
1.2 命令行使用Terser
我們可以在命令行中使用Terser:
terser [input files] [options]
# 舉例說明
terser js/file1.js -o foo.min.js -c -m
我們這里來講解幾個Compress option和Mangle option:
- 因為他們的配置非常多菲宴,我們不可能一個個解析贷祈,更多的查看文檔即可;
- https://github.com/terser/terser#compress-options
- https://github.com/terser/terser#mangle-options
1.3 Compress和Mangle的options
Compress option:
- arrows:class或者object中的函數(shù)喝峦,轉(zhuǎn)換成箭頭函數(shù)势誊;
- arguments:將函數(shù)中使用 arguments[index]轉(zhuǎn)成對應(yīng)的形參名稱;
- dead_code:移除不可達(dá)的代碼(tree shaking)谣蠢;
Mangle option:
- toplevel:默認(rèn)值是false粟耻,頂層作用域中的變量名稱,進行丑化(轉(zhuǎn)換)眉踱;
- keep_classnames:默認(rèn)值是false挤忙,是否保持依賴的類名稱;
- keep_fnames:默認(rèn)值是false谈喳,是否保持原來的函數(shù)名稱册烈;
npx terser ./src/abc.js -o abc.min.js -c
arrows,arguments=true,dead_code -m
toplevel=true,keep_classnames=true,keep_fnames=true
1.4 Terser在webpack中配置
真實開發(fā)中,我們不需要手動的通過terser來處理我們的代碼婿禽,我們可以直接通過webpack來處理:
- 在webpack中有一個minimizer屬性赏僧,在production模式下大猛,默認(rèn)就是使用TerserPlugin來處理我們的代碼的;
- 如果我們對默認(rèn)的配置不滿意淀零,也可以自己來創(chuàng)建TerserPlugin的實例挽绩,并且覆蓋相關(guān)的配置;
首先窑滞,我們需要打開minimize琼牧,讓其對我們的代碼進行壓縮(默認(rèn)production模式下已經(jīng)打開了)
其次,我們可以在minimizer創(chuàng)建一個TerserPlugin(webpack5默認(rèn)安裝了):
- extractComments:默認(rèn)值為true哀卫,表示會將注釋抽取到一個單獨的文件中巨坊;
- 在開發(fā)中,我們不希望保留這個注釋時此改,可以設(shè)置為false趾撵;
- parallel:使用多進程并發(fā)運行提高構(gòu)建的速度,默認(rèn)值是true共啃,并發(fā)運行的默認(rèn)數(shù)量: os.cpus().length - 1占调;
- 我們也可以設(shè)置自己的個數(shù),但是使用默認(rèn)值即可移剪;
- terserOptions:設(shè)置我們的terser相關(guān)的配置
- compress:設(shè)置壓縮相關(guān)的選項究珊;
- mangle:設(shè)置丑化相關(guān)的選項,可以直接設(shè)置為true纵苛;
- toplevel:底層變量是否進行轉(zhuǎn)換剿涮;
- keep_classnames:保留類的名稱;
- keep_fnames:保留函數(shù)的名稱攻人;
2. CSS的壓縮
另一個代碼的壓縮是CSS:
- CSS壓縮通常是去除無用的空格等取试,因為很難去修改選擇器、屬性的名稱怀吻、值等瞬浓;
- CSS的壓縮我們可以使用另外一個插件:css-minimizer-webpack-plugin;
- css-minimizer-webpack-plugin是使用cssnano工具來優(yōu)化蓬坡、壓縮CSS(也可以單獨使用)鞍泉;
第一步腮鞍,安裝 css-minimizer-webpack-plugin:
yarn add css-minimizer-webpack-plugin -D
第二步衷旅,在optimization.minimizer中配置
plugins: [
new CssMinimizerPlugin(),
]
3. Scope Hoisting
什么是Scope Hoisting呢障涯?
- Scope Hoisting從webpack3開始增加的一個新功能;
- 功能是對作用域進行提升乔宿,并且讓webpack打包后的代碼更小位迂、運行更快;
默認(rèn)情況下webpack打包會有很多的函數(shù)作用域,包括一些(比如最外層的)IIFE:
- 無論是從最開始的代碼運行掂林,還是加載一個模塊臣缀,都需要執(zhí)行一系列的函數(shù)
- Scope Hoisting可以將函數(shù)合并到一個模塊中來運行;
使用Scope Hoisting非常的簡單泻帮,webpack已經(jīng)內(nèi)置了對應(yīng)的模塊:
- 在production模式下精置,默認(rèn)這個模塊就會啟用;
- 在development模式下锣杂,我們需要自己來打開該模塊脂倦;
plugins: [
new webpack.optimize.ModuleConcatenationPlugin()
]
4. Tree Shaking
4.1 什么是Tree Shaking
什么是Tree Shaking呢?
- Tree Shaking是一個術(shù)語元莫,在計算機中表示消除死代碼(dead_code)赖阻;
- 最早的想法起源于LISP,用于消除未調(diào)用的代碼(純函數(shù)無副作用踱蠢,可以放心的消除火欧,這也是為什么要求我們在進行函數(shù)式編程時,盡量使用純函數(shù)的原因之一)茎截;
- 后來Tree Shaking也被應(yīng)用于其他的語言苇侵,比如JavaScript、Dart企锌;
JavaScript的Tree Shaking:
- 對JavaScript進行Tree Shaking是源自打包工具rollup(后面我們也會講的構(gòu)建工具)榆浓;
- 這是因為Tree Shaking依賴于ES Module的靜態(tài)語法分析(不執(zhí)行任何的代碼,可以明確知道模塊的依賴關(guān)系)撕攒;
- webpack2正式內(nèi)置支持了ES2015模塊哀军,和檢測未使用模塊的能力;
- 在webpack4正式擴展了這個能力打却,并且通過 package.json的 sideEffects屬性作為標(biāo)記,告知webpack在編譯時谎倔,哪里文件可以安全的刪除掉柳击;
- webpack5中,也提供了對部分CommonJS的tree shaking的支持片习;
https://github.com/webpack/changelog-v5
4.2 webpack實現(xiàn)Tree Shaking
事實上webpack實現(xiàn)Tree Shaking采用了兩種不同的方案:
- usedExports:通過標(biāo)記某些函數(shù)是否被使用捌肴,之后通過Terser來進行優(yōu)化的;
- sideEffects:跳過整個模塊/文件藕咏,直接查看該文件是否有副作用状知;
4.2.1 usedExports
將mode設(shè)置為development模式:
- 為了可以看到 usedExports帶來的效果,我們需要設(shè)置為 development 模式
- 因為在 production 模式下孽查,webpack默認(rèn)的一些優(yōu)化會帶來很大額影響饥悴。
設(shè)置usedExports為true和false對比打包后的代碼:
- 在usedExports設(shè)置為true時,會有一段注釋:unused harmony export mul;
- 這段注釋的意義是什么呢西设?告知Terser在優(yōu)化時瓣铣,可以刪除掉這段代碼;
這個時候贷揽,我們j將minimize設(shè)置true:
- usedExports設(shè)置為false時棠笑,mul函數(shù)沒有被移除掉;
- usedExports設(shè)置為true時禽绪,mul函數(shù)有被移除掉蓖救;
所以,usedExports實現(xiàn)Tree Shaking是結(jié)合Terser來完成的印屁。
optimization: {
usedExports: true, // production自動設(shè)置為true
minimize: true,
minimizer: {
...
}
}
4.2.2 sideEffects
sideEffects用于告知webpack compiler哪些模塊時有副作用的:
- 副作用的意思是這里面的代碼有執(zhí)行一些特殊的任務(wù)循捺,不能僅僅通過export來判斷這段代碼的意義;
- 副作用的問題库车,在講React的純函數(shù)時是有講過的巨柒;
在package.json中設(shè)置sideEffects的值:
- 如果我們將sideEffects設(shè)置為false,就是告知webpack可以安全的刪除未用到的exports柠衍;
- 如果有一些我們希望保留洋满,可以設(shè)置為數(shù)組;
比如我們有一個format.js珍坊、style.css文件:
- 該文件在導(dǎo)入時沒有使用任何的變量來接受牺勾;
- 那么打包后的文件,不會保留format.js阵漏、style.css相關(guān)的任何代碼驻民;
- 可以在處理css的loader加入
sideEffects: true
4.2.3 Webpack中tree shaking的設(shè)置
所以,如何在項目中對JavaScript的代碼進行TreeShaking呢(生成環(huán)境)履怯?
- 在optimization中配置usedExports為true回还,來幫助Terser進行優(yōu)化;
- 在package.json中配置sideEffects叹洲,直接對模塊進行優(yōu)化柠硕;
4.3 CSS實現(xiàn)Tree Shaking
上面我們學(xué)習(xí)的都是關(guān)于JavaScript的Tree Shaking,那么CSS是否也可以進行Tree Shaking操作呢运提?
- CSS的Tree Shaking需要借助于一些其他的插件蝗柔;
- 在早期的時候,我們會使用PurifyCss插件來完成CSS的tree shaking民泵,但是目前該庫已經(jīng)不再維護了(最新更新也是在4年前了)癣丧;
- 目前我們可以使用另外一個庫來完成CSS的Tree Shaking:PurgeCSS,也是一個幫助我們刪除未使用的CSS的工具栈妆;
安裝PurgeCss的webpack插件:
npm install purgecss-webpack-plugin -D
4.3.1 配置PurgeCss
配置這個插件(生產(chǎn)環(huán)境):
- paths:表示要檢測哪些目錄下的內(nèi)容需要被分析胁编,這里我們可以使用glob(webpack默認(rèn)安裝了)厢钧;
- 默認(rèn)情況下,Purgecss會將我們的html掏呼、body標(biāo)簽的樣式移除掉坏快,如果我們希望保留,可以添加一個safelist的屬性憎夷;
new PurgeCssPlugin({
paths: glob.sync(`${resolveApp("./src")}/**/*`, {nodir: true}),
safelist: function() {
return {
standard: ["body", "html"]
}
}
})
purgecss也可以對less文件進行處理(所以它是對打包后的css進行tree shaking操作)莽鸿;
5. HTTP壓縮
5.1 什么是HTTP壓縮?
HTTP壓縮是一種內(nèi)置在 服務(wù)器 和 客戶端 之間的拾给,以改進傳輸速度和帶寬利用率的方式祥得;
HTTP壓縮的流程什么呢?
- 第一步:HTTP數(shù)據(jù)在服務(wù)器發(fā)送前就已經(jīng)被壓縮了蒋得;(可以在webpack中完成)
-
第二步:兼容的瀏覽器在向服務(wù)器發(fā)送請求時级及,會告知服務(wù)器自己支持哪些壓縮格式;
-
第三步:服務(wù)器在瀏覽器支持的壓縮格式下额衙,直接返回對應(yīng)的壓縮后的文件饮焦,并且在響應(yīng)頭中告知瀏覽器;
5.2 目前的壓縮格式
目前的壓縮格式非常的多:
- compress – UNIX的“compress”程序的方法(歷史性原因窍侧,不推薦大多數(shù)應(yīng)用使用县踢,應(yīng)該使用gzip或deflate);
- deflate – 基于deflate算法(定義于RFC 1951)的壓縮伟件,使用zlib數(shù)據(jù)格式封裝硼啤;
- gzip – GNU zip格式(定義于RFC 1952),是目前使用比較廣泛的壓縮算法斧账;
- br – 一種新的開源壓縮算法谴返,專為HTTP內(nèi)容的編碼而設(shè)計
5.3 Webpack對文件壓縮
webpack中相當(dāng)于是實現(xiàn)了HTTP壓縮的第一步操作,我們可以使用CompressionPlugin咧织。
第一步嗓袱,安裝CompressionPlugin:
npm install compression-webpack-plugin -D
第二步,使用CompressionPlugin即可:
6. HTML文件中代碼的壓縮
我們之前使用了HtmlWebpackPlugin插件來生成HTML的模板习绢,事實上它還有一些其他的配置:
inject:設(shè)置打包的資源插入的位置
- true索抓、 false 、body毯炮、head
cache:設(shè)置為true,只有當(dāng)文件改變時耸黑,才會生成新的文件(默認(rèn)值也是true)
minify:默認(rèn)會使用一個插件html-minifier-terser
7. InlineChunkHtmlPlugin
另外有一個插件桃煎,可以輔助將一些chunk出來的模塊,內(nèi)聯(lián)到html中:
- 比如runtime的代碼大刊,代碼量不大为迈,但是是必須加載的三椿;
- 那么我們可以直接內(nèi)聯(lián)到html中;
這個插件是在react-dev-utils中實現(xiàn)的葫辐,所以我們可以安裝一下它:
npm install react-dev-utils -D
8. 封裝Library
webpack可以幫助我們打包自己的庫文件搜锰,比如我們需要打包一個coderwhy_utils的一個庫。
配置webpack.config.js文件