webpack搖樹(shù)的原理的實(shí)現(xiàn)小結(jié)
Webpack 的 Tree Shaking(搖樹(shù))是一項(xiàng)用于消除 JavaScript 上下文中未引用代碼的優(yōu)化手段,它能有效減小打包體積。
核心原理
Tree Shaking 的本質(zhì)是 ?死代碼消除?,它依賴(lài) ?ES6 模塊(ESM)的靜態(tài)語(yǔ)法結(jié)構(gòu)?。
?靜態(tài)分析?:ESM 的 import/export 語(yǔ)句必須位于模塊頂層(注意:模塊頂層不是模塊文件頂部的意思,模塊頂層可以認(rèn)為是模塊文件中最外層的代碼區(qū),不在任何函數(shù)、類(lèi)或代碼塊內(nèi)部),且模塊路徑必須是字符串常量。這樣, Webpack 在編譯階段就能構(gòu)建出完整的模塊依賴(lài)圖,無(wú)需運(yùn)行代碼即可分析出哪些導(dǎo)出值未被其他模塊使用 。
這時(shí)有同學(xué)就會(huì)問(wèn)了,那么動(dòng)態(tài) import 怎么判斷呢?
其實(shí),還是那個(gè)關(guān)鍵點(diǎn),是否可以被“靜態(tài)分析”。
// ? 難以靜態(tài)分析,無(wú)法使用搖樹(shù)優(yōu)化
const componentMap = {
basic: () => import('./BasicComponent'),
advanced: () => import('./AdvancedComponent')
};
const getComponent = componentMap[userInput]; // 運(yùn)行時(shí)才能確定
// ? 條件明確,可以被靜態(tài)分析
if (import.meta.env.VITE_APP_MODE === 'basic') {
const BasicComponent = await import('./BasicComponent');
}
?標(biāo)記與清除?:Webpack 的 Tree Shaking 過(guò)程大致分為兩步。首先,在編譯階段,Webpack 會(huì)遍歷所有模塊,標(biāo)記(Mark) 出未被使用的導(dǎo)出(通常會(huì)在注釋中生成類(lèi)似 unused harmony export 的提示)。隨后,在代碼壓縮階段,Terser 等壓縮工具會(huì)真正將標(biāo)記過(guò)的"死代碼"清除(Shake) 掉 。
這些配置你是否清楚?
要讓 Tree Shaking 生效,需要同時(shí)滿足以下條件:
- ?使用 ES6 模塊語(yǔ)法?:必須使用
import和export語(yǔ)句。CommonJS 的require和module.exports是動(dòng)態(tài)的,無(wú)法在編譯時(shí)進(jìn)行靜態(tài)分析,因此不支持 Tree Shaking 。 - ?啟用生產(chǎn)模式或明確配置?:在 Webpack 配置中,將
mode設(shè)置為'production'生產(chǎn)模式下會(huì)自動(dòng)開(kāi)啟相關(guān)的優(yōu)化功能。當(dāng)然也可以在開(kāi)發(fā)模式下手動(dòng)配置optimization.usedExports和optimization.minimize。
// webpack.config.js
module.exports = {
mode: 'production', // 生產(chǎn)模式自動(dòng)開(kāi)啟優(yōu)化
optimization: {
usedExports: true, // 啟用使用導(dǎo)出分析
minimize: true // 啟用代碼壓縮(清除死代碼)
}
};
- ?**正確聲明副作用 (
sideEffects??)**?:在項(xiàng)目的package.json中,通過(guò)sideEffects屬性告知 Webpack 哪些文件是"純凈"的(無(wú)副作用),可以安全移除。這能防止具有副作用的文件(如全局樣式表、polyfill)被誤刪 。
// package.json
{
"sideEffects": false, // 表示整個(gè)項(xiàng)目都沒(méi)有副作用
// 或明確指定有副作用的文件
"sideEffects": [
"**/*.css",
"./src/polyfill.js"
]
}有同學(xué)又會(huì)問(wèn)了,搖樹(shù)搖的不是 js 嗎,樣式表 css 怎么會(huì)被搖掉呢?
其實(shí),這里指的是導(dǎo)入的但是沒(méi)有明確導(dǎo)出的 css 樣式表,導(dǎo)入導(dǎo)出是明確的 js 語(yǔ)句,css 是“副作用”,比如:
- 僅導(dǎo)入但未使用任何導(dǎo)出(如
import './style.css'),屬于是無(wú)形的“使用”,可能被誤刪 - 使用 CSS Modules(如
import styles from './Component.module.css'),被視為有被使用的對(duì)象(如styles.className),通常不會(huì)被誤刪
這些問(wèn)題你遇到過(guò)嗎?
開(kāi)發(fā)過(guò)程中,以下情況仍可能導(dǎo)致 Tree Shaking 失效,看看你有沒(méi)有遇到過(guò):
- ?Babel 配置不當(dāng)?:Babel 預(yù)設(shè)
@babel/preset-env可能會(huì)將 ESM 轉(zhuǎn)換為 CommonJS。務(wù)必確保其modules選項(xiàng)設(shè)置為false,只有 ESM 可以搖樹(shù)。
// .babelrc
{
"presets": [["@babel/preset-env", { "modules": false }]]
}- ?第三方庫(kù)的模塊版本?:優(yōu)先選擇提供 ES6 模塊版本的庫(kù)(如使用
lodash-es而非lodash),并采用按需導(dǎo)入的方式 。
// 推薦:按需導(dǎo)入
import { debounce } from 'lodash-es';
// 不推薦:整體導(dǎo)入
import _ from 'lodash';
- ?導(dǎo)出粒度太粗?:盡量使用具名導(dǎo)出而非默認(rèn)導(dǎo)出對(duì)象,有助于進(jìn)行更精細(xì)的分析 。
// 推薦:細(xì)粒度導(dǎo)出
export function func1() {}
export function func2() {}
// 謹(jǐn)慎使用:粗粒度導(dǎo)出(不利于分析內(nèi)部未使用屬性)
export default { func1, func2 };
到此這篇關(guān)于webpack搖樹(shù)的原理的實(shí)現(xiàn)小結(jié)的文章就介紹到這了,更多相關(guān)webpack搖樹(shù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JS庫(kù)之Particles.js中文開(kāi)發(fā)手冊(cè)及參數(shù)詳解
因?yàn)樽约盒枰霎a(chǎn)品,所以一個(gè)好的UI界面也是很重要的,發(fā)現(xiàn)這種散射的原子顆粒特效還不錯(cuò)。今天腳本之家小編把Particles.js中文開(kāi)發(fā)手冊(cè)及particles.js參數(shù)分享給大家,需要的朋友參考下吧2017-09-09
javascript定時(shí)器的簡(jiǎn)單應(yīng)用示例【控制方塊移動(dòng)】
這篇文章主要介紹了javascript定時(shí)器的簡(jiǎn)單應(yīng)用,結(jié)合javascript事件觸發(fā)控制方塊移動(dòng)操作分析了javascript定時(shí)器使用相關(guān)操作技巧,需要的朋友可以參考下2019-06-06
JavaScript 使用Ckeditor+Ckfinder文件上傳案例詳解
這篇文章主要介紹了JavaScript 使用Ckeditor+Ckfinder文件上傳案例詳解,本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08
js 判斷當(dāng)前時(shí)間是否處于某個(gè)一個(gè)時(shí)間段內(nèi)
這篇文章主要介紹了js 判斷當(dāng)前時(shí)間是否處于某個(gè)一個(gè)時(shí)間段內(nèi),使用 jutils - JavaScript常用函數(shù)庫(kù)的 isDuringDate 函數(shù)來(lái)實(shí)現(xiàn),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-09-09
javascript中tostring()和valueof()的用法及兩者的區(qū)別
基本上,所有JS數(shù)據(jù)類(lèi)型都擁有valueOf和toString這兩個(gè)方法,null除外。它們倆解決javascript值運(yùn)算與顯示的問(wèn)題,本文給大家介紹javascript中tostring()和valueof()的用法及兩者的區(qū)別,對(duì)js tostring valueof相關(guān)知識(shí)感興趣的朋友一起學(xué)習(xí)吧2015-11-11
javascript 緩沖運(yùn)動(dòng)框架的實(shí)現(xiàn)
這篇文章主要介紹了javascript 緩沖運(yùn)動(dòng)框架的實(shí)現(xiàn)的相關(guān)資料,希望通過(guò)本能幫助到大家,實(shí)現(xiàn)這樣類(lèi)似的功能,需要的朋友可以參考下2017-09-09
js實(shí)現(xiàn)時(shí)鐘定時(shí)器
這篇文章主要為大家詳細(xì)介紹了js實(shí)現(xiàn)時(shí)鐘定時(shí)器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-03-03

