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 useawait
to resolve promises. - Attribute names are the same as in HTML, therefore you must use
class
instead ofclassName
oraria-label
instead ofariaLabel
. - 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 ofbackgroundColor
(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
orstyle
, it is automatically translated to a JSON string in the resulting markup (e.g.data-props={{ key: "value" }}
becomesdata-props="{"key":"value"}"
). - 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>" }}
.
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<> {{ html: "<!DOCTYPE html>"}} <html lang="en"> <body> <h1>{{ html: "Include <i>literal</i> html from a <b>trusted</b> source" }}</h1> </body> </html> <>
this.jsxEscapeHTML = false
in a JSX component. This feature can be used for advanced patterns (e.g. to create custom HTML components):
Then use it like:export default function Html({ children }) { const $jsxEscapeHTML = this.jsxEscapeHTML; const RestoreEscape = () => { this.jsxEscapeHTML = $jsxEscapeHTML; return null; }; this.jsxEscapeHTML = false; return ( <> {children} <RestoreEscape /> </> ); }
If you need to escape HTML by hand, you can import the existing utility function directly from Jeasx:<Html> <section> {"<p>Unescaped text</p>"} </section> </Html>
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);
};
}
For all the advanced features provided by the jsx-async-runtime
, have a look at the example application in the GitHub-Repository.