Skip to content

RFC: implement multi-head SSR #241

@wmertens

Description

@wmertens

Champion

@wmertens

What's the motivation for this proposal?

Problems you are trying to solve:

  • discovering Promises/generators during render

Goals you are trying to achieve:

  • as early as possible
  • Out-of-order streaming enablement

Proposed Solution / Feature

What do you propose?

Right now the SSR blocks when it needs to render Promise or while a generator is running.

Instead of having a single writer connected to the response, have a stack of writers attached to the current writer, and buffer the writes.

E.g. we start with writer0 which is connected to the response object. We run <Root/> and get <html><head/><body><App /></body></html>
We can already stream "<html><head/><body>"
Next we run <App /> and get <header/><main>{contentPromise}</main><Footer />
We can stream "<header/><main>" but we have to await contentPromise before we can continue streaming.

At this point, we start a new writer which buffers to memory, push it on writer0.next[], write "</main>" to it and run <Footer />.

If contentPromise turns out to have more promises inside, those will create more writers that are pushed on writer0.next[]`.

When writer0 has nothing left to write, it recursively pop()s its .next[], flushing it to the response.

This does mean that we have to pass the writer while handling JSX, we can't use container.writer.

SSRStreamBlock

Sometimes, we need to be sure that everything above the current component has been streamed, because we're gathering data. In that case, we should output <SSRStreamBlock />, which will block the current writer until it's the one streaming to the response.

Conclusion

Using this method, we can ensure that we discover blocking Promises as early as possible, reducing the time needed to SSR the page.

Right now, Promises are serially discovered and run, and with this technique they'll all be parallel, except for waterfalls where Promises return nested Promises.

As for Out-of-Order-Streaming, using this technique will already allow waiting for like 50ms before outputting an OoOS placeholder, without actually delaying the SSR.

PRs/ Links / References

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    Status

    In Progress (STAGE 2)

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions