<Babel> 前端语言的巴别塔

news2025/2/4 8:38:38

在这里插入图片描述

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);
      // 使用编译器将源代码转为 ast
      const 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

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/761925.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

windows命令行运行mysql

1.运行命令&#xff1a;mysql -u用户名 -p密码 2.创建数据库&#xff1a; create 数据库名称 &#xff1b; 3.use 数据库 4.show tables &#xff1b; 5.创建用户&#xff0c;分配权限 6.退出 ctrlc 7.切换用户

海外app在谷歌和苹果商店中该如何设置关键词

主导应用商店搜索结果的方法就是关键词的设置。我们需要寻找关键词&#xff0c;跟踪关键词排名并监控其应用的性能&#xff0c;这样就能大大的提高应用的可见度。 优先考虑可推动Android或ios应用自然下载量的关键词&#xff0c;使用搜索量指标了解某个关键词在应用商店中的搜…

数字孪生很火嘛?是做什么的?

数字孪生是一种新兴的技术概念&#xff0c;将现实世界与数字世界紧密结合&#xff0c;通过数字化的方式模拟、仿真和预测真实世界的物理实体、过程和系统。它是物理实体与其数字化的虚拟模型之间的一种互联关系&#xff0c;旨在实现对现实世界的全面感知和实时监测。 数字孪生的…

骑行健身,生活和工作压力的避风港

在忙碌的现代生活中&#xff0c;每个人都面临着种种生活压力和工作压力。而自行车运动&#xff0c;正是一种理想的压力释放方式。它不仅能帮助我们保持身体健康&#xff0c;更能丰富我们的生活&#xff0c;让我们在自然中寻找宁静。 首先&#xff0c;骑自行车是一种全身性的运动…

BigTable:一个针对结构化数据的分布式存储系统----论文摘要

目录 摘要 1. 介绍 2. 数据模型 行 列族 时间戳 3. API 4. 所需构件 5. 实现 5.1 Tablet的位置 5.2 Tablet分配 5.3 Tablet服务 5.4 压实&#xff08;Compactions&#xff09; 6. 优化 本地化分组 压缩(compression) 通过缓存提高读操作的性能 Bloom过滤器 C…

2023年7月16日,HashMap

HashMap HashMap存储的是一组无序的键值对。存储时是根据键的哈希码来计算存储的位置&#xff0c;因为对象的哈希码是不确定的&#xff0c;因此HashMap存储的元素是无序的。 Map用于保存具有映射关系的数据&#xff0c;Map里保存着两组数据&#xff1a;key和value&#xff0c;它…

Leetcode-每日一题【2487.从链表中移除节点】

题目 给你一个链表的头节点 head 。 对于列表中的每个节点 node &#xff0c;如果其右侧存在一个具有 严格更大 值的节点&#xff0c;则移除 node 。 返回修改后链表的头节点 head 。 示例 1&#xff1a; 输入&#xff1a;head [5,2,13,3,8]输出&#xff1a;[13,8]解释&…

拒绝被其他域名恶意解析到你的服务器上

拒绝被其他域名恶意解析到你的服务器上 备案问题恶意解析解决方案后记 备案问题 新的一周开始了&#xff0c;又是一个摸鱼的好时候。。。。结果&#xff0c;刚刚坐到工位上&#xff0c;机房客服发来了一个 excel &#xff0c;说。。。你的备案信息没完善。。。 啥&#xff1f…

C语言进阶之程序环境和预处理

程序环境和预处理 1. 程序的翻译环境和执行环境2. 详解编译链接2.1 翻译环境2.2 编译的几个阶段2.3 运行环境 3. 预处理详解3.1 预定义符号3.2 #define3.2.1 #define 定义标识符3.2.2 #define 定义宏3.2.3 #define 替换规则3.2.4 #和##3.2.5 带副作用的宏参数3.2.6 宏和函数对比…

快速搭建接口自动化测试框架

1 接口测试 接口测试是对系统或组件之间的接口进行测试&#xff0c;主要是校验数据的交换&#xff0c;传递和控制管理过程&#xff0c;以及相互逻辑依赖关系。 接口自动化相对于UI自动化来说&#xff0c;属于更底层的测试&#xff0c;这样带来的好处就是测试收益更大&#xff…

Python基础教程:数据结构

Python是一门广泛使用的编程语言&#xff0c;它的丰富的数据结构使得编写程序变得异常简单和方便。在本篇教程中&#xff0c;我将详细介绍Python中的四种主要数据结构&#xff1a;列表、元组、字典、集合。 1.列表&#xff08;List&#xff09; 列表是Python中最常用的数据结…

Nginx代理Grafana,鉴权访问以及Grafan免登录访问

✨概述 在使用grafana做页面嵌入的场景中&#xff0c;通常需要grafana与前端在同域下&#xff0c;方便鉴权、解决跨域。 Nginx代理Grafana后&#xff0c;就不能使用Grafana中默认配置的端口和路径进行访问&#xff0c;必须通过Nginx访问Grafana。 如果需要做Iframe嵌入自研系…

RabbitMQ ---- 发布高级确认

RabbitMQ ---- 发布高级确认 1. 发布确认 springboot 版本1.1 确认机制方案1.2 代码架构图1.3 配置文件1.4 添加配置类1.5 消息生产者1.6 回调接口1.7 消息消费者1.8 结果分析 2. 回退消息2.1 Mandatory 参数2.2 回调接口2.3 结果分析 3. 备份交换机3.1 代码架构图3.2 修改配置…

CAD可以转换成PDF吗?教你简单好用的转换方法

PDF格式是一种通用格式&#xff0c;可以在不同的设备和操作系统上轻松打开和查看&#xff0c;这使得共享和协作变得更加容易和高效。尤其是在远程工作的情况下&#xff0c;PDF格式能够让团队成员更方便地分享和合作&#xff0c;不受地理位置和设备的限制。那么怎么将CAD文件转换…

7. Java + Selenium 环境搭建

前提&#xff1a;Java 版本最低要求为 8&#xff1b;推荐使用 chrome 浏览器 chrome Java 1. 下载 chrome 浏览器&#xff08;推荐&#xff09; 2. 查看 chrome 浏览器版本 重点记住前两位即可。 3. 下载 chrome 浏览器驱动 下载链接&#xff1a; https://chromedriver.…

IPD跟敏捷、DevOps一样吗?有什么区别?

1992年在激烈的全球市场竞争下&#xff0c;IBM遭遇到了严重的财政困难&#xff0c;公司销售收入停止增长&#xff0c;利润急剧下降。经过内部分析&#xff0c;IBM发现他们在研发费用、研发损失费用和产品上市时间等几个方面远远落后于业界最佳。为了重新获得市场竞争优势&#…

SpringBoot源码分析(6)--SpringBootExceptionReporter/异常报告器

文章目录 一、前言二、异常报告器介绍2.1、作用2.2、接口定义2.3、FailureAnalyzer错误分析器2.4、FailureAnalysisReporter错误报告器 三 、SpringBootExceptionReporter源码分析四、shutdownHook介绍4.1、背景4.2、什么是Shutdown Hook4.3、什么时候会调用Shutdown Hook4.4、…

MYSQL 5.7.17 安装版 的配置文件

解压版解压后都有 my.ini配置文件&#xff0c;安装版要查找这个配置文件可以查看 MYSQL Workbench --> 左侧 INSTANCE --> Options File &#xff0c;然后可以看到底部 Configuration File所处的位置&#xff0c;即为my.ini的路径。

医疗设备如何保障?蓄电池自动监测,简直太牛了!

蓄电池监控在医院中扮演着重要的角色&#xff0c;确保在电力故障或断电时医院能够继续供电&#xff0c;保障医疗设备和关键系统的正常运行。 通过监测蓄电池的状态、充电状态和容量&#xff0c;以及触发警报和提醒&#xff0c;监控系统可以提前发现蓄电池的故障或异常情况&…

计算机网络 day8 动态路由 - NAT - SNAT实验 - VMware的网卡的3种模式

目录 动态路由&#xff1a;IGP 和 EGP 参考网课&#xff1a;4.6.1 路由选择协议概述_哔哩哔哩_bilibili ​编辑 IGP&#xff08;Interior Gateway Protocol&#xff09;内部网关协议&#xff1a; EGP&#xff08;Interior Gateway Protocol&#xff09;外部网关协议&#x…