《深入解析:JSX如何通过Babel变身React可执行代码》

208 阅读4分钟

前言

学过 React 的朋友们,肯定对 JSX 十分熟悉。它是 React 中编写 UI 的主要方式,看起来像是直接在 JavaScript 里写 HTML,但实际上它的背后隐藏了许多重要的机制。今天,我们就来深入探讨 JSX 的本质、原理以及编译它的工具-Babel。

JSX到底是个啥?

JSX(JavaScript XML)  是 React 提供的一种JavaScript语法扩展,允许我们在 JavaScript 代码中编写类似 HTML 的结构。例如:

const element = <h1>Hello, React!</h1>;

虽然它看起来像 HTML,但它 并不是真正的 HTML,而是一种 JavaScript 的语法糖,最终会被转换成标准的 JavaScript 代码。

JSX背后的原理

JSX 不能独立运行

JSX 的语法(如 <div>Hello</div>)并不是原生 JavaScript 的一部分,浏览器和 JavaScript 引擎无法直接解析它,如果你尝试直接运行JSX,那么则会报语法错误,因为它不符合 JavaScript 语法规范:

  • JSX 的语法(如 <div>Hello</div>)并不是原生 JavaScript 的一部分,浏览器和 JavaScript 引擎无法直接解析它。

  • JSX 最终需要被转换为标准的 JavaScript 函数调用(如 React.createElement()),否则会报语法错误。

要让JSX能够运行的几种方法:

  1. 使用编译器:通过 Babel 等工具将 JSX 转为 JavaScript。
  2. 提供运行时环境:确保 React(或类似库如 Preact)被引入。
  3. 配置构建工具:例如在 Webpack 中配置 babel-loader

JSX的编译--Babel

上面我们提到了JSX不能独立运行,它必须通过工具(如 Babel、TypeScript 或 SWC)编译成普通的 JavaScript 代码,才能运行,今天我们就对编译工具Babel进行详解,Babel也是React通常使用的将 JSX 转换为 React.createElement() 调用的方法,让我们看看Babel是具体怎么编译JSX的吧!

Babel是什么?

Babel 是一个 JavaScript 编译器,主要用于将新版本的 JavaScript(如 ES6+)或扩展语法(如 JSX)转换成浏览器广泛支持的旧版 JavaScript(如 ES5)。它通过插件系统(如 @babel/preset-react)处理 JSX,将其编译为 React.createElement() 调用,并支持语法降级、代码优化等功能,是现代前端开发(如 React、Vue 等框架)不可或缺的工具链核心。

详细步骤解析

Babel 将 JSX 转换为 React.createElement() 调用的过程可以分为以下几个关键步骤:

1. 安装必要依赖

首先需要安装 Babel 核心工具和 React 相关的预设:

pnpm install @babel/cli @babel/core @babel/preset-react -D
  • @babel/cli: Babel 命令行工具
  • @babel/core: Babel 核心编译引擎
  • @babel/preset-react: 专门处理 JSX 转换的预设

2. 配置 Babel

创建或修改 babel.config.json 文件:

{
  "presets": ["@babel/preset-react"]
}

3. 编译过程详解

当 Babel 处理 JSX 文件时,会经历以下转换步骤:

3.1 解析阶段 (Parsing)

Babel 使用 Babylon 解析器将 JSX 代码解析成抽象语法树(AST)

// 原始代码
const element = <h1 className="title">Hello</h1>;

会被解析为类似这样的 AST 结构:

{
  "type": "JSXElement",
  "openingElement": {
    "type": "JSXOpeningElement",
    "name": { "type": "JSXIdentifier", "name": "h1" },
    "attributes": [
      {
        "type": "JSXAttribute",
        "name": { "type": "JSXIdentifier", "name": "className" },
        "value": { "type": "StringLiteral", "value": "title" }
      }
    ]
  },
  "children": [
    { "type": "JSXText", "value": "Hello" }
  ]
}

3.2 转换阶段 (Transformation)

@babel/preset-react 中的插件会将 JSX AST 转换为 JavaScript AST

转换规则:

  • JSX 元素 → React.createElement() 调用
  • 属性 → 第二个参数的对象属性
  • 子元素 → 后续参数

3.3 生成阶段 (Code Generation)

将转换后的 AST 重新生成为 JavaScript 代码:

// 转换后代码
const element = React.createElement(
  "h1",
  { className: "title" },
  "Hello"
);

4. 执行编译

使用 Babel CLI 执行编译:

./node_modules/.bin/babel src --out-dir lib

或通过 npm script:

{
  "scripts": {
    "build": "babel src --out-dir lib"
  }
}

5. 运行时要求

编译后的代码需要 React 运行时支持,因此需要确保:

  1. React 已安装 (pnpm install react)
  2. React 在作用域内可用 (通过 import 或全局变量)

看看我们的编译结果把!

image.png

image.png

了解了这个过程之后,所以现在你能够知道:JSX不能直接运行,它需要通过React使用Babel的工具编译。而在实际开发中,我们很少直接使用Babel的命令行工具(@babel/cli)来手动编译JSX,是因为现代前端工具链React已经帮我们自动集成了这个过程。

总结

JSX作为React的核心语法,虽然看起来像HTML,但实际上是JavaScript的语法扩展,无法被浏览器直接执行。通过本文的深入探讨,我们了解到Babel在这一转换过程中扮演着关键角色:它将JSX代码解析为AST抽象语法树,再转换为React.createElement()调用,最终生成浏览器可执行的JavaScript代码。有趣的是,在现代前端开发中,虽然我们很少直接操作Babel命令行工具,但通过create-react-app等脚手架工具和webpack等打包工具,这一编译过程已经被完美地自动化集成。理解JSX的编译原理不仅能帮助我们更好地使用React,也能在遇到相关问题时快速定位和解决,是每位React开发者都应该掌握的核心知识。