DEV Community

Taichi Murai
Taichi Murai

Posted on

How JSX Works

What is JSX?

JSX(JavaScript Syntax eXtension) is a syntax extension(Not a separate language!) for JavaScript that allows us to write HTML-like code within our JavaScript code.
It was originally developed by Meta to be used with React, but it has been adopted by other libraries and frameworks(Vue.js, Solid, Qwik etc) as well.

Benefits of JSX

  • Improved security ... JSX code can be compiled into safer JavaScript code that produces HTML strings that have dangerous characters removed, like < and >, which could create new elements. Instead, these HTML strings replace the angular brackets with the less-than and greater-than signs in this scenario to make things safer. (sanitization)
  • Encourages component-based architecture ... JSX encourages a component-based architecture, which can help make code more modular and easier to maintain.

Drawbacks of JSX

  • Requires tooling ... JSX code must be compiled into regular JavaScript code before it can be executed, which adds an extra step to the development tool-chain. Other alternatives, like Vue.js, for example, can work immediately in a browser environment when included as nothing more than a <script> tag in a page.
  • Mixing of concerns ... Some developers argue that JSX mixes concerns by combining HTML-like code with JavaScript code, making it harder to separate presentation from logic

How it works

Code is compiled using a compiler. A compiler is a piece of software that translates source code written in a high-level programming language into a syntax tree according to specific rules. The process of compiling code involves several steps, including lexical analysis, parsing, semantic analysis, optimization, and code generation.

A compiler uses a three-step process:
1. Tokenization
Essentially breaking up a string of characters into meaningful tokens. When a tokenizer is stateful and each token contains state about its parents and/or children, a tokenizer is called a lexer. The lexer then maps key words to some type of enumerable value, depending on its implementation. For example, const becomes 0, let becomes 1, function becomes 2 etc.
2. Parsing
The process of taking the tokens and converting them into a syntax tree. The syntax tree is a data structure that represents the structure of the code.

{
type: "Program",
body: [
    {
    type: "VariableDeclaration",
    declarations: [
        {
        type: "VariableDeclarator",
        id: {
            type: "Identifier",
            name: "a"
        },
        init: {
            type: "Literal",
            value: 1,
            raw: "1"
        }
        }
    ],
    kind: "const"
    },
    {
    type: "VariableDeclaration",
    declarations: [
        {
        type: "VariableDeclarator",
        id: {
            type: "Identifier",
            name: "b"
        },
        init: {
            type: "Literal",
            value: 2,
            raw: "2"
        }
        }
    ],
    kind: "let"
    },
    {
    type: "ExpressionStatement",
    expression: {
        type: "CallExpression",
        callee: {
        type: "Identifier",
        name: "console"
        },
        arguments: [
        {
            type: "BinaryExpression",
            left: {
            type: "Identifier",
            name: "a"
            },
            right: {
            type: "Identifier",
            name: "b"
            },
            operator: "+"
        }
        ]
    }
    }
]
}
Enter fullscreen mode Exit fullscreen mode

3. Code generation
This is where the compiler generates machine code from the abstract syntax tree(AST). This involves translating the code in the AST into a series of instructions that can be executed directly by the computer’s processor. The resulting machine code is then executed by the JavaScript engine.

Extending JavaScript Syntax with JSX

To extend JavaScript syntax, we’d need to deal with our new syntax before it reaches the engine.
To do this, we need to create our own lexer and parser that can understand our extended language: that is, take a text string of code and understand it. Then, instead of generating machine code as is traditional, we can take this syntax tree and instead generate plain old regular vanilla JavaScript that all current engines can understand. This is precisely what Babel in the JavaScript ecosystem does, along with other tools like TypeScript, Traceur, and swc
Because of this, JSX cannot be used directly in the browser, but instead requires a “build step” where a custom parser runs against it, then compiles it into a syntax tree. This code is then transformed into vanilla JavaScript in a final, distributable bundle. This is called transpilation: transformed, then compiled code.

The JSX Pragma

It all starts with <, which, on its own, is an unrecognizable character in JavaScript when used outside of comparison operations. This pragma, a compiler directive to provide additional information to the compiler, can be transpiled into a function call.
The name of the function to call when a parser sees a < pragma is configurable, and defaults to the function React.createElemenmt or _jsxs with the newer transform.

Summary

The JSX compilation process involves tokenization, parsing, and code generation. During tokenization, the code is broken down into tokens, which are then converted into a syntax tree through parsing. Finally, code generation translates the syntax tree into machine code that the JavaScript engine can execute.

Extending JavaScript syntax with JSX involves creating a lexer and parser to understand the extended language, followed by transpilation to convert the JSX into vanilla JavaScript. This process requires a build step since JSX cannot be used directly in the browser. The JSX pragma, indicated by the < character, is transpiled into function calls like React.createElement or _jsxs in the newer transform.

Reference

This article is based on insights and information from the book Fluent React by O'Reilly Media.

Top comments (0)