npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@ssrx/renderer

v0.5.1

Published

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

Downloads

1,458

Readme

@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.

Usage

@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

Plugins can:

  • Hook into the client and server rendering in a standardized way
  • Extend a typesafe 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;
    };
  };
};

Directory

| Package | Release Notes | | ---------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | | @ssrx/renderer | @ssrx/renderer version | | @ssrx/react | @ssrx/react version | | @ssrx/remix | @ssrx/remix version | | @ssrx/solid | @ssrx/solid version | | @ssrx/streaming | @ssrx/streaming version | | @ssrx/trpc-react-query | @ssrx/trpc-react-query version | | @ssrx/plugin-react-router | @ssrx/plugin-react-router version | | @ssrx/plugin-solid-router | @ssrx/plugin-solid-router version | | @ssrx/plugin-tanstack-query | @ssrx/plugin-tanstack-query version | | @ssrx/plugin-tanstack-router | @ssrx/plugin-tanstack-router version | | @ssrx/plugin-trpc-react | @ssrx/plugin-trpc-react version | | @ssrx/plugin-unhead | @ssrx/plugin-unhead version |