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

@zen_flow/react-ssr-prepass

v1.1.2-next-with-gqless-example-2

Published

A custom partial React SSR renderer for prefetching and suspense

Downloads

2

Readme

react-ssr-prepass

react-ssr-prepass is a partial server-side React renderer that does a prepass on a React element tree and suspends when it finds thrown promises. It also accepts a visitor function that can be used to suspend on anything.

You can use it to fetch data before your SSR code calls renderToString or renderToNodeStream.

⚠️ Note: Suspense is unstable and experimental. This library purely exists since react-dom/server does not support data fetching or suspense yet. This two-pass approach should just be used until server-side suspense support lands in React.

The Why & How

It's quite common to have some data that needs to be fetched before server-side rendering and often it's inconvenient to specifically call out to random fetch calls to get some data. Instead Suspense offers a practical way to automatically fetch some required data, but is currently only supported in client-side React.

react-ssr-prepass offers a solution by being a "prepass" function that walks a React element tree and executing suspense. It finds all thrown promises (a custom visitor can also be provided) and waits for those promises to resolve before continuing to walk that particular suspended subtree. Hence, it attempts to offer a practical way to use suspense and complex data fetching logic today.

A two-pass React render is already quite common for in other libraries that do implement data fetching. This has however become quite impractical. While it was trivial to previously implement a primitive React renderer, these days a lot more moving parts are involved to make such a renderer correct and stable. This is why some implementations now simply rely on calling renderToStaticMarkup repeatedly.

react-ssr-prepass on the other hand is a custom implementation of a React renderer. It attempts to stay true and correct to the React implementation by:

  • Mirroring some of the implementation of ReactPartialRenderer
  • Leaning on React elements' symbols from react-is
  • Providing only the simplest support for suspense

Quick Start Guide

First install react-ssr-prepass alongside react and react-dom:

yarn add react-ssr-prepass
# or
npm install --save react-ssr-prepass

In your SSR code you may now add it in front of your usual renderToString or renderToNodeStream code:

import { createElement } from 'react'
import { renderToString } from 'react-dom/server'

import ssrPrepass from 'react-ssr-prepass'

const renderApp = async App => {
  const element = createElement(App)
  await ssrPrepass(element)

  return renderToString(element)
}

Additionally you can also pass a "visitor function" as your second argument. This function is called for every React class or function element that is encountered.

ssrPrepass(<App />, (element, instance) => {
  if (element.type === SomeData) {
    return fetchData()
  } else if (instance && instance.fetchData) {
    return instance.fetchData()
  }
})

The first argument of the visitor is the React element. The second is the instance of a class component or undefined. When you return a promise from this function react-ssr-prepass will suspend before rendering this element.

You should be aware that react-ssr-prepass does not handle any data rehydration. In most cases it's fine to collect data from your cache or store after running ssrPrepass, turn it into JSON, and send it down in your HTML result.

Examples & Recipes

Usage with react-apollo

Instead of using react-apollo's own getDataFromTree function, react-ssr-prepass can be used instead. For this to work, we will have to write a visitor function that knows how to suspend on react-apollo's Query component.

Luckily this is quite simple, since all we need to do is call the fetchData method on the Query component's instance.

ssrPrepass(<App />, (_element, instance) => {
  if (instance !== undefined && typeof instance.fetchData === 'function') {
    return instance.fetchData()
  }
})

Since we're now calling fetchData when it exists, which returns a Promise already, ssrPrepass will suspend on <Query> components.

More information can be found in Apollo's own docs

Prior Art

This library is (luckily) not a reimplementation from scratch of React's server-side rendering. Instead it's mostly based on React's own server-side rendering logic that resides in its ReactPartialRenderer.

The approach of doing an initial "data fetching pass" is inspired by:

Maintenance Status

Experimental: This project is quite new. We're not sure what our ongoing maintenance plan for this project will be. Bug reports, feature requests and pull requests are welcome. If you like this project, let us know!