关于Babel,包你入门

一、 关于Babel

Babel 是一个JavaScript编译器

Babel 主要用于将采用 ECMAScript 2015+ 语法编写的代码转换为向后兼容的 JavaScript 语法,以便能够运行在当前和旧版本的浏览器或其他环境中。

babel 有3种使用方式: 命令行(cli);构建工具的插件 (webpack 的 @babel/loader);单体文件 (standalone script)

3种使用方式只是入口不同,其核心都相同, 即包括3个步骤:

babel 总共分为3个阶段:解析,转换,生成。

  • 解析阶段: @babel/parser 将源码解析成AST
  • 转换阶段: @babel/core本身不具有任何转化功能,它把转化的功能都分解到一个个 plugin 里面
  • 生成阶段:@babel/generator将转好的AST重新生成代码

使用babel工具可以在3处配置: .babelrc/.babelrc.js 、package.json 的 babel 、babel.config.js

常说的 plugins & presets 的配置 就是 使用babel时主要的配置参数,如下:
cli工具中的参数.png

另外需要注意的是: babel 转换只能处理语法,不能处理新增的API。对于API的处理需要使用polyfill。

二、Plugins

babel 本身不具有任何转化功能,它把转化的功能都分解到一个个 plugin 里面。因此当我们不配置任何插件时,经过 babel 的代码和输入是相同的:

没有安装plugin时使用babel编译.png

一个插件一般支持一个语法的转化(插件是小型的 JavaScript 程序), 如添加插件@babel/plugin-transform-arrow-functions, 然后使用@babel/cli 编译:

npm install --save-dev @babel/plugin-transform-arrow-functions
npx babel src --out-dir dir --plugins=@babel/plugin-transform-arrow-functions
安装插件后的编译.png

一个插件支持一个语法。对于一套规范(比如 es2015 )包含大概十几二十个转译插件。如果每次要开发者一个个添加并安装,配置文件很长不说,npm install 的时间也会很长,更不谈我们可能还要同时使用其他规范。 所以 就有了插件套餐preset。

各规范下的插件列表: https://www.babeljs.cn/docs/plugins-list

三、Presets

安装@babel/preset-env, 使用@babel/cli 编译:

npm install --save-dev @babel/preset-env
npx babel src --out-dir dir --presets=@babel/env
presets进行编译.png

官方提供的Presets包:

  • @babel/preset-env for compiling ES2015+ syntax
  • @babel/preset-typescript for TypeScript
  • @babel/preset-react for React
  • @babel/preset-flow for Flow

其中最重要的需要关注的是 @babel/preset-env

四、Polyfill

babel 默认只转换 js 语法,而不转换新的 API; 对于新API 需使用Polyfill
用法1: 在所有代码运行之前增加 require(‘babel-polyfill’)
用法2: webpack.config.js 中将 @babel/polyfill 作为第一个 entry
注意:必须把 @babel/polyfill 作为 dependencies 而不是 devDependencies

使用@babel/polyfill 存在的问题:
1、@babel/polyfill 会导致打出来的包非常大,因为@babel/polyfill 是一个整体,把所有方法都加到原型链上。这个问题可以通过单独使用 core-js 的某个类库来解决,core-js 都是分开的。
2、@babel/polyfill 会污染全局变量,给很多类的原型链上都作了修改

babel7 后推荐使用 core-js/stable 和 regenerator-runtime/runtime

image.png

或者使用@babel/preset-env 中的useBuiltIns 配置

五、最重要的Preset @babel/preset-env

preset-env配置:

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "modules": false,
        "useBuiltIns": "usage",
        "corejs": 3
      }
    ]
  ]
}
  • module:用来设置是否把ES6的模块化语法改成其它模块化语法,默认为 auto,也就是会将ESM转为CJS。项目配置设置module为false也就是仍使用ESM,这样在webpack打包时可以使用 tree-shaking 去除无用代码减小包体积。

  • useBuiltIns:该配置项的值有 entry、usage、false。该配置主要和polyfill的行为相关。

  1. 值为false。preset-env不做额外处理,需要在入口文件引入 @babel/polyfill(全量)

  2. 值为entry。在入口文件引入 @babel/polyfill,转码时会根据 browerlist 引入polyfill。
    image.png

    由于 @babel/polyfill 推荐使用 core-js/stable 和 regenerator-runtime/runtime 替换,所以会有提示。替换为core-js后 如下:
    替换为core-js.png
  3. 值为usage。不用再显示引入 polyfill文件,转码时会根据 browerlist 和 编写的代码按需引入polyfill。


    image.png

    使用usage 时,不需要再引入 @babel/polyfill or core-js。 如下:
    直接使用usage.png

六、其他重要的包

  • @babel/cli: 命令行中使用, 如上面的使用方式

  • @babel/node : 命令行中直接执行+转译node文件,@babel/node = @babel/register + @babel/polyfill。 即 可以直接 @babel/node xxx.js, 如图所示:
    i@babel/node.png
  • @babel/register : 用法: require("@babel/register"); node 后续运行时所需要 require 进来的扩展名为 .es6、.es、.jsx、 .mjs 和 .js 的文件将由 Babel 自动转换。实时转码,所以 只适合在开发环境使用。

  • @babel/runtime
    语法转换时, 创建了helper函数。而在实际项目中我们的js文件很多,在语法转换过程中每个文件都会创建很多这种helper函数,这样会导致最终生成的包体积十分臃肿。


    image.png

这个时候 @babel/runtime 上场了,涉及到语法转换的helper函数都打包到 @babel/runtime 中,所以在语法转换的时候不用重复创建,只要引入 @babel/runtime 内的模块就可以了。

但是打包的文件那么多,总不可能每个都手动修改吧。 这时候就需要@babel/plugin-transform-runtime 了。

运行环境使用, 放在 dependencies中 而不是devDe..

  • @babel/plugin-transform-runtime
    @babel/plugin-transform-runtime 这个包的作用就是移除语法转换生成的helper函数,然后使用 @babel/runtime 中的辅助函数来替换。这样就避免了我们手动替换也减小了包的体积。


    image.png
  • @babel/loader
    与webpack等构建工具交互,可在webpack中配置,优先级最高

  • @babel/parser
    原babel 解析语法的内核 babylon

  • @babel/core
    babel 核心功能, 执行下面代码:

var babelCore = require("@babel/core");
var sourceCode = `let fn = (num) => num + 2`;

var options = {
  //是否生成解析的代码
  code: true,
  //是否生成抽象语法树
  ast: true,
  //是否生成sourceMap
  sourceMaps: true,
  plugins: [],
  presets: [],
};

babelCore.transform(sourceCode, options, function (err, result) {
  console.log(sourceCode);
  console.log(result.code);
  console.log(result.map);
  console.log(result.ast);
});

结果:
image.png

七、思维导图

我将上面的思路整理成了思维导图,方便记忆。 自行取用。


Babel.jpg

参考文档:

1、 一口(很长的)气了解 babel
2、一文彻底读懂Babel

hi~~ 学废了吗~

你可能感兴趣的:(关于Babel,包你入门)