写 React 组件时,你肯定写过这样的代码:<div><h1>Hello JSX</h1></div>—— 这行 JSX 看起来像 HTML,却能和 JavaScript 一起运行。但你有没有想过:浏览器根本不认识 JSX,它是怎么被 “看懂” 的?为什么直接在 HTML 里写 JSX 会报错?
答案藏在一个叫 “Babel” 的工具里。它就像一个 “翻译官”,能把浏览器不认识的 “新语法”(包括 JSX、ES6 + 语法)转换成它能看懂的 “旧语法”。今天就来扒一扒:JSX 为什么不能独立运行?Babel 是怎么把它 “翻译” 成正经 JavaScript 的?
一、JSX 的 “困境”:浏览器根本不认识它
先看一个简单的 JSX 代码:
const element = <h1>Hello, Babel!</h1>;
这段代码看起来直观又舒服,但有个致命问题:浏览器完全不认识它。浏览器只能理解符合 ECMAScript 标准的 JavaScript 代码,而 JSX 是 React 发明的 “扩展语法”,相当于给 JavaScript 加了 “方言”,浏览器的 “语言系统” 里根本没有这个词。
再比如 ES6 的let和箭头函数:
let a = 1;
const add = (x, y) => x + y;
在 IE8 这种 “老古董” 浏览器里,let和=>会被当成 “病句” 直接报错。
二、Babel:让 JavaScript “穿越” 到任何浏览器的 “翻译官”
Babel 的 slogan 是 “Make JavaScript great again”,它的核心功能就一个:把新的 JavaScript 语法(包括 JSX)转换成旧的、浏览器能识别的语法。
简单说,它就像一个 “语法转换器”:
- 把
let a = 1转换成var a = 1(让 IE 也能看懂); - 把
() => {}转换成function () {}; - 把
<h1>Hello</h1>转换成React.createElement('h1', null, 'Hello')(让浏览器看懂 JSX)。
(1)Babel 处理 ES6 + 语法:把 “新写法” 转成 “旧写法”
比如这段用了let和箭头函数的代码:
// 新语法:let和箭头函数
let greet = (name) => `Hello ${name}`;
经过 Babel 转换后,会变成旧浏览器能识别的var和function:
// 转换后的旧语法
"use strict";
var greet = function greet(name) {
return "Hello " + name;
};
(2)Babel 处理 JSX:把 “类 HTML” 转成 React 能识别的函数调用
JSX 是 React 的 “专属语法”,Babel 会把它转换成 React 提供的createElement函数调用。比如:
// JSX语法
const App = () => <h1 className="title">Hello JSX</h1>;
转换后:
// 转换后的React.createElement调用
"use strict";
const App = () => React.createElement(
"h1", // 标签名
{ className: "title" }, // 属性(注意className代替class)
"Hello JSX" // 子元素
);
这就是 JSX 能在 React 中运行的核心原因:Babel 把它翻译成了 React 能处理的函数调用,而React.createElement会进一步生成描述 UI 的虚拟 DOM 对象。
三、Babel 编译流程:从安装到转换,一步一步来
想让 Babel 帮你 “翻译” 代码,需要一套完整的工具链。下面用最基础的方式(不依赖 Vite、Webpack 等工程化工具),带你走一遍编译流程。
(1)第一步:安装 Babel 核心工具
Babel 的工作需要两个核心包:
@babel/core:Babel 的核心引擎,负责语法转换的核心逻辑;@babel/cli:Babel 的命令行工具,让我们能通过命令行调用 Babel 进行转换。
安装命令(需要 Node 环境):
# 局部安装(推荐,作为项目依赖)
pnpm i @babel/core @babel/cli -D
# 或npm
npm i @babel/core @babel/cli --save-dev
-D表示 “开发环境依赖”—— 因为编译是开发阶段的工作,上线后不需要 Babel,所以只在开发时安装。
(2)第二步:告诉 Babel “怎么翻译”—— 配置预设(Presets)
Babel 本身只提供了语法转换的 “框架”,具体怎么转换(比如怎么处理 ES6,怎么处理 JSX),需要通过 “预设(Presets)” 来指定。预设就是 “一组转换规则的集合”。
常用的两个预设:
@babel/preset-env:处理 ES6 + 新语法(如let、const、箭头函数、Promise等),自动转换成目标浏览器支持的旧语法;@babel/preset-react:专门处理 JSX 语法,把它转换成React.createElement调用。
安装这两个预设:
pnpm i @babel/preset-env @babel/preset-react -D
(3)第三步:创建配置文件 ——.babelrc
在项目根目录创建.babelrc文件,告诉 Babel 要使用哪些预设:
{
"presets": [
"@babel/preset-env", // 处理ES新语法
"@babel/preset-react" // 处理JSX
]
}
Babel 会自动读取这个配置文件,按照预设的规则进行转换。
(4)第四步:执行编译,看 Babel 怎么 “翻译” 代码
假设我们有一个1.jsx文件,内容是 JSX 和 ES6 语法:
const App = () => {
let message = "Hello Babel";
return <h1>{message}</h1>;
};
通过@babel/cli提供的babel命令编译这个文件:
npx babel 1.jsx -o 2.jsx
或者依赖Babel 核心库和预设(Preset)规则:
./node_modules/.bin/babel 1.jsx -o 2.jsx
编译后的dist/app.js内容:
let被转换成了var(兼容旧浏览器);- JSX 被转换成了
React.createElement调用(浏览器现在能看懂了)。
四、为什么 Vite/Create React App 里不用手动配置 Babel?
在实际开发中,我们用 Vite 或 Create React App 创建的 React 项目,从来不用手动敲babel命令 —— 因为这些工程化工具已经 “内置” 了 Babel,并帮我们做好了配置。
比如 Vite 会在开发时自动监听 JSX 文件的变化,通过内置的 Babel 插件实时把 JSX 转换成React.createElement,再交给浏览器运行。我们写的 JSX 能 “直接运行”,其实是 Vite 在背后自动完成了编译步骤。
五、总结:Babel 为什么是前端工程化的 “刚需”?
- JSX 能运行,全靠 Babel 翻译:浏览器不认识 JSX,Babel 把它转换成
React.createElement调用,让 React 能处理。 - 新语法兼容旧浏览器:ES6 + 的
let、箭头函数等新语法,经 Babel 转换后能在 IE 等旧浏览器中运行。 - 工程化工具的底层依赖:Vite、Webpack 等工具通过集成 Babel,让我们能 “写新语法,跑在任何环境”,不用关心编译细节。