<Babel> 前端语言的巴别塔

2024-01-12 22:30

本文主要是介绍<Babel> 前端语言的巴别塔,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在这里插入图片描述

Babel中文站点:https://www.babeljs.cn/
Babel外文站点:https://babeljs.io/

什么是Babel

Babel取自人类语言最早的传说,Tower of Babel。
上帝摧毁了巴别塔上说着共同语言的我们,又被Babel重新带了回来。
如果说巴别塔是人们对混乱到秩序的向往,那Babel在前端领域就带给了工程师放飞语法的所有畅想。

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

以上是官网对于Babel的解释,究其起源是由于前端的宿主容器无法实时的迎合各种语法进化而导致的兼容性问题,当我们无法改变如浏览器的宿主容器的时,Babel可以为我们提供以下服务:

  • 语法转换
  • 通过 Polyfill 方式在目标环境中添加缺失的功能
  • 源码转换(codemods)

Babel提供的服务:

语法转换

一般代指高级语言特性的降级

Polyfill

也叫垫片、补丁(通过引入第三方 polyfill 模块,例如 core-js)

源码转换

JSX等

Babel工程化的概念:

  • 可插拔(Pluggable)
    这就要求Babel需要有一套灵活的插件机制,满足第三方开发的入驻和使用场景。
  • 可调式(Debuggable)
    在Babel编译过程中,需要提供一套Source Map,来帮助使用Babel的开发找到编译前后的映射关系,从而方便前端开发中的调试。
  • 基于协定(Compact)
    需要实现灵活的配置方式,比如你熟悉的 Babelloose 模式,Babel 提供 loose 选项,帮助开发者在“尽量还原规范”和“更小的编译产出体积”之间,找到平衡。

总结

Babel的核心目标:编译

在这里插入图片描述

自身实现基于编译原理,深入AST(抽象语法树)来生成目标代码。同时,Babel 需要工程化协作,需要和各种工具(如 Webpack)相互配合,因此 Babel 一定是庞大复杂的。

Babel Monorepo架构体系

@babel/core

@babel/core 是 Babel 实现转换的核心

它可以根据配置,进行源码的编译转换:

var babel = require("@babel/core");babel.transform(code, options, function(err, result) {result; // => { code, map, ast }
});

@babel/cli

@babel/cli 是 Babel 提供的命令行,它可以在终端中通过命令行方式运行,编译文件或目录。
我们简单说一下它的实现原理:
@babel/cli 使用了 commander 库搭建基本的命令行开发。

以编译文件为例,其关键部分源码如下:

import * as util from "./util";
const results = await Promise.all(_filenames.map(async function (filename: string): Promise<Object> {let sourceFilename = filename;if (cliOptions.outFile) {sourceFilename = path.relative(path.dirname(cliOptions.outFile),sourceFilename,);}// 获取文件名sourceFilename = slash(sourceFilename);try {return await util.compile(filename, {...babelOptions,sourceFileName: sourceFilename,// 获取 sourceMaps 配置项sourceMaps:babelOptions.sourceMaps === "inline"? true: babelOptions.sourceMaps,});} catch (err) {if (!cliOptions.watch) {throw err;}console.error(err);return null;}}),
);

util.compile

在上述代码中,@babel/cli 使用了util.compile方法执行关键的编译操作,该方法定义在 babel-cli/src/babel/util.js

babel-cli/src/babel/util.js代码解析:

import * as babel from "@babel/core";
// 核心编译方法
export function compile(filename: string,opts: Object | Function,
): Promise<Object> {// 编译配置opts = {...opts,caller: CALLER,};return new Promise((resolve, reject) => {// 调用 transformFile 方法执行编译过程babel.transformFile(filename, opts, (err, result) => {if (err) reject(err);else resolve(result);});});
}

由此可见,@babel/cli 负责获取配置内容,并最终依赖了 @babel/core 完成编译。

也可以在 @babel/cli 的 package.json 中找到线索:

"peerDependencies": {"@babel/core": "^7.0.0-0"
},

@babel/core 是 @babel/cli 的关键依赖,@babel/core 提供了基础的编译能力。

@babel/standalone

可以在非 Node.js 环境(比如浏览器环境)自动编译含有 text/babel 或 text/jsx 的 type 值的 script标签,并进行编译

如下面代码:

<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel">const getMessage = () => "Hello World";document.getElementById('output').innerHTML = getMessage();
</script>

@babel/standalone的核心代码与@babel/core的关系:

import {transformFromAst as babelTransformFromAst,transform as babelTransform,buildExternalHelpers as babelBuildExternalHelpers,
} from "@babel/core";

所以,@babel/standalone也是基于@babel/core而产生的应用。@babel/standalone可以在浏览器中直接执行,因此这个包对于浏览器环境动态插入高级语言特性的脚本、在线自动解析编译非常有意义。我们知道的 Babel官网也用到了这个包,JSFiddle、JS Bin 也都是 @babel/standalone 的受益者。

以上介绍的@babel/standalone、@babel/cli可以说都是基于@babel/core的能力而衍生的应用,那@babel/core又基于哪些babel基础包搭建的核心能力呢?

@babel/core的组成

  • @babel/parser
  • @babel/code-frame
  • @babel/generator
  • @babel/traverse
  • @babel/types
  • …(等包提供基础的AST处理能力)

@babel/parser

@babel/parser 的实现主要依赖并参考了 acorn 和 acorn-jsx

典型用例:

require("@babel/parser").parse("code", {sourceType: "module",plugins: ["jsx","flow"]
});

parse源码分析:

export function parse(input: string, options?: Options): File {if (options?.sourceType === "unambiguous") {options = {...options,};try {options.sourceType = "module";// 获取相应的编译器const parser = getParser(options, input);// 使用编译器将源代码转为 astconst ast = parser.parse();if (parser.sawUnambiguousESM) {return ast;}if (parser.ambiguousScriptDifferentAst) {try {options.sourceType = "script";return getParser(options, input).parse();} catch {}} else {ast.program.sourceType = "script";}return ast;} catch (moduleError) {try {options.sourceType = "script";return getParser(options, input).parse();} catch {}throw moduleError;}} else {return getParser(options, input).parse();}
}

所以说,require(“@babel/parser”).parse()方法可以返回一个针对源码编译得到的 AST,但是这里的AST仍然需要经过我们的修改,才能产生编译后的代码。如何对AST进行二次修改和聚合,@babel/traverse、@babel/types、@babel/generator带给了我们这些。

@babel/traverse、@babel/types

提供了对具体的AST节点的修改能力。

traverse(ast, {enter(path) {if (path.isIdentifier({ name: "n" })) {path.node.name = "x";}}
});

@babel/generator

对新的 AST 进行聚合并生成 js 代码

const output = generate(ast,{/* options */},code
);

Babel整体编译底层流程 手绘

在这里插入图片描述

  1. @babel/core利用自身能力将source code解析成AST
  2. @babel/traverse、@babel/types利用自身能力将旧AST转换为新AST
  3. @babel/generator利用自身能力将新AST生成output code

在这里插入图片描述

这篇关于<Babel> 前端语言的巴别塔的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/599360

相关文章

SpringBoot返回文件让前端下载的几种方式

《SpringBoot返回文件让前端下载的几种方式》文章介绍了开发中文件下载的两种常见解决方案,并详细描述了通过后端进行下载的原理和步骤,包括一次性读取到内存和分块写入响应输出流两种方法,此外,还提供... 目录01 背景02 一次性读取到内存,通过响应输出流输出到前端02 将文件流通过循环写入到响应输出流

C语言逗号运算符和逗号表达式的使用小结

《C语言逗号运算符和逗号表达式的使用小结》本文详细介绍了C语言中的逗号运算符和逗号表达式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习... 在C语言中逗号“,”也是一种运算符,称为逗号运算符。 其功能是把两个表达式连接其一般形式为:表达

Go语言实现桥接模式

《Go语言实现桥接模式》桥接模式是一种结构型设计模式,它将抽象部分与实现部分分离,使它们可以独立地变化,本文就来介绍一下了Go语言实现桥接模式,感兴趣的可以了解一下... 目录简介核心概念为什么使用桥接模式?应用场景案例分析步骤一:定义实现接口步骤二:创建具体实现类步骤三:定义抽象类步骤四:创建扩展抽象类步

GO语言实现串口简单通讯

《GO语言实现串口简单通讯》本文分享了使用Go语言进行串口通讯的实践过程,详细介绍了串口配置、数据发送与接收的代码实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要... 目录背景串口通讯代码代码块分解解析完整代码运行结果背景最近再学习 go 语言,在某宝用5块钱买了个

SpringBoot+Vue3整合SSE实现实时消息推送功能

《SpringBoot+Vue3整合SSE实现实时消息推送功能》在日常开发中,我们经常需要实现实时消息推送的功能,这篇文章将基于SpringBoot和Vue3来简单实现一个入门级的例子,下面小编就和大... 目录前言先大概介绍下SSE后端实现(SpringBoot)前端实现(vue3)1. 数据类型定义2.

前端Visual Studio Code安装配置教程之下载、汉化、常用组件及基本操作

《前端VisualStudioCode安装配置教程之下载、汉化、常用组件及基本操作》VisualStudioCode是微软推出的一个强大的代码编辑器,功能强大,操作简单便捷,还有着良好的用户界面,... 目录一、Visual Studio Code下载二、汉化三、常用组件1、Auto Rename Tag2

GO语言zap日志库理解和使用方法示例

《GO语言zap日志库理解和使用方法示例》Zap是一个高性能、结构化日志库,专为Go语言设计,它由Uber开源,并且在Go社区中非常受欢迎,:本文主要介绍GO语言zap日志库理解和使用方法的相关资... 目录1. zap日志库介绍2.安装zap库3.配置日志记录器3.1 Logger3.2 Sugared

Go语言中如何进行数据库查询操作

《Go语言中如何进行数据库查询操作》在Go语言中,与数据库交互通常通过使用数据库驱动来实现,Go语言支持多种数据库,如MySQL、PostgreSQL、SQLite等,每种数据库都有其对应的官方或第三... 查询函数QueryRow和Query详细对比特性QueryRowQuery返回值数量1个:*sql

GO语言中gox交叉编译的实现

《GO语言中gox交叉编译的实现》本文主要介绍了GO语言中gox交叉编译的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录一、安装二、使用三、遇到的问题1、开启CGO2、修改环境变量最近在工作中使用GO语言进行编码开发,因

从基础到高级详解Go语言中错误处理的实践指南

《从基础到高级详解Go语言中错误处理的实践指南》Go语言采用了一种独特而明确的错误处理哲学,与其他主流编程语言形成鲜明对比,本文将为大家详细介绍Go语言中错误处理详细方法,希望对大家有所帮助... 目录1 Go 错误处理哲学与核心机制1.1 错误接口设计1.2 错误与异常的区别2 错误创建与检查2.1 基础