babel基础知识

450 阅读5分钟

(1)什么是babel?

babel是一个js工具包,用于向后兼容,常用于新版本,即新版本仍然可以使用老版本代码.
例如在使用jsx时,将jsx转换成虚拟DOM描述对象就需要用到babel babel的主要作用:1.源码转换。2.转换语法 例如代码转换(通过将新版本代码编译成老版本实现向下兼容):

// Babel 输入:ES2015 箭头函数 
[1, 2, 3].map(n => n + 1); 
// Babel 输出:ES5 等价语法 
[1, 2, 3].map(function(n) { return n + 1; });

我们使用 @babel/cli 从终端运行 Babel,@babel/polyfill 用于 polyfill 所有新的 JavaScript 功能,env preset 只包含我们使用的功能的转换规则,polyfills 用于填充目标浏览器中缺少的功能。

(2)babel/core和@babel/cli

@babel/core我们在很多地方都看到,它是Babel进行转码的核心依赖包,我们常用的babel-cli和babel-node都依赖于它

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

可以发现原来的es6箭头函数在结果中几乎原封不动的返回出来了;Babel的运行方式总共可以分为三个阶段:解析(parsing)、转换(transforming)和生成(generating);负责解析阶段的插件是@babel/parser,其作用就是将源码解析成AST;而负责生成阶段的插件是@babel/generator,其作用就是将转好好的AST重新生成代码。

而@babel/core本身不具备转换处理的功能,它把转换的功能拆分到一个个插件(plugins)中;因此当我们不添加任何插件的时候,输入输出代码是相同的。

在@babel/core转换时还有几个副产物:code、ast和map

@babel/cli是Babel自带了一个内置的CLI命令行工具,我们就可以通过命令行来编译文件;它有两种调用方式,可以通过全局安装或者本地安装调用,选用一种即可,推荐在项目本地安装。

v2-cf38dcb85a3314984dee99210149413f_720w.jpg

我们虽然可以在命令行中配置各种插件(plugins)或者预设(presets,也就是一组插件),但是这样并不利于后期的查看或者维护,而且大多时候babel都是结合webpack或者gulp等打包工具开发,不会直接通过命令行的方式;因此Babel推荐通过配置文件的方式来进行管理。

Babel的配置文件主要有.babelrc.babelrc.jsbabel.config.jspackage.json,他们的配置选项都是相同的,作用也是一样,主要区别在于格式语法的不同,因此我们在项目中只需要选择其中一种即可。

对于.babelrc,它的配置主要是JSON格式的,像这样:

{
  "presets": [...],
  "plugins": [...]
}

但有时候我们需要对插件和预设设置参数,就不能直接使用字符串的形式了;而应再包裹一层数组,数组的第一项是名称,第二项是设置的参数对象:

//.babelrc
{
  "plugins": [
    [
      "@babel/plugin-transform-arrow-functions", 
      { "spec": true }
    ]
  ]
}

(3)babel预设和插件的区别:

Babel官网提供了近一百个插件,但是如果我们的代码中一个一个的配置插件就需要对每一个插件有所了解,这样必然会耗费大量的时间精力;为此,Babel提供了预设(presets)的概念,意思就是预先设置好的一系列插件包;这就相当于肯德基中的套餐,将众多产品进行搭配组合,适合不同的人群需要;总有一款适合我们的套餐。

Babel官方的preset,我们实际可能会用到的其实就只有4个:

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

@babel/preset-env是一个智能预设,可让您使用最新的JavaScript,而无需微观管理目标环境所需的语法转换(以及可选的浏览器polyfill)。这都使您的生活更轻松,JavaScript包更小!

@babel/preset-env更关注适配浏览器,如果指定适配最新的chrome浏览器,只需修改配置为

{
  "presets": [
    [
      "@babel/env",
      {
        "targets": "last 2 Chrome versions"
      }
    ]
  ]
}

转换后的代码只会适配chrome最新的两个版本,也就是不会对class,箭头函数等做转换。

(4)执行顺序:

插件和预设都是通过数组的形式在配置文件中配置,如果插件和预设都要处理同一个代码片段,那么会根据一下执行规则来判定:

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

(5) @babel/polyfill

虽然@babel/preset-env可以转换大多高版本的JS语法,但是一些ES6原型链上的函数(比如数组实例上的的filter、fill、find等函数)以及新增的内置对象(比如Promise、Proxy等对象),是低版本浏览器本身内核就不支持,因此@babel/preset-env面对他们时也无能为力。

比如我们常用的filter函数,在IE浏览器上就会出现兼容性问题,因此我们通过polyfill(垫片)的方式来解决.polyfill可以在入口文件处用import引入也可以在webpack文件中配置。但是这个包下载很少引用了,因为他会加载所有的功能,会造成全局污染。

因此从Babel7.4开始@babel/polyfill就不推荐使用了,而是直接引入core-js与regenerator-runtime两个包;而@babel/polyfill本身也是这两个包的集合;在上面webpack打包出来的dist文件我们也可以看到,引用的也是这两个包。那core-js到底是什么呢?

它是JavaScript标准库的polyfill 它尽可能的进行模块化,让你能选择你需要的功能 它和babel高度集成,可以对core-js的引入进行最大程度的优化 目前我们使用的默认都是core-js@2,但它已经封锁了分支,在此之后的特性都只会添加到core-js@3,因此也是推荐使用最新的core-js@3。

  "presets": [
    [
      "@babel/preset-env",
      {
        "useBuiltIns": "usage",
        "corejs": 3
      }
    ]
  ]
}

此时他会按需引入。