Browse recipes

Verify request-scoped server storage

Prove that concurrent server requests do not expose their stored values to one another.

Table of contents

APIs used

render
Serializes Valyrian.js views on the server.
ServerStorage
Provides request-scoped browser-like storage during server rendering.
inline
Bundles build input for server-side tooling.

Run this recipe

Starting project
Start with an empty Node.js project and install Valyrian.js plus the Node types listed in Step 4.
File
Create tsconfig.json, server.tsx and build-server.mjs in the project root.
Run
Run node build-server.mjs and node dist/server.mjs.
Observable result
The terminal prints <main>request-a</main> and <main>request-b</main> from the two concurrent ServerStorage branches.

1. Create tsconfig.json

Use the same automatic TSX compiler settings as the main SSR flow.

json
{
  "compilerOptions": {
    "jsx": "react-jsx",
    "jsxImportSource": "valyrian.js",
    "skipLibCheck": true,
    "types": ["node"]
  }
}

2. Create server.tsx

Each request runs in its own ServerStorage boundary and renders a functional component declared with TSX.

tsx
import { render, ServerStorage } from "valyrian.js/node";

function RequestView({ requestId }: { requestId: string }) {
  return <main>{requestId}</main>;
}

async function renderRequest(requestId: string) {
  return ServerStorage.run(async () => {
    sessionStorage.setItem("requestId", requestId);
    await Promise.resolve();
    const storedId = sessionStorage.getItem("requestId") || "";
    return render(<RequestView requestId={storedId} />);
  });
}

const [first, second] = await Promise.all([
  renderRequest("request-a"),
  renderRequest("request-b"),
]);

console.log(first);
console.log(second);

3. Create build-server.mjs

Compile server.tsx for Node through inline.

js
import 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);

4. Build and render

Build the Node entry and run both concurrent render calls.

bash
npm install valyrian.js@9.1.13
npm install --save-dev @types/node@22.15.3
node build-server.mjs
node dist/server.mjs

Result

Each line contains the value stored by its own concurrent request.

html
<main>request-a</main>
<main>request-b</main>

Continue