Tree-shaking 的 sideEffects、optimization 設定
Table of Contents
什麼是 side effect?
根據 Webpack 官方文件,這裡的 side effect 是指當我們在 import 某個模組時,這個模組裡除了明確被 export 出來的內容外,還額外會在 import 時去執行某些操作的代碼,就稱為 side effect。
舉個例子,在前面起始專案中的 array.js
內容是這樣:
當你在 import 這個模組時,雖然 array.js
裡沒有把 console.log
的內容去做 export,但這段程式碼仍然會被執行,這就是 side effect。
另一種 side effect 的經典例子是 polyfill,參考下面這個例子,因為 polyfill 通常不提供 export 而是直接去對整個 global scope 作用,因此也會有 side effect:
回到正題,Webpack 在打包時也能參考 package.json
中的 sideEffects
設定來判斷是否要移除確定沒有副作用的程式碼,以下來實驗看看。
把 package.json
中的 sideEffects
選項拿掉後,進行 production build:
在 package.json 中加上 sideEffects 選項後,進行 production build:
可以注意到差別在 array.js
中的 flattenDeep 前的 console.log
是否被移除的差別,也就可以確認 sideEffect 這個選項的用途與使用方式,當你想保留那些你有 import 的內容,但實際沒被 export 的,可以加在 sideEffects 的陣列中告訴 Webpack 這些路徑的 pattern 有副作用,不需要幫我移除掉。
另外比較常見的是 side effect 如 import ‘./style.scss;
這樣的樣式檔,為了避免在過程中被錯誤 shake 掉,也記得加入到 sideEffects array 中:
Webpack 的 optimization 設定
接下來講幾個 Webpack 不好懂且容易搞混的 optimization 與 tree-shaking 有相關的選項。這些選項在 production mode 預設都會被啟用,所以其實不需要做什麼特別設定專案就會自動完成 tree-shaking 的配置了。
optimization.sideEffects
你可能會說,這個 sideEffects 跟 package.json 中的 sideEffect 有什麼差別,沒錯,他們有關但不是指同一件事。
這個 optimization.sideEffects
指的是「告訴 Webpack 是否要去看 package.json 中的 sideEffects 選項」,可能有點難懂。
一樣看個範例試試看這樣的配置,並去執行 production build:
可以看到最後 side effect 的 console.log("[flattenDeep] declared here!")
沒有被移除,這是因為在 optimization.sideEffects
中你請 Webpack 在打包時不要去參考 package.json 中的 sideEffects 選項,因此得到這樣的結果。
總歸來說,這個選項是 Webpack 提供一個彈性讓你可以開關是否要去參考 package.json 中的 sideEffects 選項,但預設是開啟的,所以也不用特別調整。
optimization.providedExports
預設為 true
開啟,此選項被開啟時有幾種用途:
- 自動識別導出:Webpack 嘗試分析每個模組,來確定其中有哪些內容被 export
- 針對
export * from ...
這樣的語法做優化,避免非必要的 export - 減少 bundle 大小:在明確分析模組內哪些內容有被 export 後,可以移除無用的內容
而 optimization.sideEffects
選項會依賴於這個選項需要被開啟。
optimization.usedExports
官方文件中有一段在描述其實 sideEffects
與 usedExport
雖然都是為了要減少 bundle size,但其實不是同一件事:
sideEffects
:用途是標記哪些模組、檔案路徑,雖然其中有內容沒有被 export,但這些內容需要能被保留下來,而沒有被標記的部分可以交由 bundler 放心移除。usedExport
:預設在 production mode 是true
。這個設定用來決定是否要在打包過程中利用 terser 去標記上前面提到的unused harmony export
,最後才靠 Minimizer (如老牌的 terser 或速度極快的 esbuild) 去實際將被標記的程式碼移除,達到真正的 tree-shaking 效果。
References
參考資料及延伸閱讀統一放在最後一篇中。