Skip to content

Commit 03fb3f5

Browse files
committed
Expand README
1 parent f01c2c6 commit 03fb3f5

File tree

1 file changed

+110
-16
lines changed

1 file changed

+110
-16
lines changed

README.md

Lines changed: 110 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,63 @@
1-
# react-ssr-prepass 🌲
1+
# react-ssr-prepass
22

3-
`react-ssr-prepass` is a partial server-side React renderer that is meant
4-
to do a prepass on a React tree and await all suspended promises. It also
5-
accepts a visitor function that can be used to await on custom promises.
3+
<p>
4+
<a href="https://travis-ci.org/kitten/react-ssr-prepass">
5+
<img alt="Build Status" src="https://travis-ci.org/kitten/react-ssr-prepass.svg?branch=master" />
6+
</a>
7+
<a href="https://coveralls.io/github/kitten/react-ssr-prepass?branch=master">
8+
<img alt="Test Coverage" src="https://coveralls.io/repos/github/kitten/react-ssr-prepass/badge.svg?branch=master" />
9+
</a>
10+
<a href="https://npmjs.com/package/react-ssr-prepass">
11+
<img alt="NPM Version" src="https://img.shields.io/npm/v/react-ssr-prepass.svg" />
12+
</a>
13+
</p>
614

7-
It's meant to be used for fetching data before executing `renderToString`
8-
or `renderToNodeStream` and provides a crude way to support suspense during
9-
SSR today. ✨
15+
<p>
16+
<code>react-dom/server</code> does not have support for suspense yet.<br />
17+
<code>react-ssr-prepass</code> offers suspense on the server-side today, until it does. ✨
18+
</p>
1019

11-
> ⚠️ **Disclaimer:** Suspense is unstable and experimental. Its API may change
12-
> and hence this library may break. Awaiting promises is only part of the
13-
> story and does not mean that any data will be rehydrated on the client
14-
> automatically. There be dragons!
20+
`react-ssr-prepass` is a **partial server-side React renderer** that does a prepass
21+
on a React element tree and suspends when it finds thrown promises. It also
22+
accepts a visitor function that can be used to suspend on anything.
23+
24+
You can use it to fetch data before your SSR code calls `renderToString` or
25+
`renderToNodeStream`.
26+
27+
> ⚠️ **Note:** Suspense is unstable and experimental. This library purely
28+
> exists since `react-dom/server` does not support data fetching or suspense
29+
> yet. This two-pass approach should just be used until server-side suspense
30+
> support lands in React.
31+
32+
## The Why & How
33+
34+
It's quite common to have some data that needs to be fetched before
35+
server-side rendering and often it's inconvenient to specifically call
36+
out to random fetch calls to get some data. Instead **Suspense**
37+
offers a practical way to automatically fetch some required data,
38+
but is currently only supported in client-side React.
39+
40+
`react-ssr-prepass` offers a solution by being a "prepass" function
41+
that walks a React element tree and executing suspense. It finds all
42+
thrown promises (a custom visitor can also be provided) and waits for
43+
those promises to resolve before continuing to walk that particular
44+
suspended subtree. Hence, it attempts to offer a practical way to
45+
use suspense and complex data fetching logic today.
46+
47+
A two-pass React render is already quite common for in other libraries
48+
that do implement data fetching. This has however become quite impractical.
49+
While it was trivial to previously implement a primitive React renderer,
50+
these days a lot more moving parts are involved to make such a renderer
51+
correct and stable. This is why some implementations now simply rely
52+
on calling `renderToStaticMarkup` repeatedly.
53+
54+
`react-ssr-prepass` on the other hand is a custom implementation
55+
of a React renderer. It attempts to stay true and correct to the
56+
React implementation by:
57+
58+
- Mirroring some of the implementation of `ReactPartialRenderer`
59+
- Leaning on React elements' symbols from `react-is`
60+
- Providing only the simplest support for suspense
1561

1662
## Quick Start Guide
1763

@@ -40,14 +86,62 @@ const renderApp = async App => {
4086
}
4187
```
4288

43-
You should also be aware that `react-ssr-prepass` does not handle any
89+
Additionally you can also pass a "visitor function" as your second argument.
90+
This function is called for every React class or function element that is
91+
encountered.
92+
93+
```js
94+
ssrPrepass(<App />, (element, instance) => {
95+
if (element.type === SomeData) {
96+
return fetchData()
97+
} else if (instance && instance.fetchData) {
98+
return instance.fetchData()
99+
}
100+
})
101+
```
102+
103+
The first argument of the visitor is the React element. The second is
104+
the instance of a class component or undefined. When you return
105+
a promise from this function `react-ssr-prepass` will suspend before
106+
rendering this element.
107+
108+
You should be aware that `react-ssr-prepass` does not handle any
44109
data rehydration. In most cases it's fine to collect data from your cache
45110
or store after running `ssrPrepass`, turn it into JSON, and send it
46111
down in your HTML result.
47112

113+
## Examples & Recipes
114+
115+
### Usage with `react-apollo`
116+
117+
Instead of using `react-apollo`'s own `getDataFromTree` function, `react-ssr-prepass`
118+
can be used instead. For this to work, we will have to write a visitor function
119+
that knows how to suspend on `react-apollo`'s `Query` component.
120+
121+
Luckily this is quite simple, since all we need to do is call the `fetchData`
122+
method on the `Query` component's instance.
123+
124+
```js
125+
ssrPrepass(<App />, (_element, instance) => {
126+
if (instance !== undefined && typeof instance.fetchData === 'function') {
127+
return instance.fetchData()
128+
}
129+
})
130+
```
131+
132+
Since we're now calling `fetchData` when it exists, which returns a `Promise`
133+
already, `ssrPrepass` will suspend on `<Query>` components.
134+
135+
[More information can be found in Apollo's own docs](https://www.apollographql.com/docs/react/features/server-side-rendering.html#getDataFromTree)
136+
48137
## Prior Art
49138

50-
This library is mostly based on `react-dom`'s `ReactPartialRenderer`
51-
implementation. Its API and purpose is based on `react-apollo`'s
52-
`getDataFromTree` function and hence it's also a successor to
53-
`react-tree-walker`.
139+
This library is (luckily) not a reimplementation from scratch of
140+
React's server-side rendering. Instead it's mostly based on
141+
React's own server-side rendering logic that resides in its
142+
[`ReactPartialRenderer`](https://github.com/facebook/react/blob/13645d2/packages/react-dom/src/server/ReactPartialRenderer.js).
143+
144+
The approach of doing an initial "data fetching pass" is inspired by:
145+
146+
- [`react-apollo`'s `getDataFromTree`](https://github.com/apollographql/react-apollo/blob/master/src/getDataFromTree.ts)
147+
- [`react-tree-walker`](https://github.com/ctrlplusb/react-tree-walker)

0 commit comments

Comments
 (0)