JSX
Ende runs JSX in .jsx and .tsx files with no build step. This page covers
how to configure it: which JSX library to use, how to render JSX to HTML on the
server, and the options that control the transform.
JSX needs a library to turn tags like <h1> into values at runtime. You select
it with the jsxImportSource setting in ende.json. Ende loads packages from
JSR, so the library has to be published there. This page uses
Hono's JSX, from jsr:@hono/hono. Static sites can also
use satz's string renderer.
Set up JSX
Configure JSX once in your ende.json with the automatic runtime. You write JSX
and Ende inserts the right imports for you, so you never import the JSX factory
by hand:
{
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "@hono/hono/jsx"
},
"imports": {
"@hono/hono": "jsr:@hono/hono@^4"
}
}A component is just a function that returns JSX:
export function Hello() {
return <h1>Hello, world!</h1>;
}Legacy classic runtime
Ende's built-in default predates the automatic runtime: it is the classic
"react" transform, which compiles JSX to React.createElement calls and
expects a React variable to be in scope. Prefer the automatic runtime above.
Render JSX to HTML on the server
Hono's JSX elements render to an HTML string with toString(). Text and
attribute values are escaped:
function App({ name }: { name: string }) {
return <h1>Hello {name}</h1>;
}
Ende.serve(async () => {
const html = await (<App name="Ende"/>).toString();
return new Response(`<!DOCTYPE html>${html}`, {
headers: { "content-type": "text/html; charset=utf-8" }
});
});Speed up server rendering
Ende ships a precompile transform built for server-side rendering. It analyzes
your JSX at build time and turns static markup into prebuilt HTML strings, so
the server skips most of the work of creating JSX objects on each request. Set
jsx to "precompile":
{
"compilerOptions": {
"jsx": "precompile",
"jsxImportSource": "@hono/hono/jsx"
},
"imports": {
"@hono/hono": "jsr:@hono/hono@^4"
}
}The JSX library has to support it: its jsx-runtime must export the
jsxTemplate, jsxAttr and jsxEscape helpers the transform calls. Hono's and
satz's do.
Configure JSX per file with pragmas
When most of your project uses one setup but a single file needs another, set
the import source for that file with a pragma comment instead of changing
ende.json. This is common for standalone scripts that have no project
configuration. The pragma must appear in the file's leading comments:
/** @jsxImportSource jsr:@hono/hono@^4/jsx */
export function App() {
return <h1>Hello from a one-off script</h1>;
}If the library does not ship its own types, point Ende at a separate types
module with @jsxImportSourceTypes. The same jsxImportSourceTypes is also
available as a compiler option in ende.json.
Transform options reference
The jsx compiler option selects how Ende compiles JSX. Set it in ende.json
under compilerOptions:
jsx value |
What it does |
|---|---|
"react-jsx" |
Automatic runtime. Inserts imports from <jsxImportSource>/jsx-runtime. Recommended. |
"react-jsxdev" |
Automatic runtime with debug info (file, line, column) added to each node. Development only. |
"precompile" |
Optimized server-rendering transform. Fastest for SSR. |
"react" |
Legacy classic transform. Compiles to React.createElement; needs React in scope. |
Related settings:
jsxImportSource: the module JSX imports come from (@hono/hono/jsx,@ende/satz). Ende appends/jsx-runtimeautomatically.jsxImportSourceTypes: a types module to use when the JSX library ships none.jsxPrecompileSkipElements: tag names to leave out of the precompile transform.
For the full set of TypeScript compiler options Ende supports, see the
ende.json reference and
Configuring TypeScript.
Next steps
- HTTP server: serve the HTML your components render.
- Configuration file: every
ende.jsonfield, includingcompilerOptions.