Run a Valyrian.js browser application in Node.js
Import the application already used by the browser and render it to HTML in Node.js.
The example declares `App` once in `app.tsx`. The browser entry mounts it, while `server.tsx` imports the same `App`, compiles the server entry through `inline` and prints the HTML returned by `render`.
Table of contents
Main APIs
- mount
- Starts a Valyrian.js application on a DOM target.
- render
- Executes a Valyrian.js application in Node.js and serializes its rendered output to HTML.
- isNodeJs
- Reports whether Valyrian.js is running in a Node.js environment.
- inline
- Bundles build input for server-side tooling.
1. Export the shared application from app.tsx
tsxexport function App({ path }: { path: string }) {
return (
<main>
<h1>Hello SSR at {path}</h1>
</main>
);
}2. Create browser-entry.tsx and mount the application
tsximport { mount } from "valyrian.js";
import { App } from "./app";
mount("body", <App path={window.location.pathname} />);3. Render the shared application in server.tsx
Import `render` from `valyrian.js/node`, import the existing `App` from `app.tsx` and pass that same application to `render`.
tsximport { render } from "valyrian.js/node";
import { App } from "./app";
const html = render(<App path="/users/42" />);
console.log(html);4. Keep environment-specific behavior inside the shared application with `isNodeJs`
Update `app.tsx` so the shared `App` uses `isNodeJs` to select the branch required by the current environment without creating a server-specific component.
tsximport { isNodeJs } from "valyrian.js";
export function App({ path }: { path: string }) {
const runtime = isNodeJs ? "Node.js" : "browser";
return (
<main>
<h1>Hello SSR at {path}</h1>
<p>Running in {runtime}</p>
</main>
);
}5. Create tsconfig.json
Configure the automatic TSX runtime documented by Valyrian.js.
json{
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "valyrian.js",
"skipLibCheck": true,
"types": ["node"]
}
}6. Create build-server.mjs
Compile server.tsx through inline as a Node ESM module while keeping installed packages external.
jsimport fs from "node:fs";
import { inline } from "valyrian.js/node";
const result = await inline("./server.tsx", {
esbuild: {
format: "esm",
packages: "external",
platform: "node",
},
});
fs.mkdirSync("./dist", { recursive: true });
fs.writeFileSync("./dist/server.mjs", result.raw);7. Build and render
Install Valyrian.js, compile the TSX entry and execute the generated module with Node.
bashnpm install valyrian.js@9.1.13
npm install --save-dev @types/node@22.15.3
node build-server.mjs
node dist/server.mjsResult
Node.js produced this HTML by executing the same `App` module mounted by the browser.
html<main><h1>Hello SSR at /users/42</h1><p>Running in Node.js</p></main>