Babel
是一个流行的用于将新版本ES6+代码转换为向后兼容版本(ES5)
代码的JavaScript编译器。它还为JSX语法提供了编译
支持,还有一些其他插件可用于转换特定类型的代码。下面是一些关于Babel
的介绍和原理:
Babel的使用
-
安装Babel命令行工具:
npm install -g babel-cli
-
安装Babel的Loader和Preset,这些用于解析和转换代码并生成新的代码:
npm install -g babel-loader @babel/core @babel/preset-env
-
创建一个
.babelrc
文件,在其中指定您要使用哪些转换器和编译选项。例如:
{
"presets": [
"@babel/preset-env"
]
}
- 运行 Babel 编译器:
babel input.js -o output.js
Babel插件
Babel常常使用插件去实现转换操作。请注意,Babel将在插件执行转换之前将代码解析为AST。这使得可以在AST上进行操作转换。以下是一些常用的Babel插件:
-
@babel/plugin-transform-arrow-functions
: 将箭头函数转换为函数表达式以实现向后兼容性。 -
@babel/plugin-proposal-class-properties
: 将ES6中添加的类属性转换为向后兼容版本。 -
@babel/plugin-proposal-object-rest-spread
: 将对象展开操作符转换为ES5代码。
总结
Babel
是一个非常强大的JavaScript
编译器,它可以将新版本的ES6+
代码转换为向后兼容版本(ES5)
代码,以及提供支持JSX语法的编译支持。它使用抽象语法树(AST)
来表示代码,插件通过操作AST
节点实现代码转换。
Babel
是一个JavaScript
编译器,用于将最新的JavaScript
语法转换为向后兼容的版本并处理浏览器兼容性问题。它使用了一种称为抽象语法树(AST
)的数据结构,将源代码转换为一个可操作的表示形式并进行处理。
Babel 的工作原理:三类功能
解析
当 Babel 接收到源代码时,将会调用一个叫做解析器的工具,用于将源代码转换为抽象语法树(AST)。在这个过程中,解析器会识别代码中的语法结构,并将其转换为对应的节点类型。
例如,当解析器遇到一个变量声明语句时,它将会创建一个 “VariableDeclaration” 节点,并将该节点的信息存储在 AST 中。AST 是一个以节点为基础组成的树形结构,每个节点都有相应的类型、属性和子节点等信息。
转换
一旦 AST 被创建,Babel 将遍历整个树形结构,对每个节点进行转换。这些转换可以是插件、预设或手动创建的。转换器会检查 AST 中的每个节点,然后对其进行相应的修改或替换,以将新语法转换为旧语法。
例如,如果 Babel 遇到一个包含箭头函数的节点,而你已经启用了转换插件,该插件将会将箭头函数转换为其等效的体函数。代码转换后,Babel 将会生成一个新的 AST。
生成
最后,Babel 将基于转换后的 AST 生成代码文本。在这个步骤中,Babel 将遍历转换后的 AST,并创建对应的代码字符串,并将这些字符串组合成一个完整的 JavaScript 文件。如果启用了代码压缩,Babel 还可以将生成的代码进行压缩。
总结来说,Babel 的原理就是将 JavaScript 源代码转换为抽象语法树(AST),然后对 AST 进行转换,生成与源代码功能相同但向后兼容的代码。Babel 提供了一个强大的生态系统,使得开发者可以轻松扩展并自定义转换器,实现自己的功能需求。
babel解析过程发生了什么
输入:Babel 接收到待处理的源代码字符串作为输入。
词法分析(Lexical Analysis):在词法分析阶段,Babel 的解析器将源代码字符串分解成一个个称为 “令牌”(Tokens) 的单位。令牌代表源代码中的基本元素,如标识符、关键字、运算符等。词法分析器(Lexer)根据一系列的词法规则来识别和生成令牌。
例如,对于源代码中的语句 const x = 10;,词法分析器会依次生成令牌 “const”、“x”、“=”、“10” 和 “;”。
语法分析(Parsing):在语法分析阶段,Babel 使用解析器(Parser)以及词法分析得到的令牌序列构建抽象语法树(AST)。解析器根据语法规则和文法定义来识别语法结构,并将其表示为节点。
例如,对于语句 const x = 10;,解析器会创建一个 “VariableDeclaration” 节点,并将其子节点设置为一个 “Identifier” 节点(表示变量名 “x”)和一个 “NumericLiteral” 节点(表示数值 “10”)。
AST 构建:在这一阶段,Babel 将解析器生成的节点组合成一个抽象语法树(AST)。AST 是一个以节点为基础组成的树形结构,其中树的每个节点都包含有关语法结构的信息。
语义分析(Semantic Analysis):在语义分析阶段,Babel 分析 AST 中的节点,确定其语义和上下文信息。这个过程可能涉及到变量引用、作用域和类型等语义相关的问题。
输出:最后,Babel 将根据 AST 生成转换后的代码文本,可以是源代码的等效形式(例如,将最新的 JavaScript 语法转换为旧版本的语法),也可以是其他需要的格式。
命令行使用
@babel/core
:babel的核心代码,必须安装;@babel/cli
:可以让我们在命令行使用babel;yarn add @babel/cli @babel/core
npx babel src --out-dir dist
- 预设
yarn add @babel/preset-env -D
npx babel src --out-dir dist --presets = @babel/preset-env
- 单独处理箭头函数
yarn add @babel/plugin-transform-arrow-functions
- 针对单个文件,对应命令行输入:
npx babel index.js --out-file dist.js --plugins=@babel/plugin-transform-arrow-functions
- 针对文件夹,对应命令行输入:
npx babel src --out-dir dist --plugins=@babel/plugin-transform-arrow-functions
- 针对单个文件,对应命令行输入:
- 单独处理
let
转换为var
yarn add @babel/plugin-transform-block-scoping
npx babel src --out-dir dist --plugins = @babel/plugin-transform-block-scoping,@babel/plugin-transform-arrow-functions
webpack中使用babel
设置目标浏览器
- 为了让postcss使用同一套设置,于是就统一设置在
.browserslistrc
- 优先级:
@babel/preset-env
里的targets
package.json
里的browserslist
字段.browserslistrc
配置文件
- 下面是设置在预设内:
多预设
预设preset的stage-x
-
要了解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)文件;- 它们两个有什么区别呢?目前很多的项目都采用了多包管理的方式(babel本身、element-plus、umi等);
.babelrc.json
:早期使用较多的配置方式,但是对于配置Monorepos项目是比较麻烦的;babel.config.json
(babel7):可以直接作用于Monorepos项目的子包,更加推荐;Monorepos
和Multirepos
项目架构
认识polyfill
-
babel7.4.0
之前,可以使用@babel/polyfill
的包,但是该包现在已经不推荐使用了 -
babel7.4.0
之后,yarn add core-js regenerator-runtime
-
在
babel.config.js
内配置useBuiltIns:false
,不使用polyfill,且不需要设置corejs;useBuiltIns:"usage"
,哪里用到了,那么就在哪里引入,需要设置corejs版本。useBuiltIns:"entry"
,如果依赖某个库已经使用了自己的polyfill特性,如果我们使用usage
就会报错,用entry
就解决了问题,使用entry
需要在入口文件中添加import 'core-js/stable'; import 'regenerator-runtime/runtime
,这样会根据 browserslist 目标导入所有的polyfill,但是对应的包也会变大;
-
禁止掉
exclude:/node_modules/
,否则会和包文件内的polyfill冲突
@babel/plugin-transform-runtime
-
在前面我们使用的polyfill,默认情况是添加的所有特性都是全局的
-
如果我们正在编写一个工具库,这个工具库需要使用polyfill;
-
别人在使用我们工具时,工具库通过polyfill添加的特性,可能会污染它们的代码;
-
所以,当编写工具时,
yarn add @babel/plugin-transform-runtime
-
使用plugins来配置
babel.config.js:
-
配置插件了,就需要把预设的额外配置给注释掉
-
注意:因为我们使用了corejs3,所以我们需要安装对应的库:
-
安装对应的库
yarn add @babel/runtime-corejs3
React的jsx支持
- 在我们编写react代码时,react使用的语法是jsx,jsx是可以直接使用babel来转换的。
- 对react jsx代码进行处理需要如下的插件:
yarn add @babel/plugin-syntax-jsx
yarn add @babel/plugin-transform-react-jsx
yarn add @babel/plugin-transform-react-display-name
- 但是开发中,我们并不需要一个个去安装这些插件,我们依然可以使用preset来配置
yarn add @babel/preset-react
- 修改
babel.config.js
预设配置 - 在代码中使用到的包
yarn add react react-dom
zanlan.config.js
index.js
- 打包后的
index.html
,添加 - 打开预览
TypeScript的编译
- 在项目开发中,我们会使用TypeScript来开发,那么TypeScript代码是需要转换成JavaScript代码。
- 可以通过TypeScript的compiler来转换成JavaScript:
yarn add typescript
- 另外TypeScript的编译配置信息我们通常会编写一个tsconfig.json文件:
tsc --init
- 生成配置文件如下:
- 之后我们可以运行 npx tsc来编译自己的ts代码:
npx tsc
使用ts-loader处理ts文件
- 如果我们希望在webpack中使用TypeScript,那么我们可以使用ts-loader来处理ts文件:
yarn add ts-loader
,默认会安装typescript的了,所以我们自己没有安装typescript,也可以使用ts-loader
- 配置ts-loader:
- 之后,我们通过npm run build打包即可。
使用babel-loader来处理ts代码
- 除了可以使用TypeScript Compiler来编译TypeScript之外,我们也可以使用Babel:
- Babel是有对TypeScript进行支持;
- 我们可以使用插件:
@babel/tranform-typescript;
- 但是更推荐使用preset:
@babel/preset-typescript;
- 我们来安装@babel/preset-typescript:
yarn add @babel/preset-typescript
ts-loader和babel-loader选择
- 那么我们在开发中应该选择ts-loader还是babel-loader呢?
- 使用ts-loader(TypeScript Compiler)
-
来直接编译TypeScript,那么只能将ts转换成js,可以检测代码;
-
如果我们还希望在这个过程中添加对应的polyfill,那么ts-loader是无能为力的;
-
我们需要借助于babel来完成polyfill的填充功能;
-
- 使用babel-loader(Babel)
- 来直接编译TypeScript,也可以将ts转换成js,并且可以实现polyfill的功能;
- 但是babel-loader在编译的过程中,
不会对类型错误进行检测
;即使在代码中有类型错误,照样可以打包成功
- 那么在开发中,我们如何可以同时保证两个情况都没有问题呢?
编译TypeScript最佳实践
- 事实上TypeScript官方文档有对其进行说明:
- 也就是说我们使用Babel来完成代码的转换,使用tsc来进行类型的检查
- 但是,如何可以使用tsc来进行类型的检查呢?
- 我们执行
npm run type-check
可以对ts代码的类型进行检测; - 我们执行
npm run type-check-watch
可以实时的检测类型错误; - 我们执行
npm run build2
,只有tsc --noEmit
不报错时候,才会执行第二命令
- 我们执行
babel原理
Babel 是一个 JavaScript 编译器。他把最新版的 javascript 编译成当下可以执行的版本,简言之,利用 babel 就可以让我们在当前的项目中随意的使用这些新最新的 es6,甚至 es7 的语法
ES6、7
代码输入 ->babylon
进行解析 -> 得到AST
(抽象语法树)->plugin
用babel-traverse
对AST
树进行遍历转译 ->得到新的AST
树->用babel-generator
通过AST
树生成ES5
代码
它的工作流程包括解析(parse)、转换(transform)和生成(generate)三个主要步骤
- 解析(parse) :Babel 使用解析器(如
Babylon
)将输入的 JavaScript 代码解析成抽象语法树(AST)。解析器将代码分析成语法结构,并生成对应的 AST,表示代码的抽象语法结构。这个阶段包括词法分析和语法分析。词法分析将源代码转换为一个个标记(tokens)的流,而语法分析则将这个标记流转换为 AST 的形式。 - 转换(transform) :在转换阶段,Babel 使用插件(plugins)对 AST 进行遍历和转换。插件可以对 AST 进行增删改查的操作,可以根据需求对语法进行转换、代码优化等。Babel 的插件系统非常灵活,可以根据需要自定义插件或使用现有插件来进行代码转换。
- 生成(generate) :在生成阶段,Babel 使用生成器(如
babel-generator
)将经过转换的 AST 转换回字符串形式的 JavaScript 代码。生成器会深度优先遍历 AST,并根据 AST 的节点类型生成对应的代码字符串,最终将代码字符串输出。
通过以上三个步骤,Babel 实现了将最新版本的 JavaScript 代码转换为向后兼容的代码,使得开发者可以在当前环境中使用较新的 JavaScript 特性和语法。同时,Babel 还提供了一些常用的插件和预设(presets),以便开发者快速配置和使用常见的转换规则,如转换 ES6、ES7 语法、处理模块化、转换 JSX 等。
总的来说,Babel 的原理是通过解析、转换和生成的过程,将新版本的 JavaScript 代码转换为兼容旧环境的代码,使开发者能够在当前环境中使用较新的 JavaScript 特性和语法。
babel编译器原理
-
babel编译器原理:
-
代码结构
-
tokens.js
-
old_ast.json
-
new_ast.json
官方babel原理
- node自带的包assert,
const assert = require('assert');
assert.deepStrictEqual({ a: 1 }, { a: '1' });
- 只有两个对象,有一个子节点不一样,就报错,否则,不作出反应,代表就是值结构一样对象