Skip to content

Commit 831985a

Browse files
committed
(feat): support SSR out-of-the-box by no-op'ing in Node
- add a `nodeNoop` option that is `true` by default - generally folks do not want to hydrate their store during SSR, so no-op by default and require explicit opt-in to Node hydration - see #6 for discussion (docs): add `nodeNoop` option and section on Node and SSR usage to give more details and note possible gotchas
1 parent 5d6b0e8 commit 831985a

File tree

2 files changed

+22
-3
lines changed

2 files changed

+22
-3
lines changed

README.md

+8
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,17 @@ persist('some', someStore, {
5858
- **jsonify** *bool* Enables serialization as JSON (default: `true`).
5959
- **whitelist** *Array\<string\>* Only these keys will be persisted (defaults to all keys).
6060
- **blacklist** *Array\<string\>* These keys will not be persisted (defaults to all keys).
61+
- **nodeNoop** *bool* Whether this should no-op in a Node environment (default: `true`). See below for more details.
6162

6263
- returns a void Promise
6364

65+
### Node and SSR Usage
66+
67+
To support Server-Side Rendering (SSR) out-of-the-box, `persist` will no-op in a Node environment by default.<br>
68+
Please note that it uses `typeof window === 'undefined'` to check. [`window` is defined in React Native](https://stackoverflow.com/questions/49911424/what-does-the-variable-window-represent-in-react-native), but may not be in test runners and other simulated environments.
69+
70+
If you'd like to hydrate your store in Node (vs. in the browser, which is the standard usage), set `nodeNoop` to `false` and `storage` to a supported provider for Node.
71+
6472
## Examples
6573

6674
None yet, but can take a look at [agilgur5/react-native-manga-reader-app](https://github.com/agilgur5/react-native-manga-reader-app) which uses it in production.

src/index.ts

+14-3
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,25 @@ export interface IOptions {
99
storage?: any,
1010
jsonify?: boolean,
1111
readonly whitelist?: Array<string>,
12-
readonly blacklist?: Array<string>
12+
readonly blacklist?: Array<string>,
13+
nodeNoop?: boolean
1314
}
1415
type StrToAnyMap = {[key: string]: any}
1516

1617
export const persist: IArgs = (name, store, options = {}) => {
17-
let {storage, jsonify, whitelist, blacklist} = options
18+
let {storage, jsonify, whitelist, blacklist, nodeNoop} = options
1819

19-
if (typeof window.localStorage !== 'undefined' && (!storage || storage === window.localStorage)) {
20+
// no-op in node by default to support SSR out-of-the-box
21+
// require explicit opt-in to hydrate server-side
22+
if (!nodeNoop) { nodeNoop = true }
23+
if (nodeNoop && typeof window === 'undefined') { return Promise.resolve() }
24+
25+
// use AsyncLocalStorage by default or if window.localStorage was passed in
26+
if (
27+
typeof window !== 'undefined' &&
28+
typeof window.localStorage !== 'undefined' &&
29+
(!storage || storage === window.localStorage)
30+
) {
2031
storage = AsyncLocalStorage
2132
}
2233
if (!storage) {

0 commit comments

Comments
 (0)