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 a little bit 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. As this is runtime is mostly intended for creating HTML markup on a server, it tries to stick as close to the HTML standards as possible. It also ships with some convenience rendering implementations which make additional libraries like classnames superfluous.

  • 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 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 (e.g. <div style={{ "background-color": "red", "margin-top": "1rem" }}>...</div>
  • When using an object for a class definition, it is automagically translated to a string with all truthy values separated by spaces (e.g. <h1 class={{ center: true, "my-class": true, "my-other-class": false }}>...</h1>)
  • When using an array of strings for a class definition, it is automatically translated into a single string with values separated by spaces (e.g. <div class={["v-align","h-align"]}>...</div>)
  • 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="{&quot;key&quot;:&quot;value&quot;}").
  • With Jeasx >= v2.x.x all HTML markup is escaped by default. If you want to include HTML (or other code) snippets, you can provide an object with the key html containing the literal code to be included in the rendered result: {{ html: "<p>Some HTML from a CMS</p>" }}.
    
    <>
      {{ html: "<!DOCTYPE html>"}}
      <html lang="en">
        <body>
          <h1>{{ html: "Include <i>literal</i> html from a <b>trusted</b> source" }}</h1>
        </body>
      </html>
    <>
    
    If you need to disable HTML escaping globally (e.g. restore the behaviour of Jeasx < v2.x.x) or for a component and children, you can set this.jsxEscapeHTML = false in a JSX component. This feature can be used for advanced patterns (e.g. to create custom HTML components):
    
    export default function Html({ children }) {
      const $jsxEscapeHTML = this.jsxEscapeHTML;
    
      const RestoreEscape = () => {
        this.jsxEscapeHTML = $jsxEscapeHTML;
        return null;
      };
    
      this.jsxEscapeHTML = false;
    
      return (
        <>
          {children}
          <RestoreEscape />
        </>
      );
    }
    
    Then use it like:
    
    <Html>
      <section>
        {"<p>Unescaped text</p>"}
      </section>
    </Html>
    
    If you need to escape HTML by hand, you can import the existing utility function directly from Jeasx:
    
    import { escapeEntities } from "jsx-async-runtime";
    escapeEntities("<p>Hello World</p>");
    

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

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

  return (
    <>
      {{ html: "<!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"
            >
              {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/[guard].js to your project:

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

export default function ({ 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.