编译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"]}
}]
}
}
参考学习
- 编译JSX: https://esbuild.github.io/content-types/#jsx
- className属性:https://developer.mozilla.org/en-US/docs/Web/API/Element/className