Webpack 與 Rollup 中 Tree-shaking 的實(shí)現(xiàn)原理與效果
Tree-shaking 是現(xiàn)代前端構(gòu)建工具中用于消除死代碼(未被使用的代碼)的重要優(yōu)化手段,核心原理是利用 ES6 模塊的靜態(tài)特性(import/export)分析代碼依賴(lài),剔除未被引用的導(dǎo)出內(nèi)容。
一、Tree-shaking 核心前提
Tree-shaking 僅對(duì) ES6 模塊(ESM) 有效,因?yàn)?ESM 具有以下靜態(tài)特性:
- 模塊依賴(lài)關(guān)系在編譯時(shí)確定(而非運(yùn)行時(shí))。
import/export語(yǔ)句只能出現(xiàn)在模塊頂層,無(wú)法動(dòng)態(tài)修改。
CommonJS 模塊(require/module.exports)因依賴(lài)關(guān)系動(dòng)態(tài)化,無(wú)法被 Tree-shaking 優(yōu)化。
二、Rollup 中的 Tree-shaking
Rollup 是專(zhuān)注于 ES 模塊打包的工具,Tree-shaking 是其原生核心功能,實(shí)現(xiàn)簡(jiǎn)潔且高效。
1. 實(shí)現(xiàn)原理
Rollup 通過(guò)以下步驟實(shí)現(xiàn) Tree-shaking:
- 依賴(lài)解析:遍歷模塊的
import/export語(yǔ)句,構(gòu)建模塊依賴(lài)圖。 - 標(biāo)記未使用代碼:從入口模塊出發(fā),追蹤所有被引用的導(dǎo)出(
export),未被引用的導(dǎo)出被標(biāo)記為 “死代碼”。 - 刪除死代碼:在打包階段直接剔除標(biāo)記的死代碼,不生成冗余內(nèi)容。
Rollup 對(duì)代碼的靜態(tài)分析更徹底,且默認(rèn)輸出未被混淆的代碼,因此 Tree-shaking 效果直觀可見(jiàn)。
2. 代碼示例與效果
源文件
// utils.js(ES 模塊)
export const add = (a, b) => a + b;
export const minus = (a, b) => a - b; // 未被使用的函數(shù)
// index.js(入口文件)
import { add } from './utils.js';
console.log(add(1, 2)); // 僅使用 add
Rollup 配置(rollup.config.js)
export default {
input: 'src/index.js',
output: {
file: 'dist/bundle.js',
format: 'es' // 輸出 ES 模塊(保留 import/export,便于觀察)
}
};
打包結(jié)果(dist/bundle.js)
const add = (a, b) => a + b; console.log(add(1, 2));
- 效果:未被使用的
minus函數(shù)被完全剔除,輸出代碼簡(jiǎn)潔。
三、Webpack 中的 Tree-shaking
Webpack 從 v2 開(kāi)始支持 Tree-shaking,但實(shí)現(xiàn)邏輯更復(fù)雜,受多種因素影響(如模式、壓縮工具等)。
1. 實(shí)現(xiàn)原理
Webpack 的 Tree-shaking 分為三個(gè)階段:
標(biāo)記階段:
- 解析 ES 模塊的
import/export,通過(guò)ModuleConcatenationPlugin分析模塊依賴(lài)。 - 對(duì)未被引用的導(dǎo)出標(biāo)記為
/* unused harmony export xxx */(僅標(biāo)記,不刪除)。
- 解析 ES 模塊的
刪除階段:
- 依賴(lài) 壓縮工具(如 Terser) 剔除標(biāo)記的死代碼。
- 僅在
production模式下默認(rèn)啟用(開(kāi)發(fā)模式為保留代碼不刪除)。
副作用處理:
- 通過(guò)
package.json的sideEffects字段標(biāo)記模塊是否有副作用(如全局變量修改、DOM 操作),避免誤刪有副作用的代碼。
- 通過(guò)
2. 代碼示例與效果
源文件(同 Rollup 示例)
// utils.js
export const add = (a, b) => a + b;
export const minus = (a, b) => a - b; // 未被使用
// index.js
import { add } from './utils.js';
console.log(add(1, 2));
Webpack 配置(webpack.config.js)
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
mode: 'production' // 必須為 production 模式才會(huì)刪除死代碼
};
打包結(jié)果(dist/bundle.js,簡(jiǎn)化后)
console.log(3); // add(1,2) 被直接計(jì)算,minus 完全刪除
- 效果:未被使用的
minus被剔除,且add函數(shù)因邏輯簡(jiǎn)單被進(jìn)一步優(yōu)化(直接計(jì)算結(jié)果)。
3. 關(guān)鍵配置:sideEffects
如果模塊存在副作用(如修改全局變量),需在 package.json 中聲明,避免被誤刪:
json
{
"sideEffects": [
"./src/polyfill.js", // 有副作用的模塊
"*.css" // CSS 文件通常有副作用(插入樣式)
]
}
sideEffects: false:表示所有模塊均無(wú)副作用,可安全刪除未引用代碼。
四、核心差異對(duì)比
| 特性 | Rollup | Webpack |
|---|---|---|
| 分析能力 | 原生支持 ESM 靜態(tài)分析,更徹底 | 需依賴(lài)插件(ModuleConcatenationPlugin),分析邏輯較復(fù)雜 |
| 刪除死代碼時(shí)機(jī) | 打包階段直接刪除 | 依賴(lài)壓縮工具(Terser)在優(yōu)化階段刪除 |
| 開(kāi)發(fā)模式效果 | 即使開(kāi)發(fā)模式也會(huì)刪除死代碼 | 僅 production 模式刪除(開(kāi)發(fā)模式保留用于調(diào)試) |
| 輸出可讀性 | 輸出代碼接近源碼,Tree-shaking 效果直觀 | 輸出代碼經(jīng)壓縮混淆,效果需反推 |
| 適用場(chǎng)景 | 庫(kù)文件打包(如工具庫(kù)、組件庫(kù)) | 應(yīng)用程序打包(依賴(lài)復(fù)雜、需處理多種模塊類(lèi)型) |
五、總結(jié)
- Rollup:Tree-shaking 實(shí)現(xiàn)簡(jiǎn)潔高效,輸出代碼干凈,適合庫(kù)文件打包(如 React、Vue 等)。
- Webpack:Tree-shaking 需配合壓縮工具和模式配置,功能更全面(支持多種模塊類(lèi)型、復(fù)雜依賴(lài)),適合應(yīng)用程序打包。
六、直觀點(diǎn)
- 整個(gè)過(guò)程就像 “清理房間”:先摸清房間里的物品(依賴(lài)解析)→ 標(biāo)記沒(méi)用的垃圾(標(biāo)記死代碼)→ 直接扔掉垃圾(刪除死代碼);
- 對(duì)比 Webpack :Rollup 是 “邊打包邊扔垃圾”,Webpack 是 “先標(biāo)記垃圾,最后找清潔工(Terser)扔”,所以 Rollup 的產(chǎn)物更直觀看到剔除效果。
到此這篇關(guān)于Webpack 與 Rollup 中 Tree-shaking 的實(shí)現(xiàn)原理與效果的文章就介紹到這了,更多相關(guān)Webpack Rollup Tree-shakin實(shí)現(xiàn)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Javascript模塊化機(jī)制實(shí)現(xiàn)原理詳解
這篇文章主要介紹了Javascript模塊化機(jī)制實(shí)現(xiàn)原理詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04
在JavaScript中call()與apply()區(qū)別
這篇文章主要介紹了在JavaScript中call()與apply()區(qū)別 的相關(guān)資料,需要的朋友可以參考下2016-01-01
一個(gè)JavaScript處理textarea中的字符成每一行實(shí)例
這篇文章主要與大家分享一個(gè)JavaScript處理textarea中的字符成每一行實(shí)例,很簡(jiǎn)單,但很實(shí)用,大家可以看看2014-09-09
Bootstrap學(xué)習(xí)筆記之css樣式設(shè)計(jì)(1)
這篇文章主要為大家詳細(xì)介紹了bootstrap學(xué)習(xí)筆記之css樣式設(shè)計(jì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-06-06
javascript使用正則表達(dá)式實(shí)現(xiàn)注冊(cè)登入校驗(yàn)
這篇文章主要為大家詳細(xì)介紹了javascript使用正則表達(dá)式實(shí)現(xiàn)注冊(cè)登入校驗(yàn),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-09-09
CocosCreator怎樣使用cc.follow進(jìn)行鏡頭跟隨
這篇文章主要介紹了CocosCreator怎樣使用cc.follow進(jìn)行鏡頭跟隨,想要學(xué)習(xí)follow的同學(xué),一定要看一下2021-04-04
淺析Javascript ES6新增值比較函數(shù)Object.is
在Javascript中判斷相等是很常見(jiàn)的,常用的判斷有“==”,“===”,“!=”,“!==”,今天這篇文章我們來(lái)學(xué)習(xí)ES6中的一個(gè)方法Object.is(),有需要的可以參考學(xué)習(xí)。2016-08-08

