JSX & SSR

Server-side rendering of JSX

Jeasx is a server-side rendering (SSR) framework based on JSX, which means that all of your code is executed on the server and the resulting HTML is sent to the client. JSX is a great templating technology due to its simplicity if you are familiar with the basics of JavaScript.

If you are not familiar with JSX, you should read the excellent introduction to JSX at the React homepage.

JSX in Jeasx is different

Jeasx uses a syntax similar to React, but there are some important differences. Under the hood an independent asynchronous JSX runtime implementation (jsx-async-runtime) is used, which is optimized for performant server-side rendering.

  • You can use asynchronous code out of the box, just mark your component as async and feel free to use await to resolve promises.
  • Attribute names are the same as in HTML, therefore you must use class instead of className or aria-label instead of ariaLabel.
  • When using an object for a class definition, it is automagically translated to a string with all truthy values separated by spaces.
  • When using an array of strings for a class definition, it is automatically translated into a single string with values separated by spaces.
  • When using a style object to create inline styles, you have to provide css attribute names as used in CSS, therefore use background-color instead of backgroundColor.
  • When using an object as value for other JSX attributes than class or style, it is automatically translated to a JSON string in the resulting markup (e.g. data-props={{ key: "value" }} becomes data-props="{"key":"value"}").
  • When rendering HTML markup via JSX components, no escaping is done due to performance reasons, so you have to be careful when emitting data from uncontrolled sources. You can use a utility function via import { escapeEntities } from "jsx-async-runtime" to escape HTML entities.

Here's an example which shows all the differences in a single file:

import { escapeEntities } from "jsx-async-runtime";

export default async function Jokes() {
  const { value } = await (
    await fetch("https://api.chucknorris.io/jokes/random")
  ).json();

  return (
    <>
      {"<!DOCTYPE html>"}
      <html lang="en">
        <head>
          <title>Jokes</title>
          <style>{".center {text-align: center;}"}</style>
        </head>
        <body class="body" style={{ "background-color": "red", "padding": "1rem" }}>
          <div class={["v-align","h-align"]} data-props={{ key: "value" }}>
            <h1
              class={{ center: true, "my-class": true, "my-other-class": false }}
              style="color: white"
            >
              {escapeEntities(value)}
            </h1>
          </div>
        </body>
      </html>
    </>
  );
}

View the result of the above code

Transforming JSX components at runtime

The JSX runtime also provides a way to transform JSX components. This can be useful to patch the markup of 3rd party components or to rewrite existing attributes of components.

The following example adds a build timestamp to all image sources, so each image receives a new URL with each deployment. It works by adding a custom jsxToString handler via the this context. Just add the following code as src/routes/[guard].js to your project:

import { jsxToString } from "jsx-async-runtime";

export default function RootGuard({ request, reply }) {
  this.jsxToString = (jsxElement) => {
    if (jsxElement.type === "tag" && jsxElement.tag === "img") {
      jsxElement.props.src = jsxElement.props.src + "?" + process.env.BUILD_TIME;
    }
    return jsxToString.call(this, jsxElement);
  };
}
Learn more

For all the advanced features provided by the jsx-async-runtime, have a look at the example application in the GitHub-Repository.