知识 分享 互助 bodog官网

    bodog官网专注于网页素材下载,提供博狗博彩、博狗、Bodog、博狗娱乐等,服务于【个人站长】【博狗师】和【web开发从业者】的代码素材与设计素材网站。

    bodog官网提供网页素材下载、博狗博彩
    知识 分享 互助!

    reactjs+webpack的ie8兼容问题解决方案

    作者:佳明妈 来源:aliued 2017-11-16 人气:
    reactjs+webpack的ie8兼容问题解决方案,webpack 进行babel对ES6,7语法的转码。 webpack 引用es3ify-loader 解决es3语法兼容问题。 全局引用babel-polyfill,es5-shim/es5-sham,console-polyfill,JSON的polyfill等 不要

        reactjs+webpack的ie8兼容问题解决方案,原文来自 aliued,不过这篇文章原文基本是不能访问了,你可以试试还能不能访问:www.aliued.com/?p=3240

        首先说一下兼容ie8的通用方案,网上搜到一些方法,比如添加 transform-es3-property-literals,transform-es3-member-expression-literal , add-module-exports 插件等,不过它们可能是不同时期的不同解决方案,实际上是在解决同一类问题,即es3环境对es5语法的兼容。

        一、es3ify解决es3环境兼容

        对于这个问题,主要是解决es3的保留字在es3环境下的正确使用,default是暴露最多的问题,因为大家都在写export default xx。对于这个问题,目前比较快捷的方式就是使用es3ify,在webpack中就是添加es3ify-loader,代码如下:

    module: {
                loaders: [{
                    test: /.jsx?$/,
                    loaders: ['es3ify-loader'],
                }
            ]
        }

        它主要做的事情就是对于一些保留字的使用做了es3兼容,以及一些额外的处理,比如去除数组尾部的多余逗号:

    // babel转换前
    var a = {
        class: "haha"
    }
    a.class = "bb";
    var arr = [1,2,3,];
    
    //babel转换后
    var a = {
        "class": "haha"
    }
    a["class"] = "bb";
    var arr = [1,2,3];

        有了它,其它的一些插件transform-es3-property-literals,transform-es3-member-expression-literal,add-module-exports 就没有必要了,你会发现这些插件就是在解决部分问题:

        transform-es3-property-literals:保证在对象属性中的保留字正确

    // babel转换前
    var a = {
        class: "haha"  //变动处
    }
    a.class = "bb";
    
    //babel转换后
    var a = {
        "class": "haha"
    }
    a.class = "bb";    //变动处

        transform-es3-member-expression-literal:保证在对象属性访问中的保留字正确

    // babel转换前
    var a = {
        class: "haha"   
    }
    a.class = "bb";   //变动处
    
    //babel转换后
    var a = {
        class: "haha"
    }
    a["class"] = "bb";//变动处

        所以也会把export.default转为export[“default”], 即解决了default不兼容问题。

        add-module-exports:仅仅解决default的问题

        二、babel-polyfill 解决缺失API问题

        先跨过Object.defineProperty问题,因为那里是重要的坑点。而对于上面的这三个问题,实际上属于同一类问题,即对一些ES6 API缺失的模拟。比如常见的Object.assign,Promise对象,fetch等等,这些可以通过统一引用“babel-polyfill”来解决,如果感觉“babel-polyfill”太重,也可以针对所需要的API自行引用对应的polyfill。polyfill的应用可以有两种方式:

    1.             npm包的方式,在编译入口文件通过require(“babel-polyfill”)引入执行。

    2.             也可以在页面上,业务js前引入babel的script标签。

            这里最后一个问题:

            以及console对象的兼容问题就比较简单,也都可以通过对应polyfill解决,就不多做解释。

        三、最麻烦的Object.defineProperty

        这里整个问题的说明已经滞后,且有错误:

        首先,这里说的 “Object.defineProperty 在IE8中不存在” 是错的,而是IE8中有自己实现的Object.defineProperty,它的行为和标准不同,且只能接受DOM对象,如果传入普通javascript对象会抛异常。详细说明在这里 Object.defineProperty 。

        其次,babel会把 export(非import) 编译成 Object.defineProperty的方式。相信添加这个问题的时候,babel确实存在这样的转换,具体的issues也有人提过 babel-export,而提供的解决方案—-引入es5-shim和es5-sham在这种情况下是也确实是可行的。不过目前的babel版本已经不会有这种转换(却还存另一个转换的坑),但是es5-shim和es5-sham的引用是必要的,因为它是解决通用性的es3环境下es5 API的缺失问题,就像babel-polyfill一样,Object.defineProperty是其中的一个API。

        以上是现有常规的兼容方案,很多人使用也没有存在太多问题。

        遇到的问题和排查

        本以为按照这样的指引,进行了babel转换,引入es3ify,babel-polyfill,es5-shim/es5-sham,console-polifill就大功告成了,可惜ie8运行起来还是崩了。先是错误定位到babel-polyfill中,去掉babel-polyfill又定位到es5-sham中,报的错误都是异常未捕获,且在IE8下调试很艰难。后来根据es5-sham压缩代码的抛异常位置,查看es5-sham的源码,结合es5-sham的文档说明,基本定位为Object.defineProperty的问题。

            首先其抛异常的代码在这段:

        代码会在supportsAccessors为false且hasGetter或者hasSetter时抛异常,逻辑上讲就是如果当前js引擎不支持访问器属性,但是却在属性描述符中设置了get,set,那么就会抛出异常。supportsAccessors用于判断当前js引擎是否支持访问器属性,它的判断逻辑在这里:

            实际就是用Object.prototype.hasOwnProperty(“ defineGetter “)做判断,“ defineGetter ”的兼容情况是只兼容IE11,具体查看 defineGetter 说明 ,虽然ie9,ie10同样不支持 defineGetter ,不过他们直接支持 Object.defineProperty 方法和 get语法 ,无需sham,所以代码并不会走到异常这里。实际上es5-sham官方文档也提到对Object.defineProperty的polyfill会存在限制和fail的情况:

            具体查看: es5-shim , 虽然其说明和代码实现存在些差异,不过结论是明确的:ie8下访问器属性不支持,会抛异常;

            基本明确了是用Object.defineProperty()设置访问器属性的问题,那么就向上查找到底是哪里使用了访问器属性设置,在编译后的源代码里搜索“ :get”查到了这段代码:

            根据上面关键字syncHistoryWithStore,routerReducer等初步判断是在react-router-redux中,node_modules查看react-router-redux源码,果然,其lib中index.js里有很多对export的访问器属性设置。再查看对应src/index.js文件,两份代码如下:

    //src/index.js
    export syncHistoryWithStore from './sync'
    export { LOCATION_CHANGE, routerReducer } from './reducer'
    
    export {
        CALL_HISTORY_METHOD,
        push, replace, go, goBack, goForward,
        routerActions
    } from './actions'
    export routerMiddleware from './middleware'

        babel编译后部分代码:

    //lib/index.js
    'use strict';
    
    Object.defineProperty(exports, "__esModule", {
      value: true
    });
    exports.routerMiddleware = exports.routerActions = exports.goForward = exports.goBack = exports.go = exports.replace = exports.push = exports.CALL_HISTORY_METHOD = exports.routerReducer = exports.LOCATION_CHANGE = exports.syncHistoryWithStore = undefined;
    
    var _reducer = require('./reducer');
    
    Object.defineProperty(exports, 'LOCATION_CHANGE', {
      enumerable: true,
      get: function get() {
        return _reducer.LOCATION_CHANGE;
      }
    });
    Object.defineProperty(exports, 'routerReducer', {
      enumerable: true,
      get: function get() {
        return _reducer.routerReducer;
      }
    });

        所以确定了是babel编译问题,又回到了上面提到的,babel对直接的export会转码为Object.defineProperty,但是它们修复了这个问题,不过好死不死的,对于export 和 import结合的写法—-export xx from ‘xxx’ 还是会转码为Object.defineProperty对exports进行属性设置,更加严重的是,之前的Object.defineProperty设置的是数据属性,直接指定的value,但是这次的Object.defineProperty 脑残般的设置了访问器属性,如此一来es5-sham已经没有办法解决(上面已经说明)。

        所以最终的排查结果就是主要3点:

    1.             ie8不支持设置访问器属性,即便是引了es5-shim;

    2.             Babel 会把export xxx from ‘xx’ 语法转码为访问器属性设置的exports对象。

    3.             而react-router-react的index.js 偏偏用了export xxx from ‘xx’这样的语法。

        解决方案

        最直接的解决办法就是Babel修复这种转码方式,目前已经有人提过issue,但是尚未解决: issue

        其次react-router-redux 不要用export xx from ‘xx’的方式,也有人提过issue: issue

        不过目前为了解决线上bug,肯定没有办法等待它们的修复,且尚未找到一种ie8下兼容访问器属性设置的方法,所以最终此项目的解决方案是修改react-router-react的源码,把其中的export xx from ‘xx’的语法改成分开的方式,比如:

    //修改前
    export syncHistoryWithStore from './sync'
    
    //修改后
    import syncHistoryWithStore from './sync';
    export {syncHistoryWithStore} ;

        然后所有引用react-router-react的地方改为对src/index.js的引用,在项目中自己重新编译,而不使用lib中编译好的版本。

        总结

        原本对webpack和babel了解的就不是很多,差不多用了一天的时间来排查这个问题,感觉react的项目想要支持ie8坑还会很多,其中包括babel,webpack,第三方库对ie8的兼容支持问题并不良好,且现在 [email protected] 版本已经放弃ie8。所以目前实践的ie8兼容方案是:

    1.             webpack 进行babel对ES6,7语法的转码。

    2.             webpack 引用es3ify-loader 解决es3语法兼容问题。

    3.             全局引用babel-polyfill,es5-shim/es5-sham,console-polyfill,JSON的polyfill等

    4.             不要在代码中用Object.defineProperty设置访问器属性,若第三方包中有,找到,改之。

        各位还遇到哪些问题可以一起讨论,积累经验,整个排查过程也对很多知识理解的深刻了一点。

    ↓ 查看全文

    reactjs+webpack的ie8兼容问题解决方案由bodog官网收集整理,您可以自由传播,请主动带上本文链接

    bodog官网就是免费分享,觉得有用就多来支持一下,没有能帮到您,懒人也只能表示遗憾,希望有一天能帮到您。

    m88 188bet uedbet 威廉希尔 明升 bwin 明升88 bodog bwin 明升m88.com 18luck 188bet unibet unibet Ladbrokes Ladbrokes casino m88明升 明升 明升 m88.com 188bet m88 明陞 uedbet赫塔菲官网 365bet官网 m88 help
    188bet www.188bet.com bwin 平博 unibet 明升 188bet uk Ladbrokes 德赢vwin 188bet m88.com w88 平博88 uedbet体育 188bet 188bet 威廉希尔 明升体育app 平博88 M88 Games vwin德赢 uedbet官网 bodog fun88 188bet

    reactjs+webpack的ie8兼容问题解决方案-最新评论