当自己配置webpack的时候,很多兼容问题会暴露出来,比如浏览器的兼容问题,并且当你使用chrome或者一些比较新版本的其他浏览器的时候,还不会发现什么问题,因为它们基本都支持es6,甚至es7,但是当浏览器换到大名鼎鼎的IE,所有兼容问题都会暴露出来。

先说结论

  1. 如果你自己从零配置webpack,并且不打算兼容IE,你几乎不需要做任何兼容,一个babel-polyfill足矣
  2. 如果打算兼容IE,并且你用到了es6甚至es7的js语法,光靠babel-polyfill是不够的, babel-polyfill里只提供了一些函数库,像是Promise,fetch,Object.assign,Array类里面的新的一些内置方法,而像class关键字,箭头函数等,还需要做额外的处理

配置

.babelrc

{
  "plugins": [
    "@babel/plugin-transform-destructuring",
    "@babel/plugin-transform-arrow-functions",
    "@babel/plugin-transform-classes",
    "@babel/plugin-transform-template-literals",
    "@babel/plugin-transform-async-to-generator",
    "@babel/plugin-transform-regenerator",
    "@babel/plugin-transform-parameters",
    "@babel/plugin-transform-shorthand-properties",
    "@babel/plugin-proposal-object-rest-spread",
    "@babel/plugin-transform-spread",
    [
      "@babel/plugin-transform-react-jsx",
      {
        "pragma": "h", // default pragma is React.createElement
        "pragmaFrag": "Fragment", // default is React.Fragment
        "throwIfNamespace": false // defaults to true
      }
    ]
  ]
}

我的方案是使用plugins,而不是presets,因为presets体系有版本写法问题,这里暂时先不用了,后面有空会补上

package.json

{
  "name": "syoo.cn",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "release": "./bin/release.sh",
    "deploy": "./bin/release.sh && ./bin/deploy.sh",
    "webpack-dev": "export DEV_IP=`ifconfig | grep -e 'netmask.*broadcast'  | awk 'NR==1;' | awk '{print $2}'` && webpack-dev-server --host 0.0.0.0",
    "jekyll-dev": "export DEV_IP=`ifconfig | grep -e 'netmask.*broadcast'  | awk 'NR==1;' | awk '{print $2}'` && bundle exec jekyll serve -s jekyll --host=0.0.0.0",
    "build": "webpack --mode production"
  },
  "author": "",
  "license": "UNLICENCED",
  "devDependencies": {
    "@babel/core": "^7.5.5",
    "@babel/plugin-proposal-object-rest-spread": "^7.6.2",
    "@babel/plugin-transform-arrow-functions": "^7.2.0",
    "@babel/plugin-transform-async-to-generator": "^7.7.0",
    "@babel/plugin-transform-classes": "^7.7.0",
    "@babel/plugin-transform-destructuring": "^7.6.0",
    "@babel/plugin-transform-parameters": "^7.4.4",
    "@babel/plugin-transform-react-jsx": "^7.3.0",
    "@babel/plugin-transform-regenerator": "^7.7.0",
    "@babel/plugin-transform-runtime": "^7.6.2",
    "@babel/plugin-transform-shorthand-properties": "^7.2.0",
    "@babel/plugin-transform-spread": "^7.6.2",
    "@babel/plugin-transform-template-literals": "^7.4.4",
    "@babel/preset-env": "^7.5.5",
    "@babel/preset-react": "^7.0.0",
    "@fortawesome/fontawesome-free": "^5.9.0",
    "aos": "^3.0.0-beta.6",
    "autoprefixer": "^9.6.0",
    "babel-core": "^6.26.3",
    "babel-loader": "^8.0.6",
    "babel-preset-env": "^1.7.0",
    "bootstrap": "^4.3.1",
    "css-loader": "^3.2.0",
    "eslint": "^6.1.0",
    "eslint-plugin-react": "^7.14.3",
    "file-loader": "^4.2.0",
    "jquery": "^3.4.1",
    "mini-css-extract-plugin": "^0.8.0",
    "node-sass": "^4.12.0",
    "popper.js": "^1.15.0",
    "postcss-modules": "^1.4.1",
    "postcss-preset-env": "^6.6.0",
    "preact": "^8.5.1",
    "sass": "^1.21.0",
    "sass-loader": "^7.2.0",
    "sticky-sidebar": "^3.3.1",
    "style-loader": "^1.0.0",
    "webpack": "^4.39.2",
    "webpack-cli": "^3.3.6",
    "webpack-dev-server": "^3.8.0",
    "whatwg-fetch": "^3.0.0"
  },
  "postcss": {
    "plugins": {
      "autoprefixer": {
        "overrideBrowserslist": [
          ">1%",
          "last 4 versions",
          "Firefox ESR",
          "not ie < 9"
        ]
      }
    }
  },
  "dependencies": {
    "@babel/runtime": "^7.7.2",
    "babel-polyfill": "^6.26.0",
    "css-vars-ponyfill": "^2.1.2"
  }
}

webpack.config entry配置

...
module.exports = {
  entry: ["babel-polyfill","./javascript/packs/index.js"],
...

插件

这里可以看到所有babel插件
可以按需自己装,看自己用到哪些语法了

@babel/plugin-transform-destructuring

解构赋值

let {x, y} = obj;

let [a, b, ...rest] = arr;

@babel/plugin-transform-arrow-functions

箭头函数

var a = () => {};
var a = (b) => b;

@babel/plugin-transform-classes

class 关键字

class Foo extends mixin(Array) {}

@babel/plugin-transform-template-literals

字符串模板

`foo${bar}`;

@babel/plugin-transform-async-to-generator + @babel/plugin-transform-regenerator

这两个加起来可以解决async语法问题

@babel/plugin-transform-parameters

解构参数

function test(x = "hello", { a, b }, ...args) {
  console.log(x, a, b, args);
}

@babel/plugin-transform-shorthand-properties

这个应该叫map解构赋值(吧)

var o = { a, b, c };

@babel/plugin-proposal-object-rest-spread

动态参数

let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };

@babel/plugin-transform-spread

类似解构参数,叫啥我也不知道。

var a = ['a', 'b', 'c'];
var b = [...a, 'foo'];
var c = foo(...a);

其他

在没有webpack的情况下

不要使用es6的语法,但是可以通过从外部的cdn上拉取polyfill来使用一些比较新的标准库函数,具体做法如下

window.Promise || document.write('<script onclick='showViewer()' src="https://cdn.bootcss.com/babel-polyfill/7.6.0/polyfill.min.js"><\/script>')

这样可以节省一些流量,因为目前大部分浏览器其实都已经支持es6了,注意上面的代码要放到head里,如果要使用fetch,可以将这里的代码放到body之前,当然也可以使用cdn从外部拉,但我觉得这个比较小,就没必要

IE的一个比较坑的特性

IE的缓存很迷,建议每次请求前加上下面的两个header

headers: {"cache-control": "no-cache", "pragma": "no-cache"},