
Research
Security News
The Landscape of Malicious Open Source Packages: 2025 Mid‑Year Threat Report
A look at the top trends in how threat actors are weaponizing open source packages to deliver malware and persist across the software supply chain.
@ssrx/renderer
Advanced tools
The SSRx renderer establishes some patterns to hook into the lifecycle of streaming SSR apps in a framework/library agnostic way. It is client and server framework agnostic, so long as the server runtime supports web streams and AsyncLocalStorage (node 18
@ssrx/renderer
The SSRx renderer establishes some patterns to hook into the lifecycle of streaming SSR apps in a framework/library agnostic way. It is client and server framework agnostic, so long as the server runtime supports web streams and AsyncLocalStorage (node 18+, bun, deno, cloudflare, vercel, etc). A handful of renderer plugins for common libraries are maintained in this repo.
See the react-router-kitchen-sink and remix-vite examples for a look at how everything can work together in practice.
@ssrx/renderer
exports a createApp
function that allows you to compose all the pieces necessary to render a SSR
streamed application.
An example with React (Solid works almost exactly the same):
// In this case we're using the `react` renderer, which simply wraps @ssrx/renderer with a react specific stream function
import { createApp } from '@ssrx/react';
import { assetsPlugin } from '@ssrx/renderer/assets';
export const { clientHandler, serverHandler, ctx } = createApp({
// Usually a router plugin will provide the appRenderer, but you can always provide your own if needed
appRenderer:
({ req }) =>
() =>
<div>My App</div>,
plugins: [
// If you are also using `@ssrx/vite`, this plugin automatically injects js/css assets into your html stream
assetsPlugin(),
// ... your plugins, or 3rd party plugins. More on the plugin shape below
],
});
import { hydrateRoot } from 'react-dom/client';
import { clientHandler } from './app.tsx';
void hydrate();
async function hydrate() {
const app = await clientHandler();
hydrateRoot(document, app());
}
import { serverHandler } from '~/app.tsx';
export default {
fetch(req: Request) {
const { stream, statusCode } = await serverHandler({ req });
return new Response(stream, { status: statusCode(), headers: { 'Content-Type': 'text/html' } });
},
};
With the above steps you get a streaming react app with support for lazy asset preloading. However, plugins are where
@ssrx/renderer
really shines.
Plugins can:
ctx
object that is made available on the client and the server, even outside of the rendering tree
(for example in router loader functions). This is accomplished via a proxy that is exposed on the window in the client
context, and via async local storage on the server.Plugin Shape
See the renderer types file for the full plugin signature.
export type RenderPlugin = {
id: string;
/**
* Called once per request.
*/
hooksForReq: (props: {
req: Request;
meta?: SSRx.ReqMeta;
renderProps: SSRx.RenderProps;
ctx: Record<string, unknown>;
}) => {
// Called on the client and the server
common?: {
/**
* Extend the app ctx object with additional properties. Consider this "external" context - it is made available
* to the end application on the server and the client.
*/
extendAppCtx?: () => Record<string, unknown>;
/**
* Wrap the app component with a higher-order component. This is useful for wrapping the app with providers, etc.
*/
wrapApp?: (props: { children: () => Config['jsxElement'] }) => Config['jsxElement'];
/**
* Render the final inner-most app component. Only one plugin may do this - usually a routing plugin.
*/
renderApp?: () => (() => Config['jsxElement']) | Promise<() => Config['jsxElement']>;
};
// Only called on the server
server?: {
/**
* Return a string to emit some HTML into the SSR stream just before the document's closing </head> tag.
*
* Triggers once per request.
*/
emitToDocumentHead?: Promise<string | undefined> | string | undefined;
/**
* Return a string to emit into the SSR stream just before the rendering
* framework (react, solid, etc) emits a chunk of the page.
*
* Triggers one or more times per request.
*/
emitBeforeStreamChunk?: Promise<string | undefined> | string | undefined;
/**
* Return a string to emit some HTML to the document body, after the client renderer's first flush.
*
* Triggers once per request.
*/
emitToDocumentBody?: Promise<string | undefined> | string | undefined;
/**
* Runs when the stream is done processing.
*/
onStreamComplete?: Promise<void> | void;
};
};
};
FAQs
The SSRx renderer establishes some patterns to hook into the lifecycle of streaming SSR apps in a framework/library agnostic way. It is client and server framework agnostic, so long as the server runtime supports web streams and AsyncLocalStorage (node 18
The npm package @ssrx/renderer receives a total of 680 weekly downloads. As such, @ssrx/renderer popularity was classified as not popular.
We found that @ssrx/renderer demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
A look at the top trends in how threat actors are weaponizing open source packages to deliver malware and persist across the software supply chain.
Security News
ESLint now supports HTML linting with 48 new rules, expanding its language plugin system to cover more of the modern web development stack.
Security News
CISA is discontinuing official RSS support for KEV and cybersecurity alerts, shifting updates to email and social media, disrupting automation workflows.