react-async-ssr
Advanced tools
Comparing version 0.3.1 to 0.4.0
# Changelog | ||
## 0.4.0 | ||
Breaking changes: | ||
* Rename promise abort method from `.abort` to symbol `[ABORT]` | ||
Features: | ||
* `NO_SSR` promise signal to prevent server rendering | ||
Other: | ||
* Trivial refactors | ||
## 0.3.1 | ||
@@ -4,0 +18,0 @@ |
@@ -8,2 +8,7 @@ /* -------------------- | ||
// Imports | ||
const {ABORT} = require('./symbols'); | ||
// Exports | ||
/** | ||
@@ -15,3 +20,3 @@ * Abort promise. | ||
function abort(promise) { | ||
if (typeof promise.abort === 'function') promise.abort(); | ||
if (typeof promise[ABORT] === 'function') promise[ABORT](); | ||
} | ||
@@ -18,0 +23,0 @@ |
@@ -12,4 +12,3 @@ /* -------------------- | ||
TYPE_PROMISE: 'promise', | ||
TYPE_TEXT: 'text', | ||
NO_SSR: 'noSsr' | ||
TYPE_TEXT: 'text' | ||
}; |
@@ -12,3 +12,4 @@ /* -------------------- | ||
// Imports | ||
const {TYPE_SUSPENSE, TYPE_PROMISE, NO_SSR} = require('./constants'), | ||
const {TYPE_SUSPENSE, TYPE_PROMISE} = require('./constants'), | ||
{NO_SSR} = require('./symbols'), | ||
{followAndAbort} = require('./abort'), | ||
@@ -31,6 +32,4 @@ walkTree = require('./walkTree'), | ||
this.handleSuspense(interrupt.element); | ||
} else if (type === TYPE_PROMISE) { | ||
} else { | ||
this.handlePromise(interrupt.element, interrupt.promise); | ||
} else { | ||
throw new Error(`Unexpected interrupt type '${type}'`); | ||
} | ||
@@ -37,0 +36,0 @@ }, |
@@ -9,3 +9,3 @@ /* -------------------- | ||
// Imports | ||
const PartialRenderer = require('./renderer'); | ||
const Renderer = require('./renderer'); | ||
@@ -30,3 +30,3 @@ // Exports | ||
function render(element, makeStaticMarkup) { | ||
const renderer = new PartialRenderer(element, makeStaticMarkup); | ||
const renderer = new Renderer(element, makeStaticMarkup); | ||
@@ -33,0 +33,0 @@ return new Promise((resolve, reject) => { |
@@ -20,3 +20,3 @@ /* -------------------- | ||
const child = { | ||
const node = { | ||
type, | ||
@@ -27,3 +27,3 @@ parent, | ||
parent.children.push(child); | ||
parent.children.push(node); | ||
@@ -35,7 +35,7 @@ // Prevent insertion of '<!-- -->'. | ||
return child; | ||
return node; | ||
}, | ||
createNodeWithStackState(type, frame) { | ||
const child = this.createNode(type); | ||
const node = this.createNode(type); | ||
@@ -53,6 +53,6 @@ // Get current contexts from new Context API | ||
// Record parent suspense node | ||
child.parentSuspense = this.suspenseNode; | ||
node.parentSuspense = this.suspenseNode; | ||
// Record stackState | ||
child.stackState = { | ||
node.stackState = { | ||
context: frame.context, // Contexts from legacy Context API | ||
@@ -65,4 +65,4 @@ contexts, // Contexts from new Context API | ||
return child; | ||
return node; | ||
} | ||
}; |
/* -------------------- | ||
* react-async-ssr module | ||
* PartialRenderer class | ||
* Renderer class | ||
* ------------------*/ | ||
@@ -23,3 +23,3 @@ | ||
// Exports | ||
class PartialRenderer extends ReactDOMServerRenderer { | ||
class Renderer extends ReactDOMServerRenderer { | ||
/** | ||
@@ -110,13 +110,2 @@ * @constructor | ||
done() { | ||
// Finished processing | ||
this.destroy(); | ||
// Convert tree to HTML and callback with result | ||
// NB Do not leak `this` to callback | ||
const out = treeToHtml(this.tree, this.makeStaticMarkup); | ||
const {callback} = this; | ||
callback(null, out); | ||
} | ||
/* | ||
@@ -223,2 +212,17 @@ * If a promise marked no SSR is thrown during render, a Suspense boundary's | ||
/* | ||
* Rendering complete. | ||
* Call callback with HTML output. | ||
*/ | ||
done() { | ||
// Finished processing | ||
this.destroy(); | ||
// Convert tree to HTML and callback with result | ||
// NB Do not leak `this` to callback | ||
const out = treeToHtml(this.tree, this.makeStaticMarkup); | ||
const {callback} = this; | ||
callback(null, out); | ||
} | ||
/** | ||
@@ -255,3 +259,3 @@ * Render has failed. Call callback with error. | ||
* Abort a promise node. | ||
* Mark node as resolved and call promise's `.abort()` method. | ||
* Mark node as resolved and call promise's `[ABORT]()` method. | ||
*/ | ||
@@ -421,4 +425,4 @@ abort(node) { | ||
// Add shim, handle and node methods | ||
Object.assign(PartialRenderer.prototype, shimMethods, handleMethods, nodeMethods); | ||
Object.assign(Renderer.prototype, shimMethods, handleMethods, nodeMethods); | ||
module.exports = PartialRenderer; | ||
module.exports = Renderer; |
{ | ||
"name": "react-async-ssr", | ||
"version": "0.3.1", | ||
"version": "0.4.0", | ||
"description": "Render React Suspense on server", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -151,3 +151,3 @@ [![NPM version](https://img.shields.io/npm/v/react-async-ssr.svg)](https://www.npmjs.com/package/react-async-ssr) | ||
#### Complicated cases | ||
### Complicated cases | ||
@@ -159,3 +159,3 @@ `.renderToStringAsync()` supports: | ||
#### Hydrating the render on client side | ||
### Hydrating the render on client side | ||
@@ -188,8 +188,60 @@ The classic model for SSR is: | ||
#### Aborting unnecessary loading | ||
### Preventing components rendering on server side | ||
It's possible for a lazy component to begin loading, but then its result not to be required, because an enclosing Suspense boundary's fallback gets triggered, and so the original content will not be displayed. | ||
Sometimes you might want to prevent a component rendering on server side. For example, it might be a low-priority part of the page, "below the fold", or a heavy component which will take a long time to load on client side and increase the delay before hydration. | ||
In these cases, if the promise has an `.abort()` method, it will be called. | ||
This module provides a mechanism for that. | ||
The component should throw a promise which has `[NO_SSR]` property set to `true`. | ||
`[NO_SSR]` is a symbol which can be imported from `react-async-ssr/symbols`. | ||
If the promise has this property, the component will not be rendered and the next Suspense boundary above's fallback will be triggered. | ||
```js | ||
const {NO_SSR} = require('react-async-ssr/symbols'); | ||
function LazyNoSSR() { | ||
const promise = new Promise(() => {}); | ||
promise[NO_SSR] = true; | ||
throw promise; | ||
} | ||
function App() { | ||
return ( | ||
<React.Suspense fallback={<div>Loading...</div>}> | ||
<LazyNoSSR/> | ||
</React.Suspense> | ||
); | ||
} | ||
``` | ||
When rendered on server, this will output `<div>Loading...</div>`. | ||
On client side, to ensure no hydration mismatch errors, the component must throw a promise which then resolves to the required component/data, and not render the output synchronously. | ||
### Aborting unnecessary loading | ||
It's possible for a lazy component to begin loading, but then its result not to be required, because an enclosing Suspense boundary's fallback gets triggered. If so the result will not be displayed. | ||
In these cases, if the promise has an `[ABORT]` method, it will be called. | ||
`[ABORT]` is a symbol which can be imported from `react-async-ssr/symbols`. | ||
```js | ||
const {ABORT} = require('react-async-ssr/symbols'); | ||
function AbortableLazy() { | ||
const promise = new Promise( | ||
resolve => /* do some stuff */ | ||
); | ||
promise[ABORT] = () => { | ||
/* this will be called if result of promise will not be rendered */ | ||
}; | ||
throw promise; | ||
} | ||
``` | ||
### Additional notes | ||
@@ -196,0 +248,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
42010
18
899
278
0