uglify 壓縮報錯問題及 es5-imcompatible-versions
來自專欄 前端消息
緣起
由於維護 roadhog 和 umi,收到構建方面的問題反饋比較多,其中一個常見的是打包時 uglify 壓縮的問題。類似下面的報錯都是這個引起的,
Failed to minify the bundle. Error: 0.0f3f4c41.async.js from UglifyJsxx.async.js from UglifyJs Unexpected token: keyword (const)0.570d21b1.async.js from UglifyJsUnexpected token: punc ()) [0.570d21b1.async.js:13245,19]xx.async.js from UglifyJs Unexpected token: operator (>)
為啥會有這個問題?
通常 webpack 在構建時,是不會讓 node_modules 下的文件走 babel tranpile 的,一是會慢很多,二是 babel@6 時編譯編譯過的代碼會不安全(據說 babel@7 下沒問題了),所以業界有個潛在的約定,npm 包發布前需要先用 babel 轉出一份 es5 的代碼。
但是有些 npm 包不遵守這個約定,沒有轉成 es5 就發上去,比如 query-string@6。然後壓縮工具 uglify 又只支持 es5 的語法,遇到 const
、let
、()=>
類似的語法,就拋錯了。
解決
有多個解決方法,但各有利弊。
使用 uglify-es 進行壓縮
uglify-es 支持 es6 語法,所以不會報錯。但問題是如果你需要在 IE11 及以下,或者其他的低版本瀏覽器里跑時,就會報錯、白屏了。
讓 babel 編譯 node_modules 下的文件
由於 babel@7 可以保證編譯編譯過的代碼不會出問題,這不失為一個好的解決方案,比如 create-react-app 會在下個版本考慮用這個方案,參考 facebook/create-react-app#3776。問題是會讓本來就比較慢的 dev、build 流程雪上加霜。
babel-engine-plugin
跟進 npm 包的 engine 配置做按需編譯。缺點是使用者比較少,如果 npm 包開發者不遵循這個規則一樣會出問題。
umi/roadhog 提供的 extraBabelIncludes 配置
umi/roadhog 默認也是僅用 babel 編譯項目文件,但提供了額外的 extraBabelInclude 配置可以指定 node_modules 下的文件。比如:
{ "extraBabelIncludes:" [ "node_modules/a", "node_modules/b" ]}
問題是無法提前預知,都是出錯了一臉那啥,翻 issue 或者提問後才知道。而且找到哪個依賴用了 es6 語法也比較麻煩。
所以,有沒有一種能提前預知(用戶無感知),並且不降低 webpack 構建速度的方案?
es5-imcompatible-versions
經過討論,我們建了一個 es5-imcompatible-versions,用於收集 uglify 壓縮有問題的 npm 包版本。然後再提供配套工具,自動 resolve 到項目里有問題的 npm 包路徑,添加到 babel-loader 的 include 參數里。
然後,
- 遇到已被收錄的 es6 包,會自動走 babel 編譯
- 遇到未被收錄的,在 es5-imcompatible-versions 提 PR,被合併發布後,重裝 npm 依賴再構建,自動生效
最後,這事情是否能做成,需要大家一起來補充有問題的 npm 包。
參考
- https://github.com/umijs/es5-imcompatible-versions
- https://github.com/sindresorhus/ama/issues/446
- https://github.com/facebookincubator/create-react-app/issues/3776
推薦閱讀:
※了不起的 Gatsby.js
※最全最好用的動效落地方法、都幫你總結好了(下)
※web前端:如何(安全地)使用Vue.js的jQuery插件
※web前端大咖告訴你們前端怎麼學習?該怎樣學習!
※搭建Angular開發環境
TAG:前端開發 |