??上一章節(jié)主要介紹了webpack的進(jìn)階篇中的一些高階功能的使用和配置,這些還能在代碼中進(jìn)行一些配置、構(gòu)建?,F(xiàn)在來主要介紹一些webpack4特性原理分析,可能會(huì)比較枯燥,但是很實(shí)用。
1.Tree Shaking的使用和與案例分析

注:當(dāng)mode設(shè)置production的時(shí)候TreeShaking是默認(rèn)開啟的
(1)什么是DCE
我們了解tree shaking的之前,就要先了解一個(gè)概念DCE。

意思就是說沒有用到的代碼,就會(huì)被“殺死”;什么是DCE代碼呢?如上圖左邊寫的要求:
代碼不被執(zhí)行,不可到達(dá):不會(huì)執(zhí)行的代碼,如if(false) {}這條if就回永遠(yuǎn)不被執(zhí)行;
代碼執(zhí)行的結(jié)果不會(huì)被用到:這句話的含義是指定義了一個(gè)函數(shù),并且return一個(gè)結(jié)果,但是在調(diào)用這個(gè)函數(shù)時(shí),這個(gè)結(jié)果永遠(yuǎn)不會(huì)用到;
代碼只會(huì)影響死變量(只寫不讀):這句話的含義是當(dāng)我們定義了一個(gè)變量,并且給這個(gè)變量設(shè)置了數(shù)據(jù),但是永遠(yuǎn)沒有用到這個(gè)變量。
只要符合上述的三個(gè)要求,就是DCE代碼,在構(gòu)建的過程中就會(huì)把這些代碼刪除掉,不會(huì)打包到bundle中。
(2)tree shaking原理

(3)tree shaking 實(shí)戰(zhàn)演練
① 自定義一個(gè)js文件

② 在js文件里應(yīng)用a方法

③ 配置webpack.prod.js
- 未開啟tree shaking的情況
設(shè)置mode為none,因?yàn)閠ree shaking在mode為production的情況下是默認(rèn)開啟的,npm run build構(gòu)建項(xiàng)目,情況如下
QQ截圖20200822203558.png
可以看到我們只是在js文件中只引用了a方法,但是沒有進(jìn)行任何的調(diào)用,構(gòu)建的時(shí)候把這兩個(gè)方法都打包了進(jìn)來,顯然會(huì)增加項(xiàng)目的體積 - 開啟tree shaking的情況
設(shè)置mode為production
QQ截圖20200822204035.png
可以發(fā)現(xiàn)這兩個(gè)方法都沒有引用進(jìn)來 -
使用a方法,并且開啟tree shaking
QQ截圖20200822204321.png
構(gòu)建項(xiàng)目
QQ截圖20200822204510.png
可見a方法是調(diào)用到了,再來搜索一下b方法
QQ截圖20200822204629.png
b方法并沒有加載進(jìn)來,從而達(dá)到了tree shaking的目的。
-
其他
QQ截圖20200822204911.png
上述情況,雖然引用了a方法,看看構(gòu)建的時(shí)候是否將a方法引用了進(jìn)來
QQ截圖20200822205041.png
可以看到a方法并沒有打包進(jìn)來。
2.Scope Hoisting使用和原理分析
我們先來看下webpack在沒有使用該特性的情況下,webpack構(gòu)件時(shí)的包效果如下

可以發(fā)下產(chǎn)生了很多的閉包函數(shù),這樣會(huì)產(chǎn)生什么樣的后果呢?如下

這就有個(gè)問題,為什么webpack打包會(huì)產(chǎn)生這么多的閉包呢?是因?yàn)?strong>模塊轉(zhuǎn)換


(1)scope hoisting原理

(2)scope hoisting使用

(3)實(shí)戰(zhàn)演練
① 未開啟scope hoisting的情況

構(gòu)建項(xiàng)目

① 開啟scope hoisting的情況

構(gòu)建項(xiàng)目

3.代碼分割和動(dòng)態(tài)import
前面學(xué)過基礎(chǔ)庫分離,講述過SplitChunksPlugin插件,將頁面進(jìn)行分離,但這只是基礎(chǔ)分離,現(xiàn)在來看一下高階的代碼分割和動(dòng)態(tài)import

(1)js懶加載的方式

有兩種懶加載的方式,如上圖所述
- CommonJS: require.ensure;
- 動(dòng)態(tài)import(推薦);
目前動(dòng)態(tài)import能夠兼容好webpack。這節(jié)主要講述import
(2)如何使用動(dòng)態(tài)import

分割后的效果如下

(2)動(dòng)態(tài)import實(shí)戰(zhàn)演練
第一步安裝babel插件
npm install @babel/plugin-syntax-dynamic-import --save-dev
第二步
配置.babelrc文件

第三步創(chuàng)建一個(gè)text.js文件,如下

第四步在index.js下做如下配置

最后一步:npm run build
4.webpack中使用eslint
使用eslint能夠規(guī)范代碼,便于團(tuán)隊(duì)合作,能夠避免一些不必要的錯(cuò)誤。






5.webpack 打包庫和組件
面試題

壓縮版:適用于開發(fā)階段;
非壓縮版:適用于發(fā)布上線;


除了上面的引用方式還支持


(1)實(shí)戰(zhàn)演練
① 創(chuàng)建項(xiàng)目
mkdir large-number
cd large-number
npm init
② 搭建webpack環(huán)境
npm install webpack webpack-cli -D
③ 重構(gòu)項(xiàng)目目錄

src/index.js代碼如下
export default function add(a, b) {
let i = a.length - 1;
let j = b.length - 1;
let carry = 0;
let ret = '';
while(i >= 0 || j >= 0) {
let x = 0;
let y = 0;
let sum;
if(i >= 0) {
x = a[i] - '0'; // 轉(zhuǎn)成數(shù)字
i--;
}
if(j >= 0) {
y = b[j] - '0'; // 轉(zhuǎn)成數(shù)字
j--;
}
sum = x + y + carry;
if(sum >= 10) {
carry = 1;
sum -= 10;
} else {
carry = 0;
}
ret = sum + ret;
}
if(carry) {
ret = carry + ret;
}
return ret;
}
// add('999', '1');
④ 編寫webpack配置文件
module.exports = {
entry: {
'large-number': './src/index.js',
'large-number.min': './src/index.js'
},
output: {
filename: '[name].js',
library: 'largeNumber',
libraryTarget: 'umd',
libraryExport: 'default'
}
}
// libraryExport:最好設(shè)置成default,不然引用的時(shí)候,就要在方法后面加上default,顯得過于冗余
⑤ 配置package.json文件

⑥ 打包構(gòu)建
npm run build

然后打開項(xiàng)目目錄中的dist文件夾

我們打開這兩個(gè)文件,發(fā)現(xiàn)都被壓縮了,不符合我們的需求(開發(fā)版是非壓縮版,非開發(fā)版是壓縮版),那么怎么辦呢?如下

如上圖,將mode設(shè)置成none,關(guān)閉默認(rèn)壓縮,然后添加一個(gè)optimization,將minimize設(shè)置成true,然后通過配置minimizer設(shè)置正則匹配,只對(duì)mini.js進(jìn)行壓縮即可。
注:我們使用了TerserPlugin這個(gè)壓縮插件,他可以針對(duì)ES6的語法進(jìn)行壓縮,如果使用有些插件,就不會(huì)針對(duì)es6進(jìn)行壓縮,可能會(huì)報(bào)錯(cuò),所以推薦使用TerserPlugin,因此我們要先安裝一下這個(gè)插件
npm install terser-webpack-plugin -D安裝好之后,在webpack.config.js頭部導(dǎo)入進(jìn)來

最后重新打包,發(fā)現(xiàn)只有mini.js文件進(jìn)行了壓縮

總結(jié)
這借主要介紹了一寫webpack的原理,下節(jié)是進(jìn)階的完結(jié)篇來源






