Loading

♠ Babel的深入解析

Babel的深入解析

为什么需要babel?

事实上,在开发中我们很少直接去接触babel,但是babel对于前端开发来说,目前是不可缺少的一部分:开发中,我们想要使用ES6+的语法,想要使用TypeScript,开发React项目,它们都是离不开Babel的;

Babel是一个工具链,主要用于旧浏览器或者缓解中将ECMAScript 2015+代码转换为向后兼容版本的JavaScript;

包括:语法转换、源代码转换、Polyfill实现目标缓解缺少的功能等;

babel本身可以作为一个独立的工具(和postcss一样),不和webpack等构建工具配置来单独使用。

如果我们希望在命令行尝试使用babel,需要安装如下库:

  • @babel/core:babel的核心代码,必须安装;
  • @babel/cli:可以让我们在命令行使用babel;

使用babel来处理我们的源代码:

  • src:是源文件的目录;
  • --out-dir:指定要输出的文件夹dist;

插件的使用

比如我们需要转换箭头函数,那么我们就可以使用箭头函数转换相关的插件:

npm install @babel/plugin-transform-arrow-functions -D

npx babel src --out-dir dist --plugins=@babel/plugin-transform-arrow-functions

查看转换后的结果:我们会发现 const 并没有转成 var

  • 这是因为 plugin-transform-arrow-functions,并没有提供这样的功能;
  • 我们需要使用 plugin-transform-block-scoping 来完成这样的功能;

npm install @babel/plugin-transform-block-scoping -D

npx babel src --out-dir dist --plugins=@babel/plugin-transform-block-scoping,@babel/plugin-transform-arrow-functions

Babel的预设preset

但是如果要转换的内容过多,一个个设置是比较麻烦的,我们可以使用预设(preset):

npm install @babel/preset-env -D

执行如下命令:

Babel的底层原理

babel是如何做到将我们的一段代码(ES6、TypeScript、React)转成另外一段代码(ES5)的呢?

从一种源代码(原生语言)转换成另一种源代码(目标语言),这是什么的工作呢?就是编译器,事实上我们可以将babel看成就是一个编译器。Babel编译器的作用就是将我们的源代码,转换成浏览器可以直接识别的另外一段源代码;

Babel也拥有编译器的工作流程:

  • 解析阶段(Parsing)
  • 转换阶段(Transformation)
  • 生成阶段(Code Generation

当然,这只是一个简化版的编译器工具流程,在每个阶段又会有自己具体的工作:

babel-loader

在实际开发中,我们通常会在构建工具中通过配置babel来对其进行使用的,比如在webpack中。

npm install babel-loader @babel/core

我们可以设置一个规则,在加载js文件时,使用我们的babel

我们必须指定使用的插件才会生效

如果我们一个个去安装使用插件,那么需要手动来管理大量的babel插件,我们可以直接给webpack提供一个preset,webpack会根据我们的预设来加载对应的插件列表,并且将其传递给babel

比如常见的预设有三个:

  • env
  • react
  • TypeScript

安装preset-env:npm install @babel/preset-env

 

我们最终打包的JavaScript代码,是需要跑在目标浏览器上的,那么如何告知babel我们的目标浏览器呢?

  • rowserslist工具
  • target属性

之前我们项目中已经使用了browserslist工具,我们可以对比一下不同的配置,打包的区别:

我们也可以通过targets来进行配置

那么,如果两个同时配置了,哪一个会生效呢?

配置的targets属性会覆盖browserslist;但是在开发中,更推荐通过browserslist来配置,因为类似于postcss工具,也会使用browserslist,进行统一浏览器的适配;

Stage-X的preset

要了解Stage-X,我们需要先了解一下TC39的组织:

  • TC39是指技术委员会(Technical Committee)第 39 号;
  • 它是 ECMA 的一部分,ECMA 是 “ECMAScript” 规范下的 JavaScript 语言标准化的机构;
  • ECMAScript 规范定义了 JavaScript 如何一步一步的进化、发展;

TC39 遵循的原则是:分阶段加入不同的语言特性,新流程涉及四个不同的 Stage

  • Stage 0:strawman(稻草人),任何尚未提交作为正式提案的讨论、想法变更或者补充都被认为是第 0 阶段的"稻草人";
  • Stage 1:proposal(提议),提案已经被正式化,并期望解决此问题,还需要观察与其他提案的相互影响;
  • Stage 2:draft(草稿),Stage 2 的提案应提供规范初稿、草稿。此时,语言的实现者开始观察 runtime 的具体实现是否合理;
  • Stage 3:candidate(候补),Stage 3 提案是建议的候选提案。在这个高级阶段,规范的编辑人员和评审人员必须在最终规范上签字。Stage 3 的提案不会有太大的改变,在对外发布之前只是修正一些问题;
  • Stage 4:finished(完成),进入 Stage 4 的提案将包含在 ECMAScript 的下一个修订版中

在babel7之前(比如babel6中),我们会经常看到这种设置方式:

它表达的含义是使用对应的 babel-preset-stage-x 预设;但是从babel7开始,已经不建议使用了,建议使用preset-env来设置;

Babel的配置文件

像之前一样,我们可以将babel的配置信息放到一个独立的文件中,babel给我们提供了两种配置文件的编写:

  • babel.config.json(或者.js,.cjs,.mjs)文件;
  • .babelrc.json(或者.babelrc,.js,.cjs,.mjs)文件;

认识polyfill

为什么时候会用到polyfill呢?

  • 比如我们使用了一些语法特性(例如:Promise, Generator, Symbol等以及实例方法例如Array.prototype.includes等)
  • 但是某些浏览器压根不认识这些特性,必然会报错;
  • 我们可以使用polyfill来填充或者说打一个补丁,那么就会包含该特性了;

babel7.4.0之前,可以使用 @babel/polyfill的包,但是该包现在已经不推荐使用了:

babel7.4.0之后,可以通过单独引入core-js和regenerator-runtime来完成polyfill的使用:npm install core-js regenerator-runtime --save

 

posted @ 2022-02-13 23:24  sunflower-js  阅读(98)  评论(0编辑  收藏  举报