Webpack4+Babel7+ES6兼容IE8的實現

前陣子重構了一個挺有意思的項目,是一個基于瀏覽器環境的數據采集sdk 。公司各個產品的前端頁面中都嵌入了這個sdk,用于采集用戶的行為數據,上傳到公司的大數據平臺,為后續的運營決策分析提供數據支撐 。
筆者接手這個項目的時候,前任開發者已經把功能都寫差不多了 。唯一需要做的就是做下模塊化拆分和代碼規范,以便后續的開發維護 。模塊化拆分用webpack,代碼規范用eslint 。既然要重構,那就順手用es6重寫吧 。callback也不要了 , 全換成promise,async、await也用起來 , 反正怎么爽怎么寫 。
問PM瀏覽器最低兼容到哪個版本,PM說兼容公司各個產品所兼容的最低版本就行 。和公司各個產品的前端負責人溝通后發現 , 居然有兼容IE8的 , 真是我了個fk 。
google了一下Webpack Babel ES6兼容IE8,果然坑很多 。試了好幾篇博客給出的方案,都跑不通 。也沒怎么研究具體哪里有問題,因為那些解決方案里面的webpack和babel都是舊版的,跑通了也不高興用 。筆者分析了那些博客中提出的幾個關鍵性問題,然后參考webpack和babel最新的官方文檔,總結出一套最新的Webpack4 Babel7 ES6兼容IE8的方案 。
ES6兼容IE8需要解決四個問題
語法支持
【Webpack4 Babel7 ES6兼容IE8的實現】IE瀏覽器不支持ES6的語法,只在IE10、IE11中支持了部分ES6的API , 所以在IE瀏覽器中使用ES6需要把ES6的代碼編譯成ES5才能執行 。方法也很簡單,就是用babel-loader 。這部分沒什么坑,所以我也就不細說了 。給個網站,大家可以自行查看ES5、ES6在各瀏覽器版本中的支持情況
ES3保留關鍵字
如果在IE8下通過object.propertyName的方式使用ES3中的保留關鍵字(比如default、class、catch) , 就會報錯

Webpack4+Babel7+ES6兼容IE8的實現

webpack有一款loader插件es3ify-loader專門用來處理ES3的關鍵字兼容問題 。這個插件的作用就是把這些保留字給你加上引號,使用字符串的形式引用 。
Webpack4+Babel7+ES6兼容IE8的實現

然而,筆者親身實踐后發現 , UglifyJS本來就已經提供了對IE瀏覽器的支持,不需要額外引入es3ify-loader 。webpack默認的UglifyJS配置不支持ie8 , 需要手動配下 。
Webpack4+Babel7+ES6兼容IE8的實現

執行環境
解決了前面兩個問題只能保證語法上不報錯,但使用ES6中的API(比如Promise)還是會報錯 。另外,IE8對ES5的API支持也很差,只支持了少量的API,有些API還只是支持部分功能(比如Object.defineProperty) 。所以,要在IE8中完美運行ES6的代碼,不僅需要填充ES6的API,還要填充ES5的API 。

babel為此提供了兩種解決方案,具體使用方法官方文檔已經寫的很詳細了,筆者就不贅述了 。這里糾正墨白同學文中的一個錯誤 , 就是@babel/polyfill現在已經支持按需加載,準確的說也不能算是錯誤,因為墨白同學在寫這篇文章的時候還不支持按需加載 。具體方法我就不細說了,文檔里都有,配置下browserlist和@babel/preset-env的useBuiltsIns屬性就可以了 。

我只說下我在實際開發過程中碰到的坑 。

雖然@babel/polyfill、@babel/runtime都支持按需加載,但都只能識別出業務代碼中使用到的缺失的API,如果第三方庫有用到這些缺失的API,babel不能識別出來,自然也就不能填充進來 。比如regenerator-runtime中用到的Object.create和Array.prototype.forEach 。解決辦法是,在入口文件處手動引入缺失的API 。
模塊化加載
筆者原來是想用ES6的模塊化加載方案 , 因為這樣可以利用webpack的tree shaking,移除冗余代碼,使打包出來的文件體積更小 。但在IE8下測試發現Object.defineProperty會報錯'Accessors not supported!' 。報錯代碼如下
Webpack4+Babel7+ES6兼容IE8的實現

我用@babel/plugin-transform-modules-commonjs轉成commonjs加載就可以把這個坑繞過去 , 但同時也意味著放棄了tree shaking 。
總結
package.json
Webpack4+Babel7+ES6兼容IE8的實現

webpack配置
Webpack4+Babel7+ES6兼容IE8的實現

入口文件按需引入缺失的API
Webpack4+Babel7+ES6兼容IE8的實現

相關經驗推薦