关于前端:手把手教你如何配置Babel1

4次阅读

共计 6635 个字符,预计需要花费 17 分钟才能阅读完成。

指标

本文的目标是帮忙对 Babel 不相熟的人理解 如何书写 Babel 的配置文件,设计一个“最完满”的 Polyfill 计划

因为内容比拟多,我会把上面的目录中的内容分成四个章节去解说

  • 第一章节

    • 什么是 Babel
    • 插件和预设
    • 配置文件
    • 简略 Demo 演示
  • 第二章节

    • core-js
  • 第三章节

    • 什么是 Polyfill
    • @babel/polyfill 介绍
    • @babel/preset-env 实战
  • 第四个章节

    • @babel/runtime 实战
    • @babel/plugin-transform-runtime 实战
    • @babel/core 介绍
    • @babel/cli 介绍

文章中展现的 demo 都会增加源码链接

├── README.md
├── lerna.json
├── package.json
└── packages
    ├── tutor-basic
    ├── tutor-polyfill01
    ├── tutor-polyfill02
    ├── tutor-polyfill03
    ├── tutor-polyfill04
    ├── tutor-polyfill05
    ├── tutor-preset_env
    ├── tutor-preset_env02
    ├── tutor-preset_env03
    ├── tutor-preset_env04
    ├── tutor-preset_env05
    ├── tutor-preset_env06
    ├── tutor-preset_env07
    ├── tutor-runtime01
    ├── tutor-runtime02
    ├── tutor-runtime03
    └── tutor-runtime04

前言

本章节内容只有介绍一下 老成长谈货色——Babel 的一些概念, 思考以下问题:
须要记住的内容:

  • 为什么要编译?
  • 插件和预设的区别和关系?
  • 插件和预设解析程序?
  • 没有配置预设和插件转换后果是什么?
  • 指标环境配置表是什么货色?

什么是 Babel

Babel is a JavaScript compiler.

Babel 是一个 Javascript 编译器。Babel 官网解释很简略,然而想要真正理解 Babel 的确不简略。

为什么要编译转换

究其原因,前端语言个性 (esnext、typescript、flow 等) 和宿主环境 (浏览器 /Node.js) 高速倒退,宿主环境无奈及时反对新的语言个性。因而,须要把新的语言个性 降级解决 转换成指标环境 反对的语法,并且对指标环境不反对的 API 增加 Polyfill

Babel 对代码降级解决,能够概括为两局部:

  • 语法转换——例如:箭头函数语法、async 函数语法、class 定义类语法、解构赋值等。
  • 补齐新的 API——例如:Array.prototype.includes,String.prorotype.includes,PromiseMapSymbol

Babel 的编译流程

Babel 是 源代码 指标环境源代码 的转换,依然是 高级语言到高级语言的转换,整个过程可分为三个阶段:

  • 解析(parse)—— 通过 @babel/parser 把源代码字符串转成形象语法树(AST)
  • 转换(transform)——通过 @babel/traverse 遍历形象语法树 (AST), 并调用 Babel 配置文件中的插件 , 对形象语法树 (AST) 进行增删改
  • 生成(generate)——通过 @babel/generator 把转换后的形象语法书 (AST) 生成指标代码

Babel 官网的插件和预设的数量十分多,不过罕用的插件和预设只有几个,接下来重点解说这几个插件和预设,其余的能够触类旁通,举一反三。

插件(Plugin)

在转换的过程中,Babel 插件会对形象语法树 (AST) 进行增删改,如果不给 Babel 装上插件,形象语法树将会不变,代码就会原样输入。正是因为有插件的存在,Babel 能力对形象语法书 (AST) 进行增删改,继而产生指标源代码。

插件分类

Babel 插件大抵分为以下两种:

  • 语法插件(syntax plugin)——作用于 @babel/parser,解析特定类型的语法,将代码解析为形象语法树(AST)。jsxflow
  • 转换插件(transform plugin)—— 负责对形象语法树进行增删改

语法插件虽名为插件,但其自身并不具备功能性。语法插件所对应的语法性能其实都已在 @babel/parser 里实现,插件的作用只是将对应语法的解析性能关上。

转换插件会主动启用相应的语法插件。因而,如果曾经应用了相应的转换插件,则无需指定语法插件。是不是对这两种插件的区别有点懵逼?不必放心,持续往下看。

下文提及的 Babel 插件将专指转换插件

Babel@7 官网有 90 多个插件,不过大半曾经整合在 @babel/preset-env@babel/preset-react@babel/preset-typescript 等预设里了,个别状况下,咱们在开发的时候间接应用预设就能够了。

预设是什么?

预设(Presets)

插件 (plugin) 只是对单个性能进行转换,当配置的插件比拟多的时候,就能够封装成预设 (Presets),来简化插件(Plugins) 的应用的,预设即一组事后设定的插件。

目前 Babel 官网举荐的 preset,有上面四个:

  • @babel/preset-env 所有我的项目都会用到的
  • @babel/preset-react react 框架须要的
  • @babel/preset-flow flow 须要的。Flow 是一个动态类型检测工具,进行类型查看,相似于 ts
  • @babel/preset-typescript typescript 须要的

其它的 preset,如在 Babel@6 的时代,常见的 babel-preset-es2015、babel-preset-es2016、babel-preset-es2017、babel-preset-latest、babel-preset-stage-0、babel-preset-stage-1、babel-preset-stage-2 等这些从 Babel@7 开始曾经 不举荐应用了

插件程序

如果两个转换器都拜访同一个“Program”节点,则转换器会依照以下程序运行

  • 插件在 Presets 前运行。
  • 插件能够指定从头到尾的程序(数组坐标 0 权重最大)。
  • Preset 程序是相同的 (从后到前).

例如:

{
  "plugins": [
    "transform-decorators-legacy",
    "transform-class-properties"
  ]
}

将会运行 transform-decorators-legacy 而后是 transform-class-properties

对于 presets 肯定要记住,程序是相同的。如下:

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

按以下程序运行:@babel/preset-react 再运行 @babel/preset-env。

2. 接下来咱们会学习 @babel/polyfill@babel/preset-env@babel/plugin-transform-runtime 与等内容
从配置文件内容方面辨别,Babel 提供了两种配置内容。一种是由 js 编写,通过 module.exports={}形式输入对象。例如 Vue 的 Babel 配置文件内容

const babelPresetFlowVue = {
  plugins: [require('@babel/plugin-proposal-class-properties'),
    // require('@babel/plugin-syntax-flow'), // not needed, included in transform-flow-strip-types
    require('@babel/plugin-transform-flow-strip-types')
  ]
}

module.exports = {
  presets: [require('@babel/preset-env'),
    // require('babel-preset-flow-vue')
    babelPresetFlowVue
  ],
  plugins: [require('babel-plugin-transform-vue-jsx'),
    require('@babel/plugin-syntax-dynamic-import')
  ],
  ignore: [
    'dist/*.js',
    'packages/**/*.js'
  ]
}

这种有 js 编写的文件后缀都是.js。比方babel.config.js.babelrc.js

另外一种是间接书写 json 内容。例如 Element-UI 的配置文件

{"presets": [],// 省略了内容
  "plugins": ["transform-vue-jsx"]
}

此时文件后缀个别为.json 或者没有 例如:babel.config.json.babelrc

两种类型的文件,个别都会放到 我的项目根目录上面 或者同 package.json 同目录。如果是一个由 Lerna 治理的 Monorepo 类型的我的项目,这两种形式会有一些区别。如下

指标环境配置表

大家可能在我的项目的根目录见过这么一个文件 .browserslistrc,或者在package.json 中见 browserslist 字段吧?

他的中文名字叫 指标环境配置表,他的用户很大,须要引起足够的器重。

例如:AutoprefixerBabel 都是依据指标环境配置表提供的的 指标浏览器的环境 来,主动的增加 css 前缀,js 的 polyfill 垫,而不是无脑的增加兼容,以进步代码的编译品质。

艰深的说,指标环境配置表通知 babel 指标浏览器有哪些,如果指标浏览器不反对某种 API 或者语法,babel 会主动解决。

怎么批改和配置指标环境配置表呢?答案是看官网文档 browserslist,或者更简略的办法去看一下 vue-clicreate-react-app生成的我的项目外面怎么配置的。理解一下字段的意思,用到的时候在去改。

如果我的项目中没有配置指标环境配置表 browserslist, 能够指定默认配置

配置文件类型:

Babel 有两种并行的配置文件形式:

  • 我的项目范畴的配置(Project-wide)
  • 文件相干的配置(File-relative)

    • .babelrc(和 .babelrc.js)文件
    • 带有 “babel” 键的 package.json 文件
Version Changes
v7.8.0 反对 .babelrc.mjs , babel.config.mjs
v7.7.0 反对 .babelrc,.babelrc.json, .babelrc.cjs, babel.config.json, babel.config.cjs

两种配置文件的区别,如果不明确能够临时略过,不影响前面的学习,最初完结之后,在回来认真斟酌

我的项目范畴的配置

Babel 7.x 中的新性能,Babel 具备 “root” 目录的概念,”root” 目录默认为 以后的工作目录 。编译时,Babel 将主动搜寻绝对于此根目录下的 babel.config.js 文件,或其 Babel 认可的文件,比方:babel.config.json,babel.config.cjs,babel.config.mjs

长处

它们是十分适合并值得广泛应用的配置,它甚至容许 pluginspresets 能够轻松利用于node_modules 或符号链接包中的文件

毛病

因为它依赖于工作目录, 如果一个我的项目属于 Monorepo 类型我的项目,当工作目录不是的根目录 (root),编译时就找不到配置文件,如此一来在Monorepo 中应用会比拟苦楚。

babel.config.js
package.json
packages/
  mod1/
    package.json
    src/index.js
  mod2/
    package.json
    src/index.js

各个子模块构建的时候,用户将须要通过 rootMode 手动设置它的门路,以此来加载 babel.config.js 文件

CLI
babel --root-mode upward src -d lib
Webpack
module: {
  rules: [
    {
      loader: "babel-loader",
      options: {rootMode: "upward",},
    },
  ];
}

具体内容能够参考官网文档的演示

文件相干配置

编译时,Babel 从 正在被编译的 文件 所在的 目录开始 去搜寻 .babelrc.json或其余 Babel 认可的配置文件。比方:babelrc,.babelrc.js,/package.json#babel。有了这个性能,就能够为 package 的子模块 创立独立的配置。
同时,文件相干配置 我的项目相干配置 能够独特应用。上面是官网的解释:

File-relative configurations are also merged over top of project-wide config values, making them potentially useful for specific overrides, though that can also be accomplished through “overrides”.

艰深的翻译就是以下两点:

  • 不同的配置:文件相干配置 和 我的项目相干配置 能够合并到一起
  • 雷同的配置:文件相干配置 会笼罩 我的项目相干配置

    babel.config.js
    package.json
    packages/
    mod1/
      package.json
      src/index.js
      .babelrc
    mod2/
      package.json
      src/index.js
      .babelrc

<!–

  • @Desc:
  • @FilePath: /tutor-babel/docs/md/start.md
  • @Author: liujianwei1
  • @Date: 2021-05-14 16:43:54
  • @LastEditors: liujianwei1
  • @Reference Desc:

–>

理论我的项目中,Babel 须要工程化合作,须要和各种工具 (如 Webpack) 相互配合,因为 Babel 肯定是宏大简单的。
这里先配置一个最简略的 Babel 编译工程,相熟一下整个过程。

源码地址

Demo 代码地址:tutor-basic 传送门

装置

创立 tutor-basic我的项目。装置 npm 包

npm install --save-dev @babel/core @babel/cli @babel/preset-env

配置和编译

step1: 在根目录上面 新建一个 .babelrc 文件(或babel.config.js.babelrc.js)。增加如下内容

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

step2: 在 package.json 文件的 scripts外面增加如下配置

"scripts": {"build": "babel src/index.js --out-file dist/index.js"}

step3: 在新建 lib/index.js文件,并增加如下内容

let number1 = 10
let number2 = 20
const sum = (num1, num2) => num1 + num2

step4: 运行命令

npm run build
#或者
yarn build
#或
npx babel src/index.js --out-file dist/index.js

step5: 查看编译后的后果

"use strict";

var number1 = 10;
var number2 = 20;

var sum = function sum(num1, num2) {return num1 + num2;};

以上展现了一个最简略的 Babel 应用工程,输入后果和 Babel 介绍的例子后果是一样的

其余

  • @babel/core: Babel 实现转换的外围,它能够依据配置 (.babelrc) 中的规定,进行源码的转换, 提供根底的转换能力
  • @babel/cli: Babel 提供的命令行性能,依赖@babel/core, 在终端中通过命令行形式运行,编译文件或目录。
  • @babel/preset-env 容许 去配置 须要反对的 指标环境, 提供 ES6 转换 ES5 的语法转换规则。如果不应用它,也能够实现转换,然而转换之后仍旧是 E66,说白了就是没有转换。
  • .babelrc Babel 配置文件,编译时,默认会寻找以后我的项目根目录上面的配置文件。转换规则都写在这外面。前面会具体介绍
正文完
 0