Babel 介绍和使用

发布于 2024-12-26 15:42:01 字数 11167 浏览 3 评论 0

babel.config.js(babel7) 或者 .babelrc(<7) 文件 .babelrc.js ​ ,或者放到 package.json ​,是用来设置转码的规则和插件。

npm install -D @babel/core @babel/cli

@babel/cli 是 babel 的命令行工具,主要提供 babel 命令。

babel 的核心功能包含在 @babel/core 模块中。没有它,在 babel 的世界里注定寸步难行。

# vue 项目
{
 // 此项指明,转码的规则
 "presets": [
 // env 项是借助插件 babel-preset-env,下面这个配置说的是 babel 对 es6,es7,es8 进行转码,并且设置 amd,commonjs 这样的模块化文件,不进行转码
 ["@babel/preset-env", { "modules": false }],
 // 下面这个是不同阶段出现的 es 语法,包含不同的转码插件
 "stage-2"
 ],
 // 下面这个选项是引用插件来处理代码的转换,transform-runtime 用来处理全局函数和优化 babel 编译
 "plugins": ["@babel/plugin-transform-runtime","@babel/plugin-transform-arrow-functions","syntax-dynamic-import",{
      "corejs": 3 // 指定 runtime-corejs 的版本
 }], // "syntax-dynamic-import"可不需要
 // 下面指的是在生成的文件中,不产生注释
 "comments": false,
 // 下面这段是在特定的环境中所执行的转码规则,当环境变量是下面的 test 就会覆盖上面的设置
 "env": {
 // test 是提前设置的环境变量,如果没有设置 BABEL_ENV 则使用 NODE_ENV,如果都没有设置默认就是 development
 "test": {
  "presets": ["env", "stage-2"],
  // instanbul 是一个用来测试转码后代码的工具
  "plugins": ["istanbul"]
 }
 }
}
# react 项目
{
 "presets": [
  ["@babel/preset-env", { "modules": false }],
  "stage-2",
  "react"
 ],
 "plugins": ["transform-runtime","@babel/plugin-transform-arrow-functions"],
 "comments": false,
 "env": {
  "test": {
   "presets": ["env", "stage-2"],
   "plugins": [ "istanbul" ]
  }
 }
}

语法转译器

主要对 JavaScript 最新的语法糖进行编译,并不负责转译新增的 API 和全局对象。 如 Promise,Iterator,Generator,Set,Maps,Proxy,Symbol 等全局对象,以及一些定义在全局对象的方法(比如 includes/Object.assign 等)并不能被编译。

常用到的转译器包有,babel-preset-env、babel-preset-es2015、babel-preset-es2016、babel-preset-es2017、babel-preset-latest 等。

在实际开发中可以只选用 babel-preset-env 来代替余下的,但是还需要配上 javascirpt 的制作规范一起使用,同时也是官方推荐

另外最新的提案包含在 stage-* 中,stage 里面包含了当年最新规范的草案,每年更新。

{
  // preset 就是一组插件的集合
 "presets": ["@babel/preset-env", {
   "modules": false,
     "useBuiltIns": "usage",
        "corejs": 3
  }],
  "stage-2" // npm install -D babel-preset-stage-2 
}

关键配置选项 useBuiltIns,它的取值共有三个:

  • false:即不处理 api,不会自动对每个文件的 api 进行转换,也不会去引入 polyfill。
  • entry:对全部文件进行 api 转换,并且需要在入口文件中手动引入 import from @babel/polyfill
  • usage:对 api 的转换采用按需加载,即用到哪个方法就自动引入对应的转换代码,不会全量的引入 polyfill,无需在页面入口手动引入 import from @babel/polyfill

其中 false 是默认值,一般用的比较少,而 @babel/polyfill 在 Babel 7.4 之后分成了两个库 core-js 和 regenerator-runtime,所以需要引入这两个库来代替,一般情况下使用 usage 是最合适的,在构建中会自动扫描代码中使用的新 api,并引入对应的转换代码,而不是全量引入,从而可以减少资源包的大小,但是需要注意的是:

  • 配置 usage 可以按需引入转换代码,但是 @babel/polyfill 依然需要安装。但是引入方式需要修改成 core-jsregenerator-runtime
  • 配置 usage 可以按需引入转换代码,但是对于 node_modules 文件夹下的代码,默认是不会转换的(使用 vue cli 创建的项目,babel-loader 默认不会转换这部分代码),所以类似 ant-design,element-ui 这些使用了新的 api 的库,在 node_modules 里是不会被转换的。

对于此,可以再用 entry 方式来全量引入,确保 api 转换不会出问题,当然可也以修改 vue.config.js 配置文件来增加对 node_modules 下的库转换,代码如下:

module.exports = {
    ...
    transpileDependencies: ['ant-design-vue'],
}

另外,对于 @babel/preset-env 的配置项中的 corejs 需要和安装的 corejs 版本一致。

npm install -D @babel/preset-env

@babel/preset-env 所包含的插件将支持所有最新的 JS 特性(es2015 es2016 等不包含 stage 阶段),将其转换成 ES5 代码。允许我们使用最新的 js 语法,比如 let,const,箭头函数等等。

但是 babel 只转换新的 js 语法,如箭头函数等,但不转换新的 API,这时候需要借助 @babel/polyfill ,把 es 的新特性都装进来。

{
  "presets": [
    ["@babel/preset-env",  {
      "modules": false //默认会将模块转换为 commonjs, 还有其他配置参数:"amd" | "umd" | "systemjs" | "commonjs",
        "useBuiltIns": "usage",
        "corejs": 3
    }]
  ]
}

API 和全局对象转译器

负责转译新增的 API 和全局对象,保证在浏览器的兼容性。如 Promise,Iterator,Generator,Set,Maps,Proxy,Symbol 等全局对象,以及一些定义在全局对象的方法(比如 includes/Object.assign 等)

babel polyfill

垫片,可以转译所有 ES6 API 和全局对象。用来垫平不同浏览器或者不同环境下的差异,让新的内置函数、实例方法等在低版本浏览器中也可以使用。

@babel/polyfill 模块包括 core-js 和一个自定义的 regenerator runtime 模块,可以模拟完整的 ES2015+ 环境(不包含第 4 阶段前的提议)。

babel v7.4 版之后,官方不推荐再使用 @babel/polyfill 了,需要直接安装 core-jsregenerator-runtime 去替代之前的 @babel/polyfill

虽然 @babel/polyfill 还在进行版本升级,但其使用的 core-js 包为 2.x.x 版本,而 core-js 这个包本身已经发布到了 3.x.x 版本了,@babel/polyfill 以后也不会使用 3.x.x 版本的包了。 core-js@2 分支中已经不会再添加新特性,新特性都会添加到 core-js@3

npm install -S core-js regenerator-runtime

//import '@babel/polyfill'; (babel v7.4 版之后,不推荐使用)
import "core-js/stable";
import "regenerator-runtime/runtime";

let func = () => { }
let arr = [1, 2, 4]
arr.includes(3)

缺点: 增加包体,比如仅是使用到一种 ES6 新增 API,他也会增加所有的转移语法。所以使用 @babel/runtime 把所有语法转换会用到的辅助函数都集成在一起

npm install -S @babel/runtime // 产生辅助函数

npm install -D @babel/plugin-transform-runtime // 这个插件的作用就是自动移除语法转换后内联的辅助函数。另一个作用是创建一个沙盒环境来避免对全局环境的污染。 @babel/plugin-transform-runtime 的大多数应用场景是在写第三方库时来使用,这样可以避免影响到使用者的 JavaScript 环境,造成全局污染。在自己独立的项目中,更多情况下推荐使用 @babel/preset-env 搭配 useBuiltIns 即可,而无需再使用 @babel/plugin-transform-runtime ,参考 issues

npm install -S @babel/runtime-corejs3 // 是 @babel/runtime 的进化版,开启 @babel/plugin-transform-runtime 的 API 转换功能

对于 @babel/runtime 及其进化版 @babel/runtime-corejs2、@babel/runtime-corejs3,我们只需要根据自己的需要安装一个。

  • 如果你不需要对 core-js 做 API 转换,那就安装 @babel/runtime 并把 corejs 配置项设置为 false 即可。
  • 如果你需要用 core-js2 做 API 转换,那就安装 @babel/runtime-corejs2 并把 corejs 配置项设置为 2 即可。
  • 如果你需要用 core-js3 做 API 转换,那就安装 @babel/runtime-corejs3 并把 corejs 配置项设置为 3 即可。

全自动的,不会污染全局 API。但是它只会对 es6 的语法进行转换,而不会对新 api 进行转换。如果需要转换新 api,也可以通过使用 @babel/polyfill 来规避兼容性问题

   {
     "presets": [
       "@babel/preset-env"
     ],
     "plugins": [
       [
         "@babel/plugin-transform-runtime",
         {
           "corejs": 3 //corejs 取值是 false、2 和 3,默认值是 false
         }
       ]
     ]
   }

npm install -D babel-plugin-syntax-dynamic-import

这个插件主要解决动态引入模块的问题。如果.babelrc 配置项中使用了"stage-2",也可以不实用该插件,同样支持动态模块引入

   function nDate() {
    import('moment').then(function(moment) {
     console.log(moment().format());
    }).catch(function(err) {
     console.log('Failed to load moment', err);
    });
   }
   nDate();

npm install -D @babel/polyfill

修改全局 prototype 来对 API 和全局变量的垫片的,所以可以转译实例方法。

1.import "@babel/polyfill";

2.require('@babel/polyfill');

3.module.exports = { // 适合使用 webpack 构建的项目
  entry: ["@babel/polyfill", "./app/js"]
};

npm install -S es6-promise

如果仅使用到 promise 相关 API,可以仅添加此转译器

import _promise from 'es6-promise';

const Promise = _promise.Promise;

jsx,flow,TypeScript 等插件转译器

npm install -D @babel/preset-react

npm install -D @babel/preset-env @babel/plugin-transform-runtime

使用 react 项目时,需要使用此包配合转译

{
  "presets": [
    ["@babel/env", {
      "modules": false
    }],
    "@babel/preset-react"
  ],
  "comments": false, //不产生注释
  "plugins": ["@babel/plugin-transform-runtime"]
}

npm install --save-dev @babel/preset-typescript

当项目使用 TypeScript 编写时,需要使用此包配合转译

{
    "presets": ["@babel/preset-typescript"]
}

Browserslist 集成

@babel/preset-env 会根据配置的目标环境,生成插件列表来编译。当不需要兼容所有的浏览器和环境时,通过指定目标环境,可以让编译代码保持最小。

官方推荐使用 .browserslistrc 文件来指定目标环境。

# .browserslistrc
> 1%
not ie <= 8

上面的配置含义是,目标环境是市场份额大于 1%的浏览器并且不考虑 IE8 及以下的 IE 浏览器。

last 2 Chrome versions // 执行 `npm run babel`,你会发现箭头函数不会被编译成 ES5,因为 `chrome` 的最新 2 个版本都能够支持箭头函数。

查看 browserslist 的更多配置

webpack 配置 babel

npm install -D babel-loader

# webpack.config.js
module: {
    rules:[
    {
            test: /\.js$/,
            <!--引入的第三方模块不转码-->
            exclude: /node_modules/, 
            use: [{
                loader: 'babel-loader',
                options: {
                 <!--设置 cache 目录,加快转码速度,默认目录为 node_modules/.cache/babel-loader-->
                cacheDirectory: true,
                },
            }],
        },
    ]
},
<!--在开发模式下配置,通过 chrome devtool/source/webpack-internal 可以看到 babel 转码结果-->
devtool: 'cheap-module-eval-source-map',

另外如果在 webpack 中配置 eslint,还要保证 eslint 的检查在 babel 转码之前,配置如下

module: {
    rules:[{
        // 保证先于 babel-loader 执行
        enforce: 'pre',
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'eslint-loader'
    }]
}
# .eslintrc.js 
parser: 'babel-eslint'

其他插件

总结

  • babel7 的包都是以 @babel 开头的,所有的模块插件啥的都是在 node_modules/@babel/目录下
  • babel 中真正干活的是插件,插件的作用是 transform
  • preset(预置),就是一个插件包的集合,你也可以自己写插件包,插件包不够用,再配置 plugins 呗
  • 配置了 babel7,肯定要用新版本的 babel-loader,老版本的 babel-loader 会找 babel-core 而不是 @babel/core 会报错
  • babel7 新增了 babel.config.js 配置文件,是项目级别的配置,建议使用, .babelrc 配置仍然可以用,至于为啥,memorepo 可以了解一下
  • babel7 废弃了 babel-preset-stage-0 这样的配置,如果不懂 stage-0 啥的,自行学习,如果要用,需要直接引入 cores-js 的相关模块
  • @babel-preset-env 这样的 preset 可简写,如上
  • polyfill 垫片,就是 web 开发中,可移植的代码补充库
  • 关于 babel-polyfill 其实就是 core-js 和 一个工具库
  • core-js 是实现了一些现在没支持的新功能的库,分 2 和 3 两个大版本
  • babel6 之后,对 export default 这样的 es 模块写法不支持,需要一个 babel-plugin-add-module-exports 的库支持
  • 要支持装饰器的写法,需要 @babel/plugin-proposal-decorators 插件支持,配置如上
  • babel-plugin-import 是配置 antd 按需加载的一个插件,做 React 项目,几乎 antd 是必备的吧

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

烂人

暂无简介

文章
评论
26 人气
更多

推荐作者

迎风吟唱

文章 0 评论 0

qq_hXErI

文章 0 评论 0

茶底世界

文章 0 评论 0

捎一片雪花

文章 0 评论 0

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文