webpack5 配置babel

1,096 阅读4分钟

大家好, 前面有篇文章讲述 loader [ webpack 二基础配置:配置loader] 时,babel相关配置比较多,也遇到了一些问题,因此这里专门整理了 babel 相关知识并记录下。

前置介绍准备:

babel官网

bable-loader 介绍

  •  bable-loader 把ES6转化成ES5。js es6 及以上会用到新特性,webpack 不能完全支持,因此需要load 转化语法。

环境相关: webpack 5 + babel 9 + @babel/...

1. 安装 babel-loader 并配置 对应 loader 的rules

  • 首先肯定需要安装 babel-loader
  • 当我们在webpack中使用babel的时候,首先要安装@babel/core,这是babel编译库的核心包。 如果某些代码需要调用Babel的API进行转码,就要使用@babel/core模块。
npm install babel-loader @babel/core -D

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

所以webpack.config.js中,配置下面的代码:

module:{ //设置模块
    rules:[ //设置loader
      {
        test:/.js$/, //已作为js扩展名这样类型的文件
        exclude:/node_modules/, //排除node_modules文件夹
        use:{
          loader:'babel-loader', //转换成es5
        }
      }
    ]
  },

2. @babel/preset-env

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

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

npm install babel-preset-es2016 -D

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

  • 2.1 安装 babel-preset-env
npm install babel-preset-env -D

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

module:{ //设置模块
    rules:[ //设置loader
      {
        test:/.js$/, //已作为js扩展名这样类型的文件
        exclude:/node_modules/, //排除node_modules文件夹
        use:{
          loader:'babel-loader', //转换成es5
          options:{ 
              presets:['@babel/preset-env'], //设置编译的规则  presets:['env'] 
          }
        }
      }
    ]
  },

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

当然最好不在 webpack.config.js这里配置 presets 选项

options:{ 
  presets:['@babel/preset-env'], //设置编译的规则  presets:['env'] 
}

而是在项目根目录新建文件 ( babel.config.* 或 .babelrc.*)

    1. babel.config.* :新建文件,位于项目根目录 会作为全局配置
    • babel.config.js 文件或
    • babel.config.json ( babel7 版本 推荐建babel.config.json文件 )
    1. .babelrc.* :新建文件,位于项目根目录 不会作为全局配置
    • .babelrc 文件或

    • .babelrc.js 文件或

    • .babelrc.json

babel.config.json 配置

{
    "presets": [
        [
            "@babel/preset-env",  // 将es6的语法翻译成es5语法
            {
                "targets": { // 兼容 浏览器及版本
                    "edge": "17",
                    "firefox": "60",
                    "chrome": "67",
                    "safari": "11.1"
                },
                "useBuiltIns": "usage",// 做@babel/polyfill补充时,按需补充,用到什么才补充什么,
                "corejs": "3"
            }
        ],
        [
            "@babel/preset-typescript", // 用于 ts, 需安装 @babel/preset-typescript
            {
                "isTSX": true, 
                "allExtensions": true
            }
        ]
    ],
    "plugins": [
        [
            "@babel/plugin-transform-runtime",
            {
                "corejs": 3, // 如果配置了3, 则需要安装 npm install --save @babel/runtime-corejs3
                "helpers": true,
                "regenerator": true,
                "useESModules": false
            }
        ]
    ]
}

我们在上面通过preset的targets配置项 配置了浏览器及版本 需要向下兼容的程度。

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

  • 2.2 @babel/preset-react 用于react 安装
npm install @babel/preset-react -D
  • 2.3 @babel/preset-typescript 用于ts 安装
npm install @babel/preset-typescript -D
  • 2.4 @babel/preset-flow 用于flow

3. babel-polyfill (已过时,在此主要做下介绍,可以跳过看 下一个 4. regeneratorRuntime插件)

那么接下来我们继续说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 babel-polyfill -D

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

import 'babel-polyfill'

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

4. regeneratorRuntime插件 (替代了上面的 3.babel-polyfill )

  • 4.1 安装包 @babel/plugin-transform-runtime 依赖 @babel/runtime。
npm i @babel/plugin-transform-runtime @babel/runtime -D

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

rules: [
  {
    test: /.js$/,
    use: {
      loader: 'babel-loader',
      options: {
        options:{
            presets:['@babel/preset-env'], //设置编译的规则
        },
        plugins:[ // 设置编译的插件
            ['@babel/plugin-transform-runtime'] //设置编译的规则
        ],
      }
    },
    exclude: '/node_modules/'
  }
]

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

{
    "presets": [
        [
            "@babel/preset-env",  // 将es6的语法翻译成es5语法
            {
                "targets": { // 兼容 浏览器及版本
                    "edge": "17",
                    "firefox": "60",
                    "chrome": "67",
                    "safari": "11.1"
                },
                "useBuiltIns": "usage",// 做@babel/polyfill补充时,按需补充,用到什么才补充什么,
                "corejs": "3"  //  corejs 配置依赖的是 `core-js`, 需安装core-js
            }
        ],
        [
            "@babel/preset-typescript", // 配置了.ts
            {
                "isTSX": true, 
                "allExtensions": true
            }
        ]
    ],
    "plugins": [
        [
            "@babel/plugin-transform-runtime",
            {
                "corejs": 3,//  corejs 配置依赖的是 `@babel/runtime-corejs3`, 需安装 @babel/runtime-corejs3
                "helpers": true,
                "regenerator": true,
                "useESModules": false
            }
        ]
    ]
}

  • 4.2 同时安装 @babel/runtime-corejs3,

    所谓的 corejs 正是 @babel/plugin-transform-runtime 来实现 @polyfill 的核心库。

    简单点来说,只有指定了 corejs 版本的话,@babel/plugin-transform-runtime 才会根据指定的 corejs 版本对于我们的源代码动态添加 polyfill

npm i @babel/runtime-corejs3 -D

关于 corejs 存在以下的版本:

corejs选项安装命令
falsenpm install --save @babel/runtime
2npm install --save @babel/runtime-corejs2
3npm install --save @babel/runtime-corejs3
  • 当为 false 时,表示仅仅包含 @babel/runtime@babel/runtime 的作用我们刚刚已经讲过了。(注意 false 配置并不代表开启 @babel/runtime

  • corejs 2 版本,目前已经不再维护了,所以这里不推荐大家使用。

  • corejs 3 版本,是目前最常用的版本,对比 2 版本。3 版本会额外增加一些实例方法的 polyfill 比如 "foobar".includes("foo") 中的 includes 方法 2 中是不存在的。

所以说,所谓的 corejs 配置就是针对于运行时的 polyfill 配置。如果开启了 corejs(不为false) 那么 @babel/plugin-transform-runtime 会在代码运行时为我们动态注入 polyfill 内容。

误区

需要特别留意的是 @babel/plugin-transform-runtime 的 corejs 选项和 preset-env 的 corejs 配置看起来虽然是相似的。

但是他们引入的包内容是完全不同的,preset-env 中的 corejs 配置依赖的是 core-js(大版本 2 or 大版本 3) 这个包,这个包中的 polyfill 会污染全局作用域。

而 @babel/plugin-transform-runtime 中的 corejs 选项依赖的是 @babel/runtime-corejs3/@babel/runtime-corejs2 这两个包,这两个包内提供的则是一种不污染全局作用域的 polyfill 方式。

当然,@babel/plugin-transform-runtime 的 corejs 配置默认为 false,而当使用 preset-env 设置 useBuintIns: usage or entry 时,corejs 默认为 2。

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

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

补充几点,

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

  • 还有就是transform-runtime不能完全替代babel-polyfill。transform不支持实例方法,例如,代码:[1, 2, 3].includes(3),Array,Object以及其他”实例”下es6的方法,因为babel-runtime只支持static方法。

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

参考链接:

  1. webpack怎么配置babel?
  2. 一文谈完前端项目中的Babel配置
  3. babel结合core-js使用指南
  • 文章的 4.1 @babel/preset-env