Webpack,Webpack 是一個前端資源加載/打包工具,如今版本已經 release 到 v2.6.1,今天的文章不支持介紹Webpack的API及使用,而是對最近項目開發中使用Webpack打包時處理IE低版本(IE8及如下)瀏覽器兼容問題作一次總結。issue直達,若是文章對您有幫助歡迎 star !!!html
PC端項目前端基礎技術選型jQuery + ES6 + EJS + Babel + Webpack:前端
項目開發過程都在 Chrome 瀏覽器中,一切都OK,沒有任何問題,當在IE9如下瀏覽器中調試發現好多坑,現總結以下,之後新手參考。webpack
default
、 class
、catch
ES3中保留字問題報錯信息:git
SCRIPT1048: 缺乏標識符
對應代碼:es6
e.n = function (t) { var n = t && t.__esModule ? function () { return t.default } : function () { return t }; return e.d(n, "a", n), n }
網上查找資料,webpack有一款loader插件es3ify-loader來處理ES3的兼容問題,修改webpack配置,問題解決,添加規則以下:github
module: { rules: [{ test: /.js$/, enforce: 'post', // post-loader處理 loader: 'es3ify-loader' } ] }
這個loader是幹啥用的捏,就是把這些保留字給你加上引號,使用字符串的形式引用,請看實例:web
// 編譯前 function(t) { return t.default; } // 編譯後 function(t) { return t["default"]; }
從新構建,在IE低版本瀏覽器預覽,使用 webpack.optimize.UglifyJsPlugin
壓縮時,又報上面一樣的錯誤了,從新採用 beauty:true, build 發現引號被壓縮掉了,究其緣由,研究了下uglify-js默認配置,發現了 compress.properties
屬性,增長build options以下,問題解決:ajax
new webpack.optimize.UglifyJsPlugin({ compress: { properties: false, warnings: false }, output: { beautify: true }, sourceMap: false })
從新構建,在IE低版本瀏覽器預覽,使用 webpack.optimize.UglifyJsPlugin
壓縮時,又報上面一樣的錯誤了,報錯代碼:npm
{ catch: function (t) { return this.then(null, t) } }
繼續查找uglify-js配置,發現 output.quote_keys
,修改build options,問題解決:json
new webpack.optimize.UglifyJsPlugin({ compress: { properties: false, warnings: false }, output: { beautify: true, quote_keys: true }, sourceMap: false }),
編譯後:
{ "catch": function(t) { return this.then(null, t); } }
從新構建,在IE低版本瀏覽器預覽,報錯信息以下:
SCRIPT3126: 沒法設置未定義或 null 引用的屬性
繼續分析壓縮後代碼,發現仍是uglify-js問題,其mangle 配置屬性 mangle.screw_ie8
默認爲 true, 什麼意思捏,意思就是把支持IE8的代碼clear掉,screw you => 去你的,修改壓縮配置項,從新編譯,問題解決:
new webpack.optimize.UglifyJsPlugin({ compress: { properties: false, warnings: false }, output: { beautify: true, quote_keys: true }, mangle: { screw_ie8: false }, sourceMap: false })
在 webpack 的 entry 入口文件top引入 es5-shim
問題解決
require('es5-shim'); require('es5-shim/es5-sham');
在 webpack 的 entry 入口文件top引入 console-polyfill
問題解決
require('console-polyfill');
在 webpack 的 entry 入口文件top引入 es6-promise
問題解決
require('es6-promise');
這個case 應該說是最難搞的一個case了,耗時也比較長,關鍵點在於使用 es5-shim
/es5-sham
也有問題,查看你官網發如今低版本瀏覽器也會有問題,官網描述以下:
⚠️ Object.defineProperty
In the worst of circumstances, IE 8 provides a version of this method that only works on DOM objects. This sham will not be installed. The given version of defineProperty will throw an exception if used on non-DOM objects.
In slightly better circumstances, this method will silently fail to set "writable", "enumerable", and "configurable" properties.
Providing a getter or setter with "get" or "set" on a descriptor will silently fail on engines that lack "defineGetter" and "defineSetter", which include all versions of IE.
https://github.com/es-shims/e...
那這個Object.defineProperty 是如何產生的呢,這個是babel編譯後產生的,當咱們在代碼使用 import
export
ES6 Module時出現的,那你可能最直接的想法就是我不用ES6 Module了,改用Commonjs規範,OK,修改後編譯,確實解決了問題,可是查看代碼裏仍是有一段代碼的,以下:
e.d = function(t, n, r) { e.o(t, n) || Object.defineProperty(t, n, { "configurable": !1, "enumerable": !0, "get": r }); }, e.n = function(t) { var n = t && t.__esModule ? function() { return t["default"]; } : function() { return t; }; return e.d(n, "a", n), n; }, e.o = function(t, e) { return Object.prototype.hasOwnProperty.call(t, e); }
看代碼已經作了容錯判斷。
從新構建,加入 json3
處理 JSON 對象兼容時,代碼在此處拋出了異常:
var hasGetter = 'get' in descriptor; var hasSetter = 'set' in descriptor; if (!supportsAccessors && (hasGetter || hasSetter)) { throw new TypeError(ERR_ACCESSORS_NOT_SUPPORTED); }
分析supportsAccessors代碼邏輯:
var supportsAccessors = owns(prototypeOfObject, '__defineGetter__');
經過斷點調試,supportsAccessors值爲false且hasGetter或者hasSetter時拋出了異常,也就是說當前js引擎不支持訪問器屬性,卻在屬性描述符中設置了get,set,那麼就會拋出異常。查看 defineGetter 的兼容狀況,只兼容IE11,雖然IE九、IE10一樣不支持defineGetter,不過他們直接支持Object.defineProperty方法和get語法,無需sham,因此代碼並不會走到異常這裏。可是IE8如下就扯淡了。解決這種狀況只能修改源代碼了。
至此,Webpack打包時,IE低版本瀏覽器(IE8及如下)遇到的兼容問題就總結這裏,若是你有新的問題,歡迎留言。
感謝您的閱讀
--eof--
做者[煦涵]
2017年05月28日
下面是「FED實驗室」的微信公衆號二維碼,歡迎長按、掃描關注: