IE8环境下Webpack+React全家桶配置总结

https://github.com/sitorhy/react-webpack-boilerplate

一、IE8基础兼容问题


1.1、CSS兼容

旧引擎不支持太多CSS3特性,在无法使用Flex布局的情况下尽量使用原始的表格排版代替,使用表格基本上不用考虑兼容性问题。

IE8不支持渐变和透明通道,做全局半透明遮罩的时候尤其蛋疼,DXImageTransform滤镜虽然能对容器进行着色但不能防止事件穿透,即便是一个全屏着色的遮罩层其背后的各种控件依然是可以点击的,建议放弃线性渐变,使用小尺寸PNG图片作为容器背景元素,设置background-repeat进行平铺。

1.2、JavaScript兼容

IE8非调试环境下不支持console,执行到console.log之类的代码会直接报错,只有调出控制台时才会生成window.console对象,因此首要引入console-polyfill,具体作用可参见其源代码。

1.2.1、保留字问题

ECMAScript定义了一套关键字和保留字,根据规定,关键字是保留的,不能用作变量名或函数名。在实现ECMAScript 3JavaScript引擎中使用关键字作标识符,会导致"Identifier Expected"(缺少标识符)错误。而使用保留字作标识符可能会也可能不会导致相同的错误,具体取决于特定的引擎。

break do instanceof typeof case else
new var catch finally return void
continue for switch while debugger function
this with default if throw delete
in try abstract enum int short
boolean export interface static byte extends
long super char final native synchronized
class float package throws implements protected
volatile double import public package let
yield

ECMAScript 5对使用关键字和保留字的规则进行了少许修改。关键字和保留字虽然仍然不能作为标识符使用,但可以用作对象的属性名,IE8自然是不支持新特性的,会将属性名当作保留字处理,定位“缺少标识符”错误时基本上都会指向某个保留字,使用插件es3ify-webpack-plugin可转换对象访问方式,将点运算符访问改为使用中括号运算符访问。

// In
var x = {class: 2,};
x.class = [3, 4,];
 
// Out:
var x = {"class": 2};
x["class"] = [3, 4];

混淆插件uglifyjs-webpack-plugin开启ie8支持能达到同样效果,因此可以只保留uglifyjs-webpack-plugin插件。

const UglifyJsPlugin = require('uglifyjs-webpack-plugin');

new UglifyJsPlugin({
      uglifyOptions: {
         ie8: true
   } 
})

1.2.2、ECMAScript 5

IE8不支持ECMAScript5,不能使用Array.mapFunction.bind等方法,引入es5-shim可扩展出大部分ES5 API

唯一重要且不能模拟的是Object.defineProperty,直接通过变量赋值的方式触发事件分发,已经超出旧引擎的能力范围了,像Vue.js这些使用到该特性的第三方库均不可能兼容IE8


 
  
  

Thu Feb 13 2025 21:23:58 GMT+0000 (Coordinated Universal Time)

1.2.3、ECMAScript 6

Webpack 2.x / 3.x


基本上引入babel-polyfill足够了,主要是兼容Promise,引入现版本babel-polyfill已经不需要前置引入es5-shim

  • [必要] devtool设为source-map,不想生成js.map文件可以设成false
  • [非必要] 引入es5-shim,不适用复杂场景,babel-polyfill可以代劳。
  • [非必要] 引入es5-sham,不适用复杂场景。
  • [非必要] 引入es3ify-webpack-plugin,不使用React情况下,想观察转码结果可以单独引入。
  • [必要] 引入uglifyjs-webpack-plugin,并开启ie8支持。
  • [必要] 引入console-polyfill
  • [必要] 引入babel-polyfill

Webpack 4.x


改动大致如下:

  • [必要] @babel/polyfill,全盘引入,省时省力,不要多想。
  • [必要] anujs@1.5.2,额,用1.5.3以上版本可能会翻车,针对ie8这种老古董,没事还是不要折腾核心库。
  • [必要] 不要引入es5-shim,堆栈溢出。
  • [必要] 不要引入es5-sham,堆栈溢出。
  • [必要] 引入插件@babel/plugin-transform-modules-commonjs,能绕过'Accessors not supported!'异常。
{
  "presets": [
    [
      "@babel/env",
      {
        "loose": true
      }
    ],
    "@babel/preset-react"
  ],
  "plugins": [
    "@babel/plugin-transform-modules-commonjs",
    "@babel/plugin-proposal-class-properties"
  ]
}
  • [必要] 不能使用splitChunk分包功能。
  • [必要] 引入uglifyjs-webpack-plugin,见下文。
  • [非必要] 引入@babel/plugin-proposal-class-properties,支持如下写法,不用到处bind回调方法。
class Test extends React.Component
{
      selfMethod = () => {
            /// do something
      };

      render()
      {
            return (  );
      }
}

二、Webpack配置


2.1、核心插件

Webpack 2.x / 3.x


某些插件在Webpack2.x3.x下具有不同适用性,安装的时候注意版本号。

插件 / 版本 webpack 2.7.0 webpack 3.12.0
react 0.14.9 0.14.9
react-dom 0.14.9 0.14.9
react-router 1.0.3 1.0.3
redux 3.5.2 3.5.2
webpack-dev-server 2.11.2 2.11.2
webpack-dev-middleware 2.0.6 2.0.6
webpack-hot-middleware >=2.22.2 >=2.22.2
url-loader 0.6.2 >=1.0.1
extract-text-webpack-plugin 2.1.2 3.0.2
history 1.7.0 1.7.0
es3ify-webpack-plugin >=0.0.1 >=0.1.0

测不出版本上限的插件全部用>=标注,可以尝试用最新版。
react能兼容ie8的最后版本是0.14.9
redux版本需要<3.6.0,我不清楚3.5.x3.6.0版本之间发生了什么。
react-router需要<2.0
react-redux@4.4.10是最后支持React 0.14的版本。
webpack-dev-middleware<3.0.0
history用于手动路由路转,配合react-router
anujs@1.5.2比较稳定。

Webpack 4.x


React全家桶保留Webpack 2.x / 3.x的兼容版本,其他插件基本上使用最新的即可。
因为针对IE8,需要使用uglifyjs-webpack-plugin代替默认的terser-webpack-plugin进行代码压缩。

optimization: {
        minimize: true,
        minimizer:  [
            new UglifyJsPlugin({
                uglifyOptions: {
                    warnings: false,
                    parse: {},
                    compress: false,
                    mangle: true,
                    output: null,
                    toplevel: false,
                    nameCache: null,
                    ie8: true,
                    keep_fnames: false
                }
            })
        ]
    }

因为IE8不支持WebSocket,IE8预览网页需要devServer使用生产环境配置实时watch编译,但代码被压缩不容易排错,因此还需要启动另外一个devServerChrome下进行开发。

2.2、入口文件顺序

entry项定义入口文件,其中包含必需的兼容库,视情况甚至还需要引入jQuery
main为自定义入口文件,在main.js完成ReactDOM.render等启动操作,视个人习惯而言。

entry: {
        "console-polyfill": "console-polyfill",
        "es5-shim": "es5-shim/es5-shim.js",
        "es5-sham": "es5-shim/es5-sham.js",
        "babel-polyfill": "babel-polyfill",
        main: [path.resolve("src", "index.js")]
    }

由于html-webpack-plugin默认注入顺序是不可预测的,可能会出现入口文件引入顺序不是兼容库填充顺序的情况出现。






解决办法之一是不使用entry配置,手动整理出需要加载的静态资源,然后用

三、CSS模块化


Webpackloader预处理类似于管道,上一个loader的输出作为下一个loader的输入,用数组表示就是索引大的loader的输出作为索引小loader的输入。

{
    test: /\.less$/,
    use: [{
        loader: "style-loader" // creates style nodes from JS strings
    },
    {
        loader: "css-loader" // translates CSS into CommonJS
    },
    {
        loader: "less-loader" // compiles Less to CSS
    }]
}

3.1、预处理和分离

对于less文件的编译,less-loaderless文件编译输出为css代码,css代码中的url会在css-loader中被转换,样式代码随入口文件一并打包,style-loader在运行时生成