Skip to content

Babel

官网解释:Babel 是一个工具链,主要用于将 ECMAScript 2015+ 代码转换为当前和旧版浏览器或环境中向后兼容的 JavaScript 版本。

@babel/core

是 Babel 实现编译的核心,平常说的 Babel 6(babel-core)、Babel 7 指的就是 @babel/core 的版本。

Presets

预设说明
@babel/preset-env编译 ES2015+ 语法
@babel/preset-typescript编译 Typescript 语法
@babel/preset-react编译 React 语法
@babel/preset-flow编译 Flow 语法

安装一个预设,相当于安装了一系列的插件,通过预设可以减少开发者的配置。

@babel/preset-env

.babelrc 或 babelrc.js 或 babel.config.js:

presets: [
 "@babel/preset-env",
]

只包含编译stage4的预设

这意味着使用这个 Babel 插件预设时,如果想要让 Babel 自动包含所需的 polyfill,需要显式地设置 useBuiltIns 选项(entry、usage)。
presets: [
  // @babel/preset-env 只转换语法,不要提供 polyfill
  [
    "@babel/preset-env", 
    {
      useBuiltIns: false
    }
  ]
],

如何查看当前 @babel/preset-env 包含了哪些插件呢?

@vue/babel-preset-app

如果用 Vue,presets 一般是 @vue/app,这个是把在 @babel/preset-env 包含的 plugins 上又加了很多自己定义的 plugins。

默认的 Vue cli 项目会使用 @vue/babel-preset-app,默认配置了@babel/plugin-transform-runtime。

package.json 文件里的 browserslist 字段 (或单独的 .browserslistrc 文件),用来指定项目的目标浏览器。这个值会被 @babel/preset-env 和 autoprefixer 用来确定需要转译的 JavaScript 特性和需要添加的 CSS 浏览器前缀。

module.exports = {
  presets: [
    '@vue/app'
  ]
}

Babel 插件和预设执行顺序

  • 插件 plugins 比预设 presets 先执行

  • 插件 数组从前向后执行

  • 预设 数组从后向前执行

ES2020 语法配置demo

为例:

let obj = {}
obj?.foo?.xxx
  • 确定 是 ES2020 新增特性
  • 获取项目中 @vue/babel-preset-app 版本,以此获取其依赖项 @babel/preset-env 版本
  • 根据 @babel/preset-env 版本,确定是否包含 ES2020 特性
  • 如果已包含,则项目中配置该预设就可以使用
  • 如果不包含,则需要安装对应 plugin

安装插件:

npm install @babel/plugin-proposal-optional-chaining --save-dev

babel.config.js:

module.exports = {
  presets: [
    '@vue/app'
  ],
  plugins: [
    '@babel/plugin-proposal-optional-chaining'
  ]
}

template 模板中支持。

vue.config.js:

chainWebpack: (config) => {
  config.module
    .rule('vue')
    .use('vue-loader')
    .tap(options => {
      options.compiler = require('vue-template-babel-compiler')
      return options
    }
  )
}

polyfill

ES6+ API 的方法与实现的集合叫做 polyfill,也就是经常说的"垫片"。

Babel 默认只转换新的JavaScript 语法,而不转换新的API,比如Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise等全局对象,以及一些定义在全局对象上的方法(比如Object.assign)。

这些在使用时需要用polyfill的方式来提供旧环境的兼容性。

在Babel 7.4.0以上版本,提供了一个新的插件,叫@babel/plugin-transform-runtime,它可以帮助我们按需引入polyfill。

webpack中使用babel

module: {
  rules: [
    {
      test: /\.js$/,
      exclude: /node_modules/,
      use: {
        loader: 'babel-loader',
        options: {
          presets: ['@babel/preset-env'], // 只进行语法转换
          plugins: [
            [
              // 将core-js交给transform-runtime处理 API
              // 解决多个地方使用相同代码导致打包重复的问题
              "@babel/plugin-transform-runtime",
              {
                "corejs": 3 // 推荐版本, 注意要安装@babel/runtime-corejs3
              }
            ]
          ]
        }
      }
    }
  ]
}

‌@babel/plugin-transform-runtime和@babel/runtime通常是一起使用的‌。@babel/plugin-transform-runtime插件的主要作用是将Babel转换后的代码中的辅助函数集中放在一个单独的运行时库(如@babel/runtime)中。

因为我们用了 exclude: /node_modules/,可能会造成某个第三方依赖出现兼容性问题,解决办法就是在 vue.config.js 设置:

transpileDependencies: [
  'module-name'
]