十茉稠、webpack之打包優(yōu)化

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:

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
image.png

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ù)器自己支持哪些壓縮格式;


    image.png
  • 第三步:服務(wù)器在瀏覽器支持的壓縮格式下额衙,直接返回對應(yīng)的壓縮后的文件饮焦,并且在響應(yīng)頭中告知瀏覽器;


    image.png

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即可:


image.png

6. HTML文件中代碼的壓縮

我們之前使用了HtmlWebpackPlugin插件來生成HTML的模板习绢,事實上它還有一些其他的配置:
inject:設(shè)置打包的資源插入的位置

  • true索抓、 false 、body毯炮、head

cache:設(shè)置為true,只有當(dāng)文件改變時耸黑,才會生成新的文件(默認(rèn)值也是true)
minify:默認(rèn)會使用一個插件html-minifier-terser


image.png

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
image.png

8. 封裝Library

webpack可以幫助我們打包自己的庫文件搜锰,比如我們需要打包一個coderwhy_utils的一個庫。


image.png

配置webpack.config.js文件


image.png

image.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末耿战,一起剝皮案震驚了整個濱河市蛋叼,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌剂陡,老刑警劉巖狈涮,帶你破解...
    沈念sama閱讀 216,919評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異鸭栖,居然都是意外死亡歌馍,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,567評論 3 392
  • 文/潘曉璐 我一進店門晕鹊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來松却,“玉大人,你說我怎么就攤上這事溅话∠停” “怎么了?”我有些...
    開封第一講書人閱讀 163,316評論 0 353
  • 文/不壞的土叔 我叫張陵公荧,是天一觀的道長带射。 經(jīng)常有香客問我,道長循狰,這世上最難降的妖魔是什么窟社? 我笑而不...
    開封第一講書人閱讀 58,294評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮绪钥,結(jié)果婚禮上灿里,老公的妹妹穿的比我還像新娘。我一直安慰自己程腹,他們只是感情好匣吊,可當(dāng)我...
    茶點故事閱讀 67,318評論 6 390
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著寸潦,像睡著了一般色鸳。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上见转,一...
    開封第一講書人閱讀 51,245評論 1 299
  • 那天命雀,我揣著相機與錄音,去河邊找鬼斩箫。 笑死吏砂,一個胖子當(dāng)著我的面吹牛撵儿,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播狐血,決...
    沈念sama閱讀 40,120評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼淀歇,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了匈织?” 一聲冷哼從身側(cè)響起浪默,我...
    開封第一講書人閱讀 38,964評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎报亩,沒想到半個月后浴鸿,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,376評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡弦追,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,592評論 2 333
  • 正文 我和宋清朗相戀三年岳链,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片劲件。...
    茶點故事閱讀 39,764評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡掸哑,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出零远,到底是詐尸還是另有隱情苗分,我是刑警寧澤,帶...
    沈念sama閱讀 35,460評論 5 344
  • 正文 年R本政府宣布牵辣,位于F島的核電站摔癣,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏纬向。R本人自食惡果不足惜择浊,卻給世界環(huán)境...
    茶點故事閱讀 41,070評論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望逾条。 院中可真熱鬧琢岩,春花似錦、人聲如沸师脂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,697評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽吃警。三九已至糕篇,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間酌心,已是汗流浹背娩缰。 一陣腳步聲響...
    開封第一講書人閱讀 32,846評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留谒府,地道東北人拼坎。 一個月前我還...
    沈念sama閱讀 47,819評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像完疫,于是被迫代替她去往敵國和親泰鸡。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,665評論 2 354

推薦閱讀更多精彩內(nèi)容