main
js 78 lines 2.13 KB
Raw
1 import React from 'react';
2 import {renderToPipeableStream} from 'react-dom/server';
3 import {Writable} from 'stream';
4
5 import App from '../src/components/App';
6
7 let assets;
8 if (process.env.NODE_ENV === 'development') {
9 // Use the bundle from create-react-app's server in development mode.
10 assets = {
11 'main.js': '/static/js/bundle.js',
12 'main.css': '',
13 };
14 } else {
15 assets = require('../build/asset-manifest.json');
16 }
17
18 class ThrottledWritable extends Writable {
19 constructor(destination) {
20 super();
21 this.destination = destination;
22 this.delay = 10;
23 }
24
25 _write(chunk, encoding, callback) {
26 let o = 0;
27 const write = () => {
28 this.destination.write(chunk.slice(o, o + 100), encoding, x => {
29 o += 100;
30 if (o < chunk.length) {
31 setTimeout(write, this.delay);
32 } else {
33 callback(x);
34 }
35 });
36 };
37 setTimeout(write, this.delay);
38 }
39
40 _final(callback) {
41 setTimeout(() => {
42 this.destination.end(callback);
43 }, this.delay);
44 }
45 }
46
47 export default function render(url, res) {
48 res.socket.on('error', error => {
49 // Log fatal errors
50 console.error('Fatal', error);
51 });
52 let didError = false;
53 const {pipe, abort} = renderToPipeableStream(<App assets={assets} />, {
54 bootstrapScripts: [assets['main.js']],
55 progressiveChunkSize: 1024,
56 onShellReady() {
57 // If something errored before we started streaming, we set the error code appropriately.
58 res.statusCode = didError ? 500 : 200;
59 res.setHeader('Content-type', 'text/html');
60 // To test the actual chunks taking time to load over the network, we throttle
61 // the stream a bit.
62 const throttledResponse = new ThrottledWritable(res);
63 pipe(throttledResponse);
64 },
65 onShellError(x) {
66 // Something errored before we could complete the shell so we emit an alternative shell.
67 res.statusCode = 500;
68 res.send('<!doctype><p>Error</p>');
69 },
70 onError(x) {
71 didError = true;
72 console.error(x);
73 },
74 });
75 // Abandon and switch to client rendering after 5 seconds.
76 // Try lowering this to see the client recover.
77 setTimeout(abort, 5000);
78 }