為什麼 Babel 設定會影響 tree-shaking?
Table of Contents
為什麼 Babel 設定會影響 tree-shaking?
這裡我們一樣看個實際例子,完整的初始 template 可以參考這個 repo,這次我們宣告出了 3 個 function,以及實際上使用的只有 add
:
再看到其中的 webpack.config.js
中,這裡可以注意到其中在 babel-loader
中有個 @babel/preset-env
的設定:
大多數專案中會套用 @babel/preset-env 這個 Babel 的 preset (預設配置),或是更古老的專案中可能會看到類似 babel-preset-2015
之類的 preset,以下也先岔個題簡單整理一下這些設定的意思。
關於 @babel/preset-env
你可能知道為了要能讓 ES6+ 的各種 Modern JavaScript 語法能在不同瀏覽器與版本都能兼容,我們需要用 Babel 來做轉譯與套用對應的 polyfill,而早期需要自己一個一個手動設定,像是這樣的範例:
這樣設定的問題是如果當未來某個瀏覽器停止支援、某個版本後開始支援某個語法、產品決定停止支援某版本以前使用者等,都可能要回頭手動調整 Babel 設定不夠智慧,且若沒有回頭調整也會因為打包了許多其實不需要的 polyfill 而造成 bundle 肥大,因此 @babel/preset-env
就派上用場了。
所謂的 preset 是指預設配置,這個 @babel/preset-env
可以根據你在專案中設定的 .browserlistrc
來智慧地去 mapping 在轉譯時要引入哪些 core-js polyfill,讓你打包的結果可以支援你想支援的各種瀏覽器以及其對應的版本。
@babel/preset-env 中的 modules
設定
回到正題,那為什麼 Babel 設定會與 tree-shaking 有關呢?這跟其中的 modules
這個設定有關,這個設定的意思是「當 babel-loader 在看到 ESM 時要轉譯成什麼模組」:
false
:不要轉譯,保留原本 ESM’auto’
:預設選項,意思是依照 babel-loader 中的supportsStaticESM
選項去決定行為:true
: 等同於modules: false
的效果false
: 等同於modules: "commonjs"
的效果
- 其他選項:將 ESM 轉譯成對應的 CJS、AMD、UMD 等模組
而其中的這個 'auto'
在 Webpack >= 2 中,supportsStaticESM
預設為 true
。也就是說預設如果將 modules
設為 ’auto’
與 false
的效果相同,都是告訴 Babel 在看到 ESM 時不要做轉譯。
範例
上面講的可能有點複雜,一樣直接來看個範例實際體驗一下,當我們把 modules 選項設定為 ’auto’
後,去做 production build,也就是在範例專案中執行 npm run build:prod
:
可以看到 tree-shaking 有生效,沒被使用到的 function 都被 shake 掉了,只有 add
被保留下來 。
當我們把 modules 選項設定為 ’cjs’
後,也就是跟 Babel 說「當你看到 ESM 時,請幫我轉譯成 CommonJS 模組」,此時若去做 production build:
上面可以看到可怕的事情發生了,那就是 tree-shaking 並沒有生效,雖然只有用到 add
,但 flattenDeep
與 multiply
也都被留下來了。這是因為 tree-shaking 的必備條件是只能靜態分析 ESM 模組,因此千萬要注意 babel-loader
中的 @babel/preset-env
設定是否正確。
References
參考資料及延伸閱讀統一放在最後一篇中。