编译JSX语法

大家好,我是万维读客的讲师曹欢欢。本节我们首先实现jsx的编译功能,然后基于前面介绍的jsx的转化后的数据结构,再构建react渲染虚拟DOM。

jsx测试用例

新建treact02文件夹,新建jsx.test.jsx文件,内容如下:

describe('jsx Test',()=>{
    it('build jsx', ()=>{
        const ele = (
        <div className="container">
            <span>hello</span>
            <a>w3cdoc.com</a>
        </div>);
    })
})

前面的章节中我们学习过,jsx通过编译插件编译后会变成函数形式, 类似下面这种:

const element = React.createElement(
  'div',
  {className: 'container'},
  ...
);

配置jsx编译

这个在vite里面的esbuild默认已经集成了编译jsx的组件,我们可以通过配置来修改编译的函数,修改vitest.config.ts,增加esbuild配置:

import { defineConfig } from 'vitest/config'

export default defineConfig({
    test: {
        environment: 'happy-dom',
    },
    esbuild: {
        jsxFactory: 'Treact.createElement'
    }
})

然后关闭测试用例控制台,重新启动npm run test,可以看到输出结果如下:

 FAIL  treact02/jsx.test.jsx > jsx Test > build jsx
ReferenceError: Treact is not defined
 ❯ treact02/jsx.test.jsx:15:9
     13|     it('build jsx', ()=>{
     14|         const ele = (
     15|         <div className="container">
       |         ^
     16|             <span>hello</span>
     17|             <a>w3cdoc.com</a>

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/1]⎯

 Test Files  1 failed | 1 passed (2)
      Tests  1 failed | 2 passed (3)
   Start at  20:11:48
   Duration  1.06s (transform 35ms, setup 0ms, collect 31ms, tests 513ms, environment 391ms, prepare 221ms)


 FAIL  Tests failed. Watching for file changes...
       press h to show help, press q to quit

报错提示Treact is not defined,说明已经编译成Treact了,下面我们来写个Treact试一下。

编写Treact

新建文件Treact.jsx, 内容如下,这里主要编写createElement函数:

export function createElement(type, props, ...children) {
    return {
        type,
        props: {
            ...props,
            children
        }
    }
}

然后在测试用例文件jsx.test.jsx中引入Treact, 打印我们定义的ele,修改后内容如下:

import {describe, it, expect} from 'vitest';
import * as Treact from './Treact';

describe('jsx Test',()=>{
    it('build jsx', ()=>{
        const ele = (
        <div className="container">
            <span>hello</span>
            <a>w3cdoc.com</a>
        </div>);
        console.log(JSON.stringify(ele));
    })
})

可以查看控制台已经正常输出了,测试用例通过了,输出内容:

 RERUN  treact02/jsx.test.jsx x3

stdout | treact02/jsx.test.jsx > jsx Test > build jsx
{"type":"div","props":{"className":"container","children":[{"type":"span","props":{"children":["hello"]}},{"type":"a","props":{"children":["w3cdoc.com"]}}]}}

 ✓ treact02/jsx.test.jsx (1)
   ✓ jsx Test (1)
     ✓ build jsx

 Test Files  1 passed (1)
      Tests  1 passed (1)
   Start at  20:40:26
   Duration  17ms


 PASS  Waiting for file changes...
       press h to show help, press q to quit

打印数来的ele的数据如上面所示,正是我们刚定义的createElement函数返回的数据结构。

{
  "type":"div",
  "props":{
    "className":"container",
    "children":[{
      "type":"span",
      "props":{"children":["hello"]}
    },{
      "type":"a",
      "props":{"children":["w3cdoc.com"]}
    }]
  }
}

参考学习

  1. 编译JSX: https://esbuild.github.io/content-types/#jsx
  2. className属性:https://developer.mozilla.org/en-US/docs/Web/API/Element/className


请遵守《互联网环境法规》文明发言,欢迎讨论问题
扫码反馈

扫一扫,反馈当前页面

咨询反馈
扫码关注
返回顶部