Babel7学习总结

640 阅读4分钟

Babel

Babel 是将 ES2015+ 的代码转换成兼容 ES2015(ES6) 的编译器。在编译过程解析-转译-输出中间,依靠众多的 plugin 支撑,提供对ES2015+语法的解析,以及支持新特性的的 polyfill 的插入,最终生成兼容 ES2015(ES6)的代码。

Babel 底层支持

  • @babel/core 提供编译过程的基本支持

  • @babel/cli 提供编译命令行的支持

@babel/preset-env

相比于列举一个个插件,babel 提供了方便的preset集合引入的方式,@babel/preset-env 可以根据配置可以动态的引入对应的插件集合(语法解析,polyfill特性支持)。对于JS语法的支持,@babel/preset-env基本上形成了大一统的形式。

  • 主要根据以下配置动态引入相应的插件集合如下:
    • targets:描述支持的浏览器环境
    • useBuiltIns:这个属性决定是否引入 polyfill
    • corejs:表示引入哪个版本的 core-js

其它集合

  • @babel/preset-react:提供对react jsx 语法支持
  • @babel/preset-typescript:提供对typescript语法支持,但不会做类型检查
  • @babel/preset-flow

Polyfill 详解

插件/库说明
core-js所有 polyfill 方案都需要依赖于它, 现在有1, 2, 3版本
regenerator-runtime提供 generator, async/awaitpollyfill 是对core-js的补充
@babel/runtime提供模块化的 helper 方法
@babel/polyfill包含 core-jsregenerator runtime ,已被废弃。存在缺陷:1, 会打包所有polyfill, 2.会污染全局变量
@babel/preset-env能根据设置加载对应的polyfill 插件,并已内联的方式插入helper以及polyfill代码,不会污染全局变量,但会造成代码冗余。对应当年的ES标准。不会提供stage-0~3polyfill
@babel/plugin-transform-runtime将内联的方式插入helper以及polyfill代码转为require引用,减少代码冗余。同样不会污染全局变量

综上所述: @babel/preset-env解决了polyfill的动态引入,@babel/plugin-transform-runtime 减少了内联插入的代码冗余。两者结合解决了polyfill 的引入问题。

Node 支持

  • @babel/node 支持 NodeREPL 环境的所有功能,而且可以直接运行 ES6 代码。

废弃的插件以及 stage阶段的语法支持

  • 废弃babel-preset-es20** 年份插件

  • 废弃babel-preset-stage-* proposal stage 插件

    • 要使用stage-0, 1, 2, 3的语法直接引入对应的插件@babel/plugin-proposal-*
  • 使用 npx babel-upgrade 检查与升级

配置文件

配置文件优先级

  • babel.config.json < .babelrc < programmatic options from @babel/cli or babel-loader
  • 同目录下,若两种类型的配置文件都存在,则.babelrc文件会合并覆盖babel.config.json文件。
  • 项目文件配置:
    • babel.config.json
    • 能够作用于node_modules, symbollink
  • 相对文件配置
    • .babelrc.json
    • package.json 中的babel 配置,等同于.babelrc.json

执行顺序

  • pluginspresets先执行
  • plugins 的执行顺序是从左到右
  • presets 的执行顺序是从右到左

合并规则

  1. 基本上之用直接覆盖Object.assign()合并,以下3中情况特殊
  2. parserOpts对象的属性使用Object.assign()合并
  3. generatorOpts对象的属性使用Object.assign()合并
  4. pluginspresets 使用的是合并concat数组,并去除同名的前置插件设置。

查找

Babel7开始,Babel具有“根”目录的概念,默认为当前工作目录。以下为主要的配置查找相关的配置选项,有些可以由配置文件提供,有些则是由程序化选项(programmatic options),还有一些是在脚本执行的过程中动态生成。为被解析的代码提供查找配置的依据。

Options说明仅程序化选项(programmatic options)默认值
cwd程序化选项中所有路径的相对工作目录process.cwd()
filename当前正在编译的代码对应的文件名(如果有)。文件名未知时并非所有babel的功能都可用(如:babelrc选项),因为选项的子集依赖于文件名来实现其功能。是(应该是由解析过程生成)正在编译的代码对应的文件名
root默认的项目文件目录地址,受rootMode影响。
使用场景:
1. 查找默认的configFile值时的基本目录path.resolve(opts.root, "babel.config.json")
2. 作为:babelrcRoots 的默认值
opts.cwd
rootMode决定opts.root取值的模式

选项(upward upward-optional 现在最终会冒泡查找到系统的根目录,使用时要谨慎)
- root: 取opts.root做根目录
- upward: opts.root目录向外查找含有babel.config.json的目录作为根目录,找不到则报错
- upward-optional: opts.root目录向外查找含有babel.config.json的目录作为根目录,找不到则取opts.root做根目录

应用:
适用于当在monorepos子项目中执行脚本时,向外部查找全局的公共babel配置。(因为默认情况下babel会在出现package.json 的目录停止向上检索配置文件)
root
configFile显式指定项目配置文件path.resolve(opts.root, "babel.config.json"),找不到该文件则为false
babelrc决定是否要加载相对文件配置,并作用于当前正在编译的代码。为true 时会向上查找相对于当前filename路径的相对文件配置,遇到package.json 停止。如果找到的配置不在项目文件配置 babelrcRoots中,则会被忽略opts.filename选项有值时,为true
babelrcRoots指定哪些目录下的相对文件配置有效opts.root

在查找配置的过程中,babel主要做如下工作

  • 确定项目的根opts.root
  • 确定configFile文件, 根据opts.root或显式指定。此文件为项目配置文件,能够作用于项目目录中的文件,以及node_modules, symbollink
  • 根据filename决定是否要查找相对文件配置,根据babelrcRoots 决定是否要忽略该相对文件配置
  • 合并.babelrc.jsonbabel.config.json 作为当前编译代码的最终配置
  • 无论是 项目配置文件 还是 相对配置文件 往上搜索配置的过程中,如果在某一层找到了package.json文件,就会停止搜索。

monorepos应用

每个package 可以设置自己的.babelrc.json,并在 项目配置文件中设置babelrcRoots

babelrcRoots: [
  // 表示不要忽略根目录下的.babelrc.json
  ".",

	// 表示不要忽略 monorepos 子目录中的.babelrc.json
  "./packages/*"
]

每个package 可以设置自己的.babelrc.json,并设置rootMode

rootMode: "upward" // 或 "upward-optional"