Skip to content

Commit da43b5b

Browse files
committed
Updates docs to reflect latest API changes.
1 parent 2f91394 commit da43b5b

File tree

1 file changed

+141
-25
lines changed

1 file changed

+141
-25
lines changed

README.md

Lines changed: 141 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,21 @@ const AsyncProduct = createAsyncComponent({
2020
- [Introduction](#introduction)
2121
- [Usage](#usage)
2222
- [API](#api)
23+
- [createAsyncComponent(config)](#createasynccomponentconfig)
24+
- [withAsyncComponents(element)](#withasynccomponentselement)
25+
- [Examples](#examples)
26+
- [Creating Async Components](#creating-async-components)
27+
- [Simple](#simple)
28+
- [With Loading Component](#with-loading-component)
29+
- [Webpack 1/2 `require.ensure` Code Splitting](#webpack-12-require.ensure-code-splitting)
30+
- [Webpack 2 `import` / `System.import` Code Splitting](#webpack-2-import-system.import-code-splitting)
31+
- [Defer Loading to the Client/Browser](#defer-loading-to-the-clientbrowser)
32+
- [End to End Examples](#end-to-end-examples)
33+
- [Browser Only Application](#browser-only-application)
34+
- [Server Side Rendering Application](#server-side-rendering-application)
35+
- [Important Information for using in Server Side Rendering Applications](#important-information-for-using in-server-side-rendering-applications)
36+
- [SSR AsyncComponent Resolution Process](#ssr-asyncComponent-resolution-process)
37+
- [SSR Performance Optimisation](#ssr-performance-optimisation)
2338
- [Caveats](#caveats)
2439
- [FAQs](#faqs)
2540

@@ -29,7 +44,7 @@ This library is an evolution of [`code-split-component`](). Unlike `code-split-c
2944

3045
## Usage
3146

32-
Firstly, you need to use our helper to allow your application to use asynchronous components in an efficient manner.
47+
Firstly, you need to use our helper, which helps your application use asynchronous components in an efficient manner.
3348

3449
```jsx
3550
import { withAsyncComponents } from 'react-async-component'; // 👈
@@ -97,16 +112,36 @@ Our async Component factory. Config goes in, an async Component comes out.
97112
#### Arguments
98113

99114
- `config` (_Object_) : The configuration object for the async Component. It has the following properties available:
100-
- `resolve` (_Function => Promise<Component>_) :A function that should return a `Promise` that will resolve the Component you wish to be async.
101-
- `defer` (_Boolean_, Optional, default: false) : Only useful for server side rendering applications. If this is set to true then the async component will only be resolved on the client/browser, not the server. I _highly_ recommend that you consider using this value as much as you can. Try to relieve the load on your server and use server side rendering to provide an application shell for your users. They will still get a perceived performance benefit.
115+
- `resolve` (_Function => Promise<Component>_) : A function that should return a `Promise` that will resolve the Component you wish to be async.
116+
- `ssrMode` (_Boolean_, Optional, default: 'render') : Only applies for server side rendering applications. We _highly recommend_ that you read the [SSR Performance Optimisation](#ssr-performance-optimisation) section for more on this configuration property.
102117
- `Loading` (_Component_, Optional, default: null) : A Component to be displayed whilst your async Component is being resolved. It will be provided the same props that will be provided to your resovled async Component.
103118
- `es6Aware` (_Boolean_, Optional, default: true) : If you are using ES2015 modules with default exports (i.e `export default MyComponent`) then you may need your Component resolver to do syntax such as `require('./MyComp').default`. Forgetting the `.default` can cause havoc with hard to debug error messages. To cover your back we will automatically try to resolve a `.default` on the result that is resolved by your Component. If the `.default` exists it will be used, else we will use the original result.
119+
- `name` (_String_, Optional, default: AsyncComponent) : Use this if you would like to name the created async Component, which helps when firing up the React Dev Tools for example.
104120

105121
#### Returns
106122

107123
A React Component.
108124

109-
#### Examples
125+
### `withAsyncComponents(element)`
126+
127+
Decorates your application with the ability to use async Components in an efficient manner. It also manages state storing/rehydrating for server side rendering applications.
128+
129+
#### Arguments
130+
131+
- `app` _React.Element_
132+
The react element representing your application.
133+
134+
#### Returns
135+
136+
A promise that resolves in a `result` object. The `result` object will have the following properties available:
137+
138+
- `appWithAsyncComponents` (_React.Element_) : Your application imbued with the ability to use async Components. ❗️Use this when rendering your app.
139+
- `state` (_Object_) : Only used on the "server" side of server side rendering applications. It represents the state of your async Components (i.e. which ones were rendered) so that the server can feed this information back to the client/browser.
140+
- `STATE_IDENTIFIER` (_String_) : Only used on the "server" side of server side rendering applications. The identifier of the property you should bind the `state` object to on the `window` object.
141+
142+
### Examples
143+
144+
#### Creating Async Components
110145

111146
##### Simple
112147

@@ -159,7 +194,7 @@ const AsyncProduct = createAsyncComponent({
159194
<AsyncProduct productId={1} />
160195
```
161196

162-
#### Defer Loading to the Client/Browser
197+
##### Defer Loading to the Client/Browser
163198

164199
i.e. The component won't be resolved and rendered in a server side rendering execution.
165200

@@ -170,36 +205,45 @@ const AsyncProduct = createAsyncComponent({
170205
});
171206
```
172207

173-
### `withAsyncComponents(element)`
174-
175-
Decorates your application with the ability to use async Components in an efficient manner. It also manages state storing/rehydrating for server side rendering applications.
208+
#### End to End Examples
176209

177-
### Arguments
210+
The below examples show off a full workflow of using the `createAsyncComponent` and `withAsyncComponents` helpers.
178211

179-
- `app` _React.Element_
180-
The react element representing your application.
212+
In all of our examples below we are going to be making use of the `System.import` API supported by Webpack v2 to do asynchronous resolution of our Components and create code split points.
181213

182-
### Returns
214+
##### Browser Only Application
183215

184-
A promise that resolves in a `result` object. The `result` object will have the following properties available:
216+
This is how you would use `react-async-component` in a "browser only" React application.
185217

186-
- `appWithAsyncComponents` (_React.Element_) : Your application imbued with the ability to use async Components. ❗️Use this when rendering your app.
187-
- `state` (_Object_) : Only used on the "server" side of server side rendering applications. It represents the state of your async Components (i.e. which ones were rendered) so that the server can feed this information back to the client/browser.
188-
- `STATE_IDENTIFIER` (_String_) : Only used on the "server" side of server side rendering applications. The identifier of the property you should bind the `state` object to on the `window` object.
218+
Let's imagine a Component that describes your application:
189219

190-
### Examples
220+
__MyApp.js__:
221+
```jsx
222+
// 👇 create an async component
223+
const AsyncHome = createAsyncComponent({
224+
resolve: () => System.import('./components/Home')
225+
});
191226

192-
#### Standard Usage
227+
export default function MyApp() {
228+
return (
229+
<div>
230+
<h1>Hello world!</h1>
231+
<AsyncHome message="💖" />
232+
</div>
233+
);
234+
}
235+
```
193236

194-
This is how you would use this helper in a "normal" React application or on the "client" side of a "server side rendering" React application.
237+
And then a module that renders it:
195238

239+
__client.js__:
196240
```jsx
197241
import React from 'react';
198242
import { render } from 'react-dom';
199243
import { withAsyncComponents } from 'react-async-component'; // 👈
200-
import MyApp from './shared/components/MyApp';
244+
import MyApp from './components/MyApp';
201245

202-
const app = <MyApp />
246+
const app = <MyApp />;
203247

204248
// 👇 run helper on your app.
205249
withAsyncComponents(app)
@@ -217,13 +261,61 @@ withAsyncComponents(app)
217261
});
218262
```
219263

220-
#### Server Side Rendering Usage
264+
##### Server Side Rendering Application
265+
266+
This is how you would use `react-async-component` in a "server side rendering" React application.
221267

222-
When using this helper on the "server" side of your "server side rendering" React application you should do the following.
268+
Let's imagine a Component that describes your application:
223269

224-
> Note: on the "client" side of a "server side rendering" application you can use the helper in the "standard" fashion as detailed in the previous example.
270+
__MyApp.js__:
271+
```jsx
272+
// 👇 create an async component
273+
const AsyncHome = createAsyncComponent({
274+
resolve: () => System.import('./components/Home'),
275+
ssrMode: 'boundary'
276+
});
225277

226-
```js
278+
export default function MyApp() {
279+
return (
280+
<div>
281+
<h1>Hello world!</h1>
282+
<AsyncHome message="💖" />
283+
</div>
284+
);
285+
}
286+
```
287+
288+
And then a module that does the browser/client side rendering:
289+
290+
__client.js__:
291+
```jsx
292+
import React from 'react';
293+
import { render } from 'react-dom';
294+
import { withAsyncComponents } from 'react-async-component'; // 👈
295+
import MyApp from './components/MyApp';
296+
297+
const app = <MyApp />;
298+
299+
// 👇 run helper on your app.
300+
withAsyncComponents(app)
301+
// 👇 and you get back a result object.
302+
.then((result) => {
303+
const {
304+
// ❗️ The result will include a version of your app that is
305+
// rehydrated with the async component state returned by
306+
// the server.
307+
appWithAsyncComponents
308+
} = result;
309+
310+
// Now you can render the app.
311+
render(appWithAsyncComponents, document.getElementById('app'));
312+
});
313+
```
314+
315+
And then an express middleware (you could use any http server of your choice) to do the rendering:
316+
317+
__reactApplicationMiddlware.js__:
318+
```jsx
227319
import React from 'react';
228320
import { withAsyncComponents } from 'react-async-component'; // 👈
229321
import { renderToString } from 'react-dom/server';
@@ -271,6 +363,30 @@ export default function expressMiddleware(req, res, next) {
271363
}
272364
```
273365

366+
### Important Information for using in Server Side Rendering Applications
367+
368+
This library is built to be used within server side rendering (SSR) applications, however, there are some important points/tips we would like to raise with you so that you can design your application components in an efficient and effective manner.
369+
370+
#### SSR AsyncComponent Resolution Process
371+
372+
It is worth us highlighting exactly how we go about resolving and rendering your `AsyncComponent` instances on the server. This knowledge will help you become aware of potential issues with your component implementations as well as how to effectively use our provided configuration properties to create more efficient implementations.
373+
374+
When running `react-async-component` on the server the helper has to walk through your react element tree (depth first i.e. top down) in order to discover all the AsyncComponent instances and resolve them in preparation for when you call the `ReactDOM.renderToString`. As it walks through the tree it has to call the `componentWillMount` method on your Components and then the `render` methods so that it can get back the child react elements for each Component and continue walking down the element tree. When it discovers an `AsyncComponent` instance it will first resolve the Component that it refers to and then it will continue walking down it's child elements (unless you set the configuration for your `AsyncComponent` to not allow this) in order to try and discover any nested `AsyncComponent` instances. It continues doing this until it exhausts your element tree.
375+
376+
Although this operation isn't as expensive as an actual render as we don't generate the DOM it can still be quite wasteful if you have a deep tree. Therefore we have provided a set of configuration values that allow you to massively optimise this process. See the next section below.
377+
378+
#### SSR Performance Optimisation
379+
380+
As discussed in the ["SSR AsyncComponent Resolution Process"](#ssr-asyncComponent-resolution-process) section above it is possible to have an inefficient implementation of your async Components. Therefore we introduced a new configuration object property for the `createAsyncComponent` helper, called `ssrMode`, which provides you with a mechanism to optimise the configuration of your async Component instances.
381+
382+
The `ssrMode` configuration property supports the following values:
383+
384+
- `'render'` (Default0) : In this mode a server side render will parse and resolve your `AsyncComponent` and then continue walking down through the child elements of your resolved `AsyncComponent`. This is the most expensive operation.
385+
- `'defer'` : In this mode your `AsyncComponent` will not be resolved during server side rendering and will defer to the browser/client to resolve and rendering it. This is the cheapest operation as the walking process stops immediately at that branch of your React element tree.
386+
- `'boundary'` : In this mode your `AsyncComponent` will be resolved and rendered on the server, however, the `AsyncComponent` resolution process will not try to walk down this components child elements in order to discover any nested AsyncComponent instances. If there are any nested instances their resolving and rendering will be deferred to the browser/client.
387+
388+
Understand your own applications needs and use the options appropriately . I personally recommend using mostly "defer" and a bit of "boundary". Try to see code splitting as allowing you to server side render an application shell to give the user perceived performance. Of course there will be requirements otherwise (SEO), but try to isolate these components and use a "boundary" as soon as you feel you can.
389+
274390
## Caveats
275391

276392
At the moment there is one known caveat in using this library: it doesn't support React Hot Loader (RHL). You can still use Webpack's standard Hot Module Replacement, however, RHL does not respond nicely to the architecture of `react-async-component`.

0 commit comments

Comments
 (0)