• 作者:老汪软件技巧
  • 发表时间:2024-08-24 04:01
  • 浏览量:

React 代码的转换主要是通过 Babel 来完成的。React 使用了 JSX 语法,而 JSX 是一种 JavaScript 的语法扩展,它看起来像 HTML,但不能直接在浏览器中运行。Babel 作为一个 JavaScript 编译器,可以将 JSX 转换为标准的 JavaScript 代码(ES5/ES6),从而使得 React 代码可以在浏览器中执行。

Webpack 集成在大多数现代 React 项目中,Babel 通常与 Webpack 集成使用。下面是一个基础的Webpack 配置示例:

const path = require('path');
module.exports = {
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js',
  },
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env', '@babel/preset-react'],
          },
        },
      },
    ],
  },
  resolve: {
    extensions: ['.js', '.jsx'],
  },
};

在这个配置中,Webpack 通过模块解析规则找到每个导入的模块,并确定这些模块的位置。Webpack 支持多种模块类型,包括 ES6 模块、CommonJS 模块等。

对于 React 代码,通常会包含诸如 import React from 'react'; 或 import App from './App'; 的语句。Webpack 会解析这些导入,查找相应的模块文件。

然后Webpack 依赖加载器(Loaders)来处理非 JavaScript 文件和特殊的 JavaScript 语法。在 React 项目中,最常用的加载器是 babel-loader,它用于转换 JSX 和 ES6+ 代码。

这个过程顺序为:@babel/preset-react先处理 JSX ,得到 ES6+语法,然后@babel/preset-env再处理成 ES5 的语法。

那我我们就来研究一下这个@babel/preset-react干了什么?

我们编写如下一段 JSX 语法:

const App = () => {
  return <h1>Hello, World!h1>;
};
export default App;

在转换过程中,上述代码最终会被转换为:

"use strict";
const App = () => {
  return /*#__PURE__*/React.createElement("h1", null, "Hello, World!");
};
export default App;

代码解释转换后的代码中,Hello, World! 被替换成了 React.createElement 的调用。这是因为 JSX 语法只是 React 语法糖,本质上它会被转换成对 React.createElement 的函数调用。这个函数返回一个描述 UI 的 JavaScript 对象(也就是虚拟 DOM),React 根据这个对象来渲染实际的 DOM。转换后的代码可以在任何支持 ES5 的环境中运行。即使浏览器不支持 JSX 语法或者不支持最新的 JavaScript 特性,Babel 也能将这些代码转换成兼容性良好的 JavaScript。

上面转化为React.createElement就是由@babel/preset-react这个预设的 babel 来做的。

我们来看看它干了什么事?

在 源码中我们看到,它又使用到了另外的插件,@babel/plugin-transform-react-jsx和@babel/plugin-transform-react-jsx-development,这两个里面才是真正的实现了转换React.createElement的功能。

源码位置:/babel/babel…

它这是用了两个插件是为了区分生产环境,我们就看看@babel/plugin-transform-react-jsx做的工作。

@babel/plugin-transform-react-jsx 也是 Babel 的一个插件,专门用于将 JSX 语法转换为标准的 JavaScript 代码。这个插件的核心任务是将 JSX 结构转换成 React.createElement 函数调用,从而使 JSX 可以在 JavaScript 环境中运行。

下面是 @babel/plugin-transform-react-jsx 的核心工作流程:

编译是什么意思_编译是哪个键_

1. 解析 JSX 元素

Babel 在解析代码时,会将 JSX 元素转换为 AST 中的特定节点类型。例如:

const element = <h1>Hello, World!h1>;

这个代码片段会被解析成一个包含 JSXElement 节点的 AST,其中 h1 是 JSXIdentifier 节点,Hello, World! 是 JSXText 节点。

**2. 转换 JSX 到 ****React.createElement**

@babel/plugin-transform-react-jsx 插件会遍历 AST,找到所有的 JSXElement 节点,然后将它们转换为对应的 React.createElement 函数调用。

伪代码示例:

function JSXElementToCreateElement(path) {
  const node = path.node;
  const openingElement = node.openingElement;
  const tagName = openingElement.name.name;  // 例如 'h1'
  const attributes = openingElement.attributes;  // 例如 []
  const children = node.children;  // 例如 ['Hello, World!']
  // 转换成 React.createElement(tagName, props, ...children)
  path.replaceWith(
    t.callExpression(
      t.memberExpression(t.identifier("React"), t.identifier("createElement")),
      [
        t.stringLiteral(tagName),  // 第一个参数是标签名
        t.nullLiteral(),  // 第二个参数是属性,这里为空
        ...children.map(child => t.stringLiteral(child.value))  // 子元素
      ]
    )
  );
}

3. 处理属性

如果 JSX 元素有属性,这些属性会被转换为一个对象,并作为 React.createElement 的第二个参数。例如:

const element = <h1 className="header">Hello, World!h1>;

转换为:

const element = React.createElement("h1", { className: "header" }, "Hello, World!");

4. 处理子元素

JSX 元素中的子元素(例如文本节点或嵌套的 JSX 元素)会作为 React.createElement 的第三个及后续参数传递。插件会递归地处理这些子元素,并将它们转换为相应的 JavaScript 表达式。

5. 插件的整体结构

@babel/plugin-transform-react-jsx 的结构大致如下:

module.exports = function(babel) {
  const { types: t } = babel;
  return {
    visitor: {
      JSXElement(path) {
        // 将 JSX 元素转换为 React.createElement
        JSXElementToCreateElement(path);
      }
    }
  };
};

总结

@babel/plugin-transform-react-jsx 的核心工作是将 JSX 语法转换为 JavaScript 的函数调用(通常是 React.createElement)。通过遍历 AST 中的 JSX 元素节点,并将这些节点转换为等效的 JavaScript 表达式,这个插件实现了从 JSX 到普通 JavaScript 代码的转换。这使得开发者可以编写直观的 JSX 代码,而不必手动构造复杂的 JavaScript 表达式。

本文只讲到了冰山一角,还有很多工作没有涉及到,让大家直接初步了解 react 最终转化成ES代码以后是怎么工作的。


上一条查看详情 +何时Softmax退化成Sigmoid?
下一条 查看详情 +没有了