Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Server Component response must be flushed inline with SSR #30994

Closed
devknoll opened this issue Nov 4, 2021 · 1 comment
Closed

Server Component response must be flushed inline with SSR #30994

devknoll opened this issue Nov 4, 2021 · 1 comment
Assignees

Comments

@devknoll
Copy link
Contributor

devknoll commented Nov 4, 2021

In order to properly hydrate the SSR'd Server Component tree, we have to flush the Server Component data along with it, at least for now. To do that, we should introduce a ServerRoot.client component:

export function ServerRoot({ req, bootstrap }) {
  const id = useId()
  const res = useServerResponse(id, req, bootstrap)
  return res.readRoot()
}

Here, req would be some serialized representation of a Server Component request (such as a URL). useServerResponse would have a different implementation based on whether it was being used for SSR or by the browser. For SSR, that might look like:

export function createSSRHook() {
  const rscCache = new Map()
  return (id, req, bootstrap) => {
    let entry = rscCache.get(id)
    if (!entry) {
      const [renderStream, forwardStream] = renderFlight(req).tee()
      entry = createFromReadableStream(renderStream)
      rscCache.set(id, entry)

      if (bootstrap) {
        res.write(renderToString(
          <script dangerouslySetInnerHTML={{ __html: `(self.__next_s=self.__next_s||[]).push(${JSON.stringify([0, id])})` }} />
        ))
      }

      forEachStream(forwardStream, chunk => {
        res.write(renderToString(
          <script dangerouslySetInnerHTML={{ __html: `(self.__next_s=self.__next_s||[]).push(${JSON.stringify([1, id, chunk])})` }} />
        ))
      })
    }
    return entry
  }
}

For SSR, we would render a tree like:

<ServerRoot req={rscReq} bootstrap={true} />

Similarly, the next/client would install a handler for window.__next_s calls when it loads, and use it to manage a global map of IDs to ReadableStreams and enqueue them to be consumed by the browser implementation of useServerResponse. That implementation would consume the streams from this global map, or kick off a new request if the value is not present.

The bootstrap part replaces __NEXT_DATA__, which, by itself, isn't suitable for streaming rendering. Instead, it just tells the client which stream corresponds to the root Server Component, and any initialization needed (such as the webpack asset prefix).

@shuding shuding self-assigned this Nov 9, 2021
kodiakhq bot pushed a commit that referenced this issue Nov 15, 2021
Initial step to refactor the rendering logic by decoupling the handler and renderer:
1. Delegate Flight rendering to server/render
2. Reuse the piper glue code for both Fizz and Flight streams
3. Add buffering for ReadableStream

In 1), this PR also makes sure that gSSP/gSP are correctly executed before the Flight stream and `pageProps` and `router` are correctly delivered to the component.

Related to #30994.

## Bug

- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Errors have helpful link attached, see `contributing.md`

## Feature

- [ ] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR.
- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Documentation added
- [ ] Telemetry added. In case of a feature if it's used or not.
- [ ] Errors have helpful link attached, see `contributing.md`

## Documentation / Examples

- [ ] Make sure the linting passes by running `yarn lint`
kodiakhq bot pushed a commit that referenced this issue Dec 13, 2021
This PR implements the basic inline embedded server response data (#30994) for RSC, as well as partial hydration (#31338) for RSC and React 18 SSR streaming.

For #30994, `renderTargetSuffix` is passed to the `bodyResult` resolver so the stream can inject corresponding hydration scripts and the closing body tag at the correct time. The expected behavior should be _prefix_, _body shell_, _suffix scripts_, _stream and inlined data_, _close body_.

For #31338, we have to force turn on `disableOptimizedLoading` when `concurrentFeatures` is enabled to opt-out of deferred script tags.

## Bug

- [x] Related issues linked using `fixes #number`
- [x] Integration tests added
- [ ] Errors have helpful link attached, see `contributing.md`

## Feature

- [x] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR.
- [x] Related issues linked using `fixes #number`
- [x] Integration tests added
- [ ] Documentation added
- [ ] Telemetry added. In case of a feature if it's used or not.
- [ ] Errors have helpful link attached, see `contributing.md`

## Documentation / Examples

- [ ] Make sure the linting passes by running `yarn lint`
@shuding shuding closed this as completed Dec 13, 2021
cdierkens pushed a commit to cdierkens/next.js that referenced this issue Dec 20, 2021
This PR implements the basic inline embedded server response data (vercel#30994) for RSC, as well as partial hydration (vercel#31338) for RSC and React 18 SSR streaming.

For vercel#30994, `renderTargetSuffix` is passed to the `bodyResult` resolver so the stream can inject corresponding hydration scripts and the closing body tag at the correct time. The expected behavior should be _prefix_, _body shell_, _suffix scripts_, _stream and inlined data_, _close body_.

For vercel#31338, we have to force turn on `disableOptimizedLoading` when `concurrentFeatures` is enabled to opt-out of deferred script tags.

## Bug

- [x] Related issues linked using `fixes #number`
- [x] Integration tests added
- [ ] Errors have helpful link attached, see `contributing.md`

## Feature

- [x] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR.
- [x] Related issues linked using `fixes #number`
- [x] Integration tests added
- [ ] Documentation added
- [ ] Telemetry added. In case of a feature if it's used or not.
- [ ] Errors have helpful link attached, see `contributing.md`

## Documentation / Examples

- [ ] Make sure the linting passes by running `yarn lint`
@balazsorban44
Copy link
Member

This issue has been automatically locked due to no recent activity. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.

@vercel vercel locked as resolved and limited conversation to collaborators Jan 27, 2022
This issue was closed.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants