babel 基础

Babel

Babel 是什么?

Babel 是一个工具集,主要用于将 ES6 版本的 JS 代码转换为 ES5 等向后兼容的 JS 代码,从而可以运行在低版本浏览器或其它环境中。

因此,完全可以使用 ES6 编写程序,最后使用 Babel 转换为 ES5 这样就不用担心所在环境是否支持了。


Babel 配置:

Babel 的配置文件是 Babel 执行时默认在当前目录寻找的文件,主要有

  • .babelrc

    {
    "presets": ["es2015", "react"],
    "plugins": ["transform-decorators-legacy", "transform-class-properties"]
    }
    
  • .babelrc.js

  • .babel.config.js

    // 对于 babel.config.js 和 .babel.js 它们的配置是一样的
    // 通过 module.exports 输出配置项
    
    module.exports = {
      "presets": ["es2015", "react"],
      "plugins": ["transform-decorators-legacy", "transform-class-properties"]
    }
    
  • .babel.config.json

  • .package.json

    {
      "name": "demo",
      "version": "1.0.0",
      "description": "",
      "main": "index.js",
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1"
      },
      "author": "",
      "babel": {
        "presets": ["es2015", "react"],
        "plugins": ["transform-decorators-legacy", "transform-class-properties"]
      }
    }
    

它们的配置项都是相同的,其实都是 plugins 和 presets,作用也是一样的,只需选择一种

除了将配置写在配置文件中,也可以写在构建工具的配置里,对于不同的构建工具,Babel 也提供了相应的配置,如 webpack 的 babel-loader 的配置项,本质和配置文件一样。

配置文件总结起来就是配置 plugins 和 presets 这两个数组,分别成为 插件数组 和 预设数组

除去 plugins 和 presets 这两个配置项,还有 minified、ignore等,但是平时基本用不到

推荐 后缀名 js 的配置文件因为可以用 js 做 逻辑处理

  //  这里只是举个例子,实际项目中,我们可以传入环境变量等来做处理
  var year = 2020;
  var presets = [];
  if (year > 2018) {
    presets = ["@babel/env"];
  } else {
    presets = "presets": ["es2015", "es2016", "es2017"],
  }
  module.exports = {
    "presets": presets,
    "plugins": []
  }

插件与预设:

plugin 代表插件,preset 代表预设,分别放在 plugins 和 presets下,每个预设或插件都是一个 npm 包

Babel 的 插件非常多,而所有的插件第必须先安装 npm 包到 node_modules 下才可使用

假如只配置插件数组,那么需要将插件都下载下来,那么 Babel 配置文件会非常臃肿

所以 presets 预设就是帮助解决这个问题的,预设是一组 Babel 插件的集合,如 babel-preset-es2015 就是所有处理 es2015 的二十多个 Babel 插件集合。另外,预设也可以是插件和其它预设的集合,所有的预设都需要先安装 npm 包 到 node_modules


plugin 与 preset 的短名称:

插件可以在配置文件里写短名称,如果插件的 npm 包名称前缀为 babel-plugin- , 那么可以省略前缀

如果 npm 包名称的前缀带有 npm 作用域 @ 如 @org/babel-plugin-xxx ,短名称可写 @org/xxx

目前 Babel7 的官方 npm 包里绝大部分插件已经升级为 @babel/plugin- 前缀的,这种情况的短名称比较特殊了,绝大部分可以像 babel-plugin- 那样省略 @babel/plugin- 。但 babel 官方并没有给出明确的说明,所以还是推荐用全称。

预设的短名称规则和插件的类似,预设 npm 包名称的前缀为 babel-preset- 或作用域 @xxx/babel-preset-xxx 的可以省略 babel-preset-

对于 Babel7 的官方 npm 包里绝大部分预设已经升级为 @babel/preset- 前缀的,这种情况的短名称比较特殊了,绝大部分可以像 babel-preset- 那样省略 @babel/preset- 。但 babel 官方并没有给出明确的说明,例如,@babel/preset-env 的短名称就是 @babel/env,所以还是推荐用全称。


执行顺序:

plugins 插件数组和 presets 预设数组是有顺序要求的,如果两个插件或预设都要处理一个代码块,那么会根据插件和预设的顺序来执行,规则如下:

  • 插件比预设先执行
  • 插件执行顺序是插件数组从前向后执行
  • 预设执行顺序是预设数组从后向前执行

Babel 插件和预设的参数:

每个插件都是插件数组的成员项,每个预设都是预设数组的成员项,而要改写一个数组,数组的第一项是插件或预设的名称字符串,第二个是各对象,该对象由于设置第一项代表的插件或预设的参数,如:

// 给 @babel/preset-env 设置参数
{
    "presets": [
        [
            "@babel/preset-env",
            {
                "useBuiltIns": "entry"
            }
        ]
    ]
}

预设和插件的选择:

目前来讲,可能会用到的预设可能只有四个:

  • @babel/preset-env
  • @babel/preset-flow
  • @babel/preset-react
  • @babel/preset-typescript

插件选择,目前较常用的插件只有 @babel/plugin-transform-runtime,很少见到其它,需要其它的插件时可以去官网找


Babel-polyfill:

在 Babel7 以后名称为 @babel/polyfill

polyfill 广义上讲为环境提供不支持的特性的一类文件或库

总的来说,Babel 官方的 polyfill 使用方法如下:

  • 直接在 html 文件 引用 Babel 官方的 polyfill.js 脚本文件
  • 在前端工程的入口文件里引入 polyfill.js
  • 在前端工程的入口文件里引入 @babel/polyfill
  • 在前端工程的入口文件里引入 core-js/stable 与 regenerator-runtime/runtime
  • 在前端工程构建工具的配置文件入口引入 polyfill.js
  • 在前端工程构建工具的配置文件入口引入 @babel/polyfill.js
  • 在前端工程构建工具的配置文件入口引入 core-js/stable 与 regenerator-runtime/runtime

因为官方不在推荐使用 @babel/polyfill 包括官方的 polyfill.js

所以目前应该使用如下两个方法:

// 在 前端工程的 入口文件 引入 core-js/stable 和 regenerator-runtime/runtime
import "core-js/stable"; 
import "regenerator-runtime/runtime";
```javascript
// 在 前端工程构建工具的配置文件入口里引入 core-js/stable 和 regenerator-runtime/runtime
// 将 webpack.config.js 的 entry 项数组的前两项改为 core-js/stable 和 regenerator-runtime/runtime
const path = require('path');
  module.exports = {
    entry: ['core-js/stable', 'regenerator-runtime/runtime', './a.js'],
    output: {
      filename: 'b.js',
      path: path.resolve(__dirname, '')
    },
    mode: 'development'
  };
// 然后执行 npm run dev 打包

@babel/preset-env:

@babel/preset-env 的参数项,数量有十几个,但大部分要么用不到,要么将废弃,重点学的有 targets、useBuiltlns、modules、corejs。

对于 preset 当不需要对其设置参数时,只需将该 preset 名称放入 presets 中即可

module.exports = {
    presets: ['@babel/env'], // @babel/env 为 @babel/preset-env 的缩写
    plguins: []
}

如果需要对某个 preset 设置参数, 该 preset 就不能以字符串形式直接放在 presets 中,而是应该在包裹一层数组,数组第一项是该 preset 字符串,第二项是该 preset 的参数对象,如果该preset 没有参数需要设置,则数组第二项可以是空对象或不写第二项,一下方法是等价的:

module.exports = {
    presets: ["@babel/env"],
    plugins: []  
}
```javascript
 module.exports = {
    presets: [["@babel/env", {}]],
    plugins: []
 }
```javascript
 module.exports = {
    presets: [["@babel/env"]],
    plugins: [] 
 }
```javascript
"browserslist": [
    "> 1%",
    "not ie <= 8"
]
// 即 目标环境是 市场份额大于 1% 的浏览器 且不考虑 IE8 及以下 IE 浏览器
// Browserslist叫做目标环境配置表,除了写在package.json里,也可以单独写在工程目录下.browserslistrc文件里。
// 用browserslist来指定代码最终要运行在哪些浏览器或node.js环境。Autoprefixer、postcss等就可以根据browserslist,来自动判断是否要增加CSS前缀(例如'-webkit-')。
// Babel也可以使用browserslist,如果使用了@babel/preset-env这个预设,此时Babel就会读取browserslist的配置。
// 如果 @babel/preset-env 不设任何参数。Babel 会 完全根据 browserslist 的配置做语法转换,如果没有 browserslist 那么 Babel 会 将所有 ES6 语法 转换为 ES5 版本
// 如果 Babel 没有配置任何预设或插件,那么 Babel 对转换的代码不做任何处理

参数项:

targets:

该参数项可以取值为字符串,字符串数组或对象,不设置的时候去默认值空对象 {}

写法同 browserslist 一样,如下:

module.exports = {
    presets: [["@babel/env",{
        targets: {
            'chrome': "58",
            "ie": "11"
        }
    }]],
    plugins: []
}
// 如果 使用了 targets 参数,那么就不应该使用 browserslist ,反之,如果 targets 和 browserslist 都没有配置,那么默认将所有 ES6 语法 转换为 ES5

// 正常情况下 推荐使用 browserslist 的配置而非 targets
useBuiltIns:

useBuiltlns 项取值可以使 'usage'、'entry'、或 false 如果不配置,默认取 false

主要与 polyfill 行为有关,如果没有配置或取值为 false,polyfill 会全部引入最终的代码中去

取值为 entry 或 usage 时,会根据配置的目标环境找出需要的 polyfill 进行部分引入

useBuiltIns: 'entry'

module.exports = {
    presets: [["@babel/env",{
        useBuiltIns: 'entry'
    }]],
    plugins: []
}
// 会 根据输入的代码和目标浏览器 自动引入相应的补齐模块
// 需要在 入口文件 引入 polyfill
// 不会根据使用的 API 进行针对引入
// 使用 entry 时 只能 import polyfill 一次,多次 import 会报错

useBuiltIns: 'usage'

module.exports = {
     presets: [["@babel/env", {
      useBuiltIns: "usage"
    }]],
    plugins: []
}
// 会 根据输入代码好目标浏览器 自动引入相应补齐模块
// 不需要在 入口文件 引入 polyfill
// 根据使用的 API 进行针对引入
corejs:

参数项取值可以为 2 或 3,默认取值 2(还有一种对象 proposals 取值方法 ,但是实际用不到,可忽略)

只有 useBuiltIns 为 usage 或 entry 时生效

取默认值 2 时,Babel 转码使用的是 core-js@2 版本(即 core-js2.x.x)。因为某些新 API 只有 core-js@3 才有,如数组的 flat 方法,需要使用 core-js@3 的 API 模块进行补齐,此时将该项设为 3

在使用时,必须安装并引入 core-js 文件,值为 2 引入 @2 版本,值为 3 引入 @3 版本,否则会报错

modules:

可 取值 amd、umd、systemjs、commonjs、cjs、auto、false

默认取值 auto

用于设置是否将 ES6 模块语法转为 其它模块语法

常见的模块语法如下:

  • ES6 的模块语法 import 与 export
  • commonjs 模块语法 require 与 module.exports

值为 auto 或 不设置, import 会被转为 require


@babel/runtime

集成了所有语法转换会用到的辅助函数

  {
    "presets": [
      "@babel/env"
    ],
    "plugins": [
      "@babel/plugin-transform-runtime"
    ]
  }

具有三大作用:

  • 会自动移出语法转换后内联的辅助函数,改为使用 @babel/runtime/helpers 里的辅助函数替代,减少了手动引入的麻烦
  • 当代码使用了 core-js 的 API 自动引入 @babel/runtime-corejs3/core-js-stable/,以此代替全局引入的 core-js/stable
  • 当代码使用了 Generator/async 函数,自动引入 @babel/runtime/regenerator 以此代替全局引入的 regenerator-runtime/runtime

作用 2 、3其实是在做 API 转换,对内置对象重命名,防止污染全局环境

  {
    "plugins": [
      "@babel/plugin-transform-runtime"
    ]
  }
  // 是上方的默认值
  { 
    "plugins": [
      [
        "@babel/plugin-transform-runtime",
        {
          "helpers": true, // 是否自动引入辅助函数包。取值为 布尔值 默认为 true

          "corejs": false, // 是否做 API 转换以避免污染全局环境 取 false 2 3
            // 一般取 false 即 不对 Promise 这类 API 进行 转换

          "regenerator": true,// 是否做 API 转换以避免污染全局环境 取布尔值

          "useESModules": false, // 是否使用 ES6 模块化语法 取值 布尔值, 默认 false 
            // 在用 webpack 等打包工具时 设 true 以便静态分析

          "absoluteRuntime": false, // 用于自定义 
            // @babel/plugin-transform-runtime 引入 @babel/runtime/ 模块的路径规则
            // 取值 布尔值 或 字符串,没有特殊需求,不做修改 保持默认 false 即可

          "version": "7.0.0-beta.0"
        }
      ]
    ]
  }

babel 基础
http://localhost:8080/archives/cc27ae56-0792-46c5-829f-ccb5ffe9bd84
作者
inksha
发布于
2024年09月14日
许可协议