main
js 96 lines 2.53 KB
Raw
1 /**
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 *
7 */
8
9 import * as React from 'react';
10 // import {renderToString} from 'react-dom/server';
11 import {renderToPipeableStream} from 'react-dom/server';
12 import App from '../src/App';
13 import {DataProvider} from '../src/data';
14 import {API_DELAY, ABORT_DELAY} from './delays';
15
16 // In a real setup, you'd read it from webpack build stats.
17 let assets = {
18 'main.js': '/main.js',
19 'main.css': '/main.css',
20 };
21
22 module.exports = function render(url, res) {
23 const data = createServerData();
24 // This is how you would wire it up previously:
25 //
26 // res.send(
27 // '<!DOCTYPE html>' +
28 // renderToString(
29 // <DataProvider data={data}>
30 // <App assets={assets} />
31 // </DataProvider>,
32 // )
33 // );
34
35 // The new wiring is a bit more involved.
36 res.socket.on('error', error => {
37 console.error('Fatal', error);
38 });
39 let didError = false;
40 const {pipe, abort} = renderToPipeableStream(
41 <DataProvider data={data}>
42 <App assets={assets} />
43 </DataProvider>,
44 {
45 bootstrapScripts: [assets['main.js']],
46 onAllReady() {
47 // Full completion.
48 // You can use this for SSG or crawlers.
49 },
50 onShellReady() {
51 // If something errored before we started streaming, we set the error code appropriately.
52 res.statusCode = didError ? 500 : 200;
53 res.setHeader('Content-type', 'text/html');
54 pipe(res);
55 },
56 onShellError(x) {
57 // Something errored before we could complete the shell so we emit an alternative shell.
58 res.statusCode = 500;
59 res.send('<!doctype><p>Error</p>');
60 },
61 onError(x) {
62 didError = true;
63 console.error(x);
64 },
65 }
66 );
67 // Abandon and switch to client rendering if enough time passes.
68 // Try lowering this to see the client recover.
69 setTimeout(abort, ABORT_DELAY);
70 };
71
72 // Simulate a delay caused by data fetching.
73 // We fake this because the streaming HTML renderer
74 // is not yet integrated with real data fetching strategies.
75 function createServerData() {
76 let done = false;
77 let promise = null;
78 return {
79 read() {
80 if (done) {
81 return;
82 }
83 if (promise) {
84 throw promise;
85 }
86 promise = new Promise(resolve => {
87 setTimeout(() => {
88 done = true;
89 promise = null;
90 resolve();
91 }, API_DELAY);
92 });
93 throw promise;
94 },
95 };
96 }