<meter id="7ntxv"></meter>

<b id="7ntxv"><listing id="7ntxv"><ol id="7ntxv"></ol></listing></b>
<nobr id="7ntxv"></nobr><mark id="7ntxv"></mark>

    <p id="7ntxv"><menuitem id="7ntxv"><font id="7ntxv"></font></menuitem></p>
    <sub id="7ntxv"><menuitem id="7ntxv"><meter id="7ntxv"></meter></menuitem></sub>

    <mark id="7ntxv"></mark>
    <meter id="7ntxv"><var id="7ntxv"></var></meter>

    知識 分享 互助 懶人建站

      懶人建站專注于網頁素材下載,提供網站模板、網頁設計、ps素材、圖片素材等,服務于【個人站長】【網頁設計師】和【web開發從業者】的代碼素材與設計素材網站。

      懶人建站提供網頁素材下載、網站模板
      知識 分享 互助!

      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[&ldquo;default&rdquo;], 即解決了default不兼容問題。

          add-module-exports:僅僅解決default的問題

          二、babel-polyfill 解決缺失API問題

          先跨過Object.defineProperty問題,因為那里是重要的坑點。而對于上面的這三個問題,實際上屬于同一類問題,即對一些ES6 API缺失的模擬。比如常見的Object.assign,Promise對象,fetch等等,這些可以通過統一引用&ldquo;babel-polyfill&rdquo;來解決,如果感覺&ldquo;babel-polyfill&rdquo;太重,也可以針對所需要的API自行引用對應的polyfill。polyfill的應用可以有兩種方式:

      1.             npm包的方式,在編譯入口文件通過require(&ldquo;babel-polyfill&rdquo;)引入執行。

      2.             也可以在頁面上,業務js前引入babel的script標簽。

              這里最后一個問題:

              以及console對象的兼容問題就比較簡單,也都可以通過對應polyfill解決,就不多做解釋。

          三、最麻煩的Object.defineProperty

          這里整個問題的說明已經滯后,且有錯誤:

          首先,這里說的 &ldquo;Object.defineProperty 在IE8中不存在&rdquo; 是錯的,而是IE8中有自己實現的Object.defineProperty,它的行為和標準不同,且只能接受DOM對象,如果傳入普通javascript對象會拋異常。詳細說明在這里 Object.defineProperty 。

          其次,babel會把 export(非import) 編譯成 Object.defineProperty的方式。相信添加這個問題的時候,babel確實存在這樣的轉換,具體的issues也有人提過 babel-export,而提供的解決方案&mdash;-引入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(&ldquo; defineGetter &ldquo;)做判斷,&ldquo; defineGetter &rdquo;的兼容情況是只兼容IE11,具體查看 defineGetter 說明 ,雖然ie9,ie10同樣不支持 defineGetter ,不過他們直接支持 Object.defineProperty 方法和 get語法 ,無需sham,所以代碼并不會走到異常這里。實際上es5-sham官方文檔也提到對Object.defineProperty的polyfill會存在限制和fail的情況:

              具體查看: es5-shim , 雖然其說明和代碼實現存在些差異,不過結論是明確的:ie8下訪問器屬性不支持,會拋異常;

              基本明確了是用Object.defineProperty()設置訪問器屬性的問題,那么就向上查找到底是哪里使用了訪問器屬性設置,在編譯后的源代碼里搜索&ldquo; :get&rdquo;查到了這段代碼:

              根據上面關鍵字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結合的寫法&mdash;-export xx from &lsquo;xxx&rsquo; 還是會轉碼為Object.defineProperty對exports進行屬性設置,更加嚴重的是,之前的Object.defineProperty設置的是數據屬性,直接指定的value,但是這次的Object.defineProperty 腦殘般的設置了訪問器屬性,如此一來es5-sham已經沒有辦法解決(上面已經說明)。

          所以最終的排查結果就是主要3點:

      1.             ie8不支持設置訪問器屬性,即便是引了es5-shim;

      2.             Babel 會把export xxx from &lsquo;xx&rsquo; 語法轉碼為訪問器屬性設置的exports對象。

      3.             而react-router-react的index.js 偏偏用了export xxx from &lsquo;xx&rsquo;這樣的語法。

          解決方案

          最直接的解決辦法就是Babel修復這種轉碼方式,目前已經有人提過issue,但是尚未解決: issue

          其次react-router-redux 不要用export xx from &lsquo;xx&rsquo;的方式,也有人提過issue: issue

          不過目前為了解決線上bug,肯定沒有辦法等待它們的修復,且尚未找到一種ie8下兼容訪問器屬性設置的方法,所以最終此項目的解決方案是修改react-router-react的源碼,把其中的export xx from &lsquo;xx&rsquo;的語法改成分開的方式,比如:

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

          然后所有引用react-router-react的地方改為對src/index.js的引用,在項目中自己重新編譯,而不使用lib中編譯好的版本。

          總結

          原本對webpack和babel了解的就不是很多,差不多用了一天的時間來排查這個問題,感覺react的項目想要支持ie8坑還會很多,其中包括babel,webpack,第三方庫對ie8的兼容支持問題并不良好,且現在 react@15.x.x 版本已經放棄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兼容問題解決方案由懶人建站收集整理,您可以自由傳播,請主動帶上本文鏈接

      懶人建站就是免費分享,覺得有用就多來支持一下,沒有能幫到您,懶人也只能表示遺憾,希望有一天能幫到您。

      reactjs+webpack的ie8兼容問題解決方案-最新評論

      亚洲免费的黄色网站_黄色网站在线放久操射视频_A片www.黄色网站成年人_天天干 天天操天天干

      <meter id="7ntxv"></meter>

      <b id="7ntxv"><listing id="7ntxv"><ol id="7ntxv"></ol></listing></b>
      <nobr id="7ntxv"></nobr><mark id="7ntxv"></mark>

        <p id="7ntxv"><menuitem id="7ntxv"><font id="7ntxv"></font></menuitem></p>
        <sub id="7ntxv"><menuitem id="7ntxv"><meter id="7ntxv"></meter></menuitem></sub>

        <mark id="7ntxv"></mark>
        <meter id="7ntxv"><var id="7ntxv"></var></meter>