在專欄課程裏,有位同窗提到過一個頗有意思的問題:「我沒裝 babel,js 入口裏寫了個箭頭函數,運行 webpack 構建命令後,也成功編譯了。這是爲何?」。今天就帶領你們一塊兒去探討下這個話題。前端
在使用 webpack 的時候,很常見的一個構建優化手段就是縮小構建目標。好比在構建階段只構建 src 裏面的模塊代碼,對於 node_modules 裏面所引入的三方包不進行構建操做。node
若是使用的是 webpack 3.x 版本,編寫的構建腳本相似這樣的,咱們經過設置loader 裏面的 exclude 字段避免因爲解析 node_modules 裏面的模塊形成的構建耗時:webpack
const path = require('path');
const webpack = require('webpack');
module.exports = {
entry: './src/index.js',
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle.js'
},
module: {
rules: [
{
test: /\.js$/,
loader: 'happypack/loader',
exclude: path.join(__dirname, 'node_modules')
}
]
}
plugins: [
new webpack.optimize.UglifyJsPlugin()
]
};
複製代碼
咱們常常會遇到一個問題,假設引入的 npm 包質量不夠高,好比 node_modules 裏面有 ES6 的語法,那麼 webpack 在 uglify 階段會報錯!下面給出兩種常見的出錯場景:ios
假設 node_modules 裏面存在 ES6 的模板字符串語法,那麼在生產環境打包的代碼壓縮階段,UglifyJs 會拋出錯誤。git
一樣的,你使用 ES6 的箭頭函數也是沒法正常的壓縮代碼的。github
細心的你必定會發現若是使用的是 webpack 4,這個場景描述的問題將再也不出現。webpack 4默認支持 ES6 代碼的壓縮,這個是什麼緣由呢?web
若是你有對 webpack 4 的依賴包進行過相關分析,好比直接查閱 package.json 文件或者經過 npm.broofa.com/ 網站上進行 webpack 依賴圖分析。不難發現 webpack 4 裏面使用了 terser-webpack-plugin 插件替代了以前一直使用的 uglifyjs-webpack-plugin 做爲它的內置插件。npm
以 4.39.3 這個版本爲例,能夠看到它的 package.json 文件的依賴包括了terser-webpack-plugin。json
咱們進一步分析發現 webpack 的 4.26.0 這個版本有一次提交,它的提交內容是對 webpack 內置插件進行了一次切換。bash
通過這麼一次分析,咱們能夠知道 webpack 4 之因此具有默認壓縮 ES6 代碼的能力,離不開 terser-webpack-plugin所起的做用!
在探究 terser-webpack-plugin 插件的原理前,咱們先系統的回顧一下代碼壓縮插件的歷史:
備註:壓縮插件歷史的來源 github.com/webpack/web…
到這裏,咱們能夠得出一個基本的結論:terser-webpack-plugin 基於 terser 所以它具有 ES6 的壓縮能力,uglifyjs-webpack-plugin v2.x 版本基於 uglify-js,沒法支持 ES6 的壓縮。
插件 | 依賴 | 是否支持 ES6(Y/N) |
---|---|---|
terser-webpack-plugin | terser | Y |
uglifyjs-webpack-plugin v1.x | uglify-es | Y |
uglifyjs-webpack-plugin v2.x | uglify-js | N |
代碼壓縮原理其實挺簡單的,也是 AST 的一個經典的應用案例。它的壓縮過程一般是:
JS 源代碼 -> AST -> 美化、壓縮 -> 新的 AST -> 壓縮後的代碼
複製代碼
瞭解了代碼壓縮的基本流程後,接下來咱們看看源碼包含了哪些內容,因爲 terser 是從 uglify-es Fork 出來進行修改的,所以它的代碼結構和 uglify-js 基本一致,只不過 terser 使用了 ES6 模塊的靜態分析功能。咱們以 terser 的源碼爲例分析下:
而後,咱們來一探 terser 和 uglify-js 的差別。對比了以後,發現一個很大的差別是 AST 的支持上面不一樣。
分析AST的差別發現,下面是兩個文件 diff 對比只在 terser 中才有,而這些恰好對應 ES6 的語法。
AST_Arrow,
AST_Await,
AST_BigInt,
AST_Class,
AST_ClassExpression,
AST_ConciseMethod,
AST_Const,
AST_DefaultAssign,
AST_Destructuring,
AST_Expansion,
AST_Export,
AST_ForOf,
AST_Import,
AST_Let,
AST_NameMapping,
AST_NewTarget,
AST_PrefixedTemplateString,
AST_Super,
AST_SymbolMethod,
AST_TemplateSegment,
AST_TemplateString,
AST_Yield
複製代碼
至此,咱們發現 webpack4 默認支持 ES6 壓縮的關鍵是:terser 裏面實現了 ES6 語法的 AST解析。
想學習更多 webpack 和前端工程相關知識能夠掃碼關注咱們團隊同窗公衆號:前期推送頻率每週一篇。