@pyra-js/adapter-react
v0.30.10
Published
React adapter for Pyra.js - SSR, hydration, and JSX compilation
Readme
@pyra-js/adapter-react
React adapter for Pyra.js. Wires React 18/19 into the Pyra SSR pipeline, server-side rendering with renderToString(), client-side hydration with hydrateRoot(), layout wrapping, and an <Image> component for responsive image optimization.
npm install @pyra-js/adapter-react react react-dom
# or
pnpm add @pyra-js/adapter-react react react-domPeer dependencies: react ^18.0.0 || ^19.0.0 and react-dom ^18.0.0 || ^19.0.0
Setup
Pass the adapter to your Pyra config:
// pyra.config.ts
import { defineConfig } from '@pyra-js/cli';
import { createReactAdapter } from '@pyra-js/adapter-react';
export default defineConfig({
adapter: createReactAdapter(),
routesDir: 'src/routes',
});That's all the configuration required. The CLI (pyra dev, pyra build, pyra start) picks up the adapter automatically.
Writing Pages
Create page.tsx files anywhere under src/routes/. The file's location determines the URL.
// src/routes/blog/[slug]/page.tsx
export async function load(context) {
const post = await fetchPost(context.params.slug);
return { post };
}
export default function BlogPost({ post, params }) {
return (
<article>
<h1>{post.title}</h1>
<p>{post.body}</p>
</article>
);
}load(context)- runs on the server before rendering. Whatever it returns is spread into the component's props. Routeparamsare always included automatically.- default export - the React component that gets server-rendered and then hydrated on the client.
See the SSR and Data Loading docs for a full reference.
Layouts
Create layout.tsx files to wrap pages with shared structure. Layouts nest automatically based on directory depth.
// src/routes/layout.tsx
import { Link } from '@pyra-js/adapter-react';
export default function RootLayout({ children }) {
return (
<div>
<nav>
<Link href="/">Home</Link>
<Link href="/about">About</Link>
</nav>
<main>{children}</main>
</div>
);
}Every page in the app is rendered inside this layout. For section-specific layouts (e.g., a dashboard sidebar), add a layout.tsx in the relevant subdirectory.
See the Layouts docs for nesting, route groups, and more.
Static Pages (SSG)
Export prerender = true to render the page to a static HTML file at build time:
// src/routes/about/page.tsx
export const prerender = true;
export default function About() {
return <div><h1>About Us</h1></div>;
}For dynamic routes, export a prerender object with a paths() function:
export const prerender = {
paths() {
return [
{ slug: 'hello-world' },
{ slug: 'getting-started' },
];
},
};How SSR Works
When a request comes in, Pyra calls into the adapter through the PyraAdapter interface:
renderToHTML(component, data, context)- the adapter receives the imported page component, the data returned byload(), and aRenderContextwith layouts. It callsrenderToString()and returns the HTML string.getHydrationScript(clientPath, data, layoutClientPaths)- generates the inline<script type="module">that callshydrateRoot()on the client.getDocumentShell(appContainerId)- returns the base HTML document with<!--pyra-head-->and<!--pyra-outlet-->markers that Pyra replaces with the rendered content and asset tags.
The adapter wraps the page in any layouts before calling renderToString(), building the element tree from innermost (page) to outermost (root layout) using createElement.
Core never imports React - the adapter boundary in PyraAdapter keeps the UI framework completely isolated.
TypeScript
The package ships full TypeScript declarations. JSX is handled by esbuild with jsx: 'automatic' and jsxImportSource: 'react' - no separate Babel or TSC step is needed.
Add "jsx": "react-jsx" to your project's tsconfig.json for editor support:
{
"compilerOptions": {
"jsx": "react-jsx"
}
}Full Documentation
License
MIT
