frontarm / create-universal-react-app

Configuration-free SSR for Create React App.
MIT License
126 stars 1 forks source link

Switching to renderToNodeStream reduces TTFB by 50% #4

Closed DB-Alex closed 4 years ago

DB-Alex commented 4 years ago

I was just experimenting with renderToNodeStream in combination with CURA after reading this article: https://medium.com/expedia-group-tech/profiling-react-server-side-rendering-to-free-the-node-js-event-loop-7f0fe455a901

After changing the CURA setup from renderToString to renderToNodeStream my TTFB dropped by 50% (see attachments). So i thought this is nice to share with you @jamesknelson, also it would be nice to hear your thoughts about my new setup inside index.node.js, maybe I need to add error throwing?

Old setup:

let body = renderToString(
            sheets.collect(
                <NaviHelmetProvider
                    context={helmetContext}
                    canUseDOM={false}
                >
                    <NaviProvider navigation={navigation}>
                        <ThemeProvider theme={theme}>
                            <CssBaseline />
                            <View />
                        </ThemeProvider>
                    </NaviProvider>
                </NaviHelmetProvider>,
            ),
        );
Screenshot 2019-10-08 at 12 18 36

New setup:

let body = [];

        await new Promise((resolve, reject) => {
            let bodyStream = renderToNodeStream(
                sheets.collect(
                    <NaviHelmetProvider
                        context={helmetContext}
                        canUseDOM={false}
                    >
                        <NaviProvider navigation={navigation}>
                            <ThemeProvider theme={theme}>
                                <CssBaseline />
                                <View />
                            </ThemeProvider>
                        </NaviProvider>
                    </NaviHelmetProvider>,
                ),
            );
            bodyStream.on('data', (chunk) => {
                body.push(chunk.toString());
            });
            bodyStream.on('error', (error) => {
                reject(error);
            });
            bodyStream.on('end', () => {
                resolve(body.join(''));
            });
        });
Screenshot 2019-10-08 at 12 19 23
jamesknelson commented 4 years ago

This is definitely an interesting possibility. I've give it a try before, but one of the issues I ran into was that if there's an error during rendering, you can't change the header/status, as the status has already been sent near the top of the response. I'm not exactly sure how to deal with this, so I just stuck with renderToString in the template.

DB-Alex commented 4 years ago

Thanks for your update!