First let’s look at the following code

  import "react" from "react";
  const element = (<div>
        <div>
            <span>1</span>
            <span>2</span>
            <span>3</span>
        </div>
        <div>1</div>
        <div>2</div>
</div>)
console.log(element)
Copy the code

How does Element output the structure shown above?

Environment configuration

Install React and Babel

npm i react react-dom --save
npm i @babel/core @babel/preset-env @babel/plugin-transform-react-jsx --save-dev
Copy the code

Configure the Babel

{
    test: /\.(js|jsx)$/,
    include: paths.appSrc,
    loader: require.resolve('babel-loader'),
    options: {
        {
            "presets": [
                "@babel/preset-env"]."plugins": [
                "@babel/plugin-transform-react-jsx"
            ]
        },
        cacheDirectory: true,}}Copy the code

@babel/plugin-transform-react-jsxWhat did you do?

When <div>123</div> execute React. CreateElement ("div"."123"); <div> <div>1</div> <div>2</div> <div>3</div> </div>"div", 
        React.createElement("div"."1"),
        React.createElement("div"."2"),
        React.createElement("div"."3"React import react from when developing with React if you use JSX syntax"react"
Copy the code

Write a function to simulate its execution

In order to facilitate understanding We put the < div > < div > < span > 1 < / span > < span > 2 < / span > < span > 3 < / span > < / div > < div > 1 < / div > < div > 2 < / div > < / div > as a treelet element = {
    type:"div",
    children:[{
        type:"div",
        children:[{
            type:"span",
            children:"1"
        }, {
            type:"span",
            children:"2"
        }, {
            type:"span",
            children:"3"}]}, {type:"div",
        children:1
    }, {
        type:"div", children:2}]} Write a function to deeply traverse the treefunction jsxTransformNode(element, callback){
    let children = [];
    if (Array.isArray(element.children)) {  
        children = element.children.map(child => jsxTransformNode(child, callback))
    } else {
        children = [element.chidren]
    }
    returncallback(element.type, ... children); }let nodes = jsxTransformNode(child, function ReactCreateElement(type. children){return {
        tag: type,
        children
    }
}) 
Copy the code

@babel/plugin-transform-react-jsxThe principle of

If you are not familiar with Babel, you can read this article and write a Babel plug-in from scratch

It’s going to be

<div className="name" age="12"> <div>1</div> <div>2</div> <div>3</div> </div> convert to react. createElement("div",
    {},
    React.createElement("div", {}, ...chidren),
    React.createElement("div", {}, ...chidren),
    React.createElement("div", {},... Chidren)) code blockCopy the code

Without further ado, here is a simple babel-plugin I wrote to parse JSX syntax

var generator = require("@babel/generator").default
function buildAttrsCall (attribs, t){
    let properties = [];
    attribs.forEach(attr => {
        let name = attr.name.name;
        let value = attr.value;
        properties.push(t.objectProperty(t.stringLiteral(name), value))
    });
    returnt.ObjectExpression(properties); } const createVisitor = (t) => { const visitor = {}; Visitor.JSXElement = {// WhyexitBecause JSX is DFS and not BFS;exit(path, file){
            let openingPath = path.get("openingElement");
            let children = t.react.buildChildren(openingPath.parent);
            lettagNode = t.identifier(openingPath.node.name.name); / / create the React. The createElement methodlet createElement =  t.memberExpression(t.identifier("React"),t.identifier("createElement")); // Create a propertyletattribs = buildAttrsCall(openingPath.node.attributes, t); CreateElement (tag, attrs,... Chidren) expressionletcallExpr = t.callExpression(createElement, [tagNode, attribs, ...children]); path.replaceWith(t.inherits(callExpr, path.node)); }}return{visitor, // configure JSX inherits:() => {return {
                manipulateOptions(opts, parserOpts) {
                    parserOpts.plugins.push("jsx"); }}; } } } module.exports =function(babel){
    const t = babel.types;
    return createVisitor(t);
}
Copy the code
  1. Create the tagNode variable
  2. Create the React. CreateElement expression
  3. Create an Attribs object
  4. Create react. createElement(“div”, {},… The children) expression
  5. Finally replace the node

Results the following

Source code is as follows

const a = <div className="name" age="12">
    <div>1</div>
    <div>2</div>
    <div>3</div>
</div>;

Copy the code

After the compilation

var a = React.createElement(div, {
  "className": "name"."age": "12"
}, React.createElement(div, {}, "1"), React.createElement(div, {}, "2"), React.createElement(div, {}, "3"));
console.log(a);

Copy the code