Webpack中使用babel的知识点整理 - 知乎

804
原文链接: zhuanlan.zhihu.com

在webpack中配置babel的时候,会有比较多的概念,对babel不太了解的同学经常会很茫然,简单做个总结:

当我们在webpack中使用babel的时候,首先要安装babel-core,这是babel编译库的核心包。

npm install babel-core --save-dev

之后,webpack中对js文件,我们要进行编译,就需要配置,在webpack中,你需要用到babel-loader帮你来使用babel

npm install babel-loader --save-dev

所以webpack.config.js中,你要写好下面的代码:

rules: [
  {
    test: /\.js$/,
    use: {
      loader: 'babel-loader'
    },
    exclude: '/node_modules/'
  }
]

然后我们要理解preset这个概念,也就是在babel编译之前,babel需要直到你的编译规则,到底是以什么样的规范去编译。

比如说,我需要按照es6标准编译,那么你就安装一个 babel-preset-es2015, 同样,如果你要按照es7来编译,那么你就安装babel-preset-es2016:

npm install babel-preset-es2016 --save-dev

一般来说,如果你想用最新的规范做编译,直接安装babel-preset-env就可以了,它包含了 babel-preset-es2015, babel-preset-es2016, and babel-preset-es2017,等价于babel-preset-latest,可以编译所有最新规范中的代码:

npm install babel-preset-env --save-dev

有了编译规则之后,我们继续来配置webpack,在babel-loader中我们可以新增配置参数:

rules: [
  {
    test: /\.js$/,
    use: {
      loader: 'babel-loader',
      options: {
        presets: ['env']  // 也可以写成presets:['babel-preset-env']
      }
    },
    exclude: '/node_modules/'
  }
]

到这一步,打包的时候,babel就会自动按照最新语法规范,对我们的代码进行编译了。

那么问题来了,我们要把我们的代码编译称什么样子呢?如果是一个只要求兼容chrome浏览器的项目,chrome对很多es6语法支持的很好,所以不用做很多编译,代码就可以在chrome下运行了。如果我的项目要兼容到很低的浏览器版本,那么肯定要把es6,7,8的语法编译成es4或者es5的语法。到底编译到什么成都,我们可以通过preset的配置项继续设置:

rules: [
  {
    test: /\.js$/,
    use: {
      loader: 'babel-loader',
      options: {
        presets: [
            ['babel-preset-env', {
                targets: {
                    browser: ['> 1%']
                }
            }]
        ],
      }
    },
    exclude: '/node_modules/'
  }
]

在presets里面,我们对babel-preset-env增加了一个配置项叫做browser,值是>1%,它的意思是,让babel做编译的时候,编译出来的语法支持所有市场占有率超过1%的浏览器。或者你可以写成这样:

rules: [
  {
    test: /\.js$/,
    use: {
      loader: 'babel-loader',
      options: {
        presets: [
            ['babel-preset-env', {
                targets: {
                    browser: ['chrome']
                }
            }]
        ],
      }
    },
    exclude: '/node_modules/'
  }
]

把参数变成chrome,那么打包出的代码,只能保证在chrome上运行正常,其他浏览器能不能跑就不好说了,因为你配置的打包程度就是兼容chrome即可。

这部分的配置参数很灵活,大家可以参考官方文档继续调整:Env preset · Babel

那么接下来我们继续说babel-polyfill是个什么东东。babel官网上写了很明确一句话,babel只负责对语法进行编译。当我们写尖头函数,babel会帮你把它编译成普通函数,这没有任何问题,但是,比如说我们代码里使用了promise,babel打包出来的代码其实还是promise,在低版本浏览器里,promise并不支持,但是babel并不会帮你处理,因为这不是语法编译层面需要做的事情。不转换新的API包括,比如Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise等全局对象。

于是,如果我们要让打包出来的代码能兼容低版本浏览器,还要考虑到promise,Set这样的新语法低版本浏览器不兼容的问题,这时候babel-polyfill就出场了。你只需要全局安装一下babel-polyfill:

npm install --save-dev babel-polyfill

然后在项目中使用一下它,你的代码就不存在刚才提到的兼容性问题了。

import 'babel-polyfill'

但是,直接用babel-polyfill会有一些坑,第一个坑是污染全局环境,比如说低版本浏览器没有Set,但是babel-polyfill会在全局变量里加一个Set。再一个问题是,会造成代码冗余,举个例子,多个模块用到Promise,每个模块里都有可能独立存在一个对Promise做兼容性的代码。所以,使用babel-polyfill可以解决兼容性问题,但并不是最佳方案,于是,出现了babel-plugin-transform-runtime,使用这个插件,就可以解决上面的问题了。

npm install --save-dev babel-plugin-transform-runtime
npm install --save babel-runtime

先安装插件,然后再安装babel-runtime, 之后,我们改一下配置

rules: [
  {
    test: /\.js$/,
    use: {
      loader: 'babel-loader',
      options: {
        presets: [
            ['babel-preset-env', {
                targets: {
                    browser: ['> 1%']
                }
            }]
        ],
        plugins:['transform-runtime']
      }
    },
    exclude: '/node_modules/'
  }
]

增加一个plugin的配置,好了到此,整个babel的配置差不多了。最后我们可以在工程目录下创建一个.babelrc文件,把关于babel的配置放进去:

{
  presets: [['babel-preset-env', {
    targets: {
      browser: ['> 1%', 'last 2 versions']
    }
  }]],
  plugins:['transform-runtime']
}

然后,webpack.config.js 可以精简为:

rules: [
  {
    test: /\.js$/,
    use: {
      loader: 'babel-loader'
    },
    exclude: '/node_modules/'
  }
]

补充几点,一般来说,在自己写框架或者库的时候,使用babel-plugin-transform-runtime是个很好的选择,主要是不污染环境。而如果自己写项目,不使用它,使用babel-polyfill会更简单一些。

另外,babel-polyfill和babel-plugin-transform-runtime是独立的,两者没有依赖关系,不要两个一起安装,没意义~