標籤:

uglify 壓縮報錯問題及 es5-imcompatible-versions

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 的語法,遇到 constlet()=> 類似的語法,就拋錯了。

解決

有多個解決方法,但各有利弊。

使用 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 包。

參考

  • github.com/umijs/es5-im
  • github.com/sindresorhus
  • github.com/facebookincu

推薦閱讀:

了不起的 Gatsby.js
最全最好用的動效落地方法、都幫你總結好了(下)
web前端:如何(安全地)使用Vue.js的jQuery插件
web前端大咖告訴你們前端怎麼學習?該怎樣學習!
搭建Angular開發環境

TAG:前端開發 |