Skip to content

Commit

Permalink
Render resolved streaming content for static render result (#35221)
Browse files Browse the repository at this point in the history
* Fix the static streaming render result isn't the resolved streaming rendering content (resolve suspense)
* Update readable stream polyfill to fit the w3c standard
  • Loading branch information
huozhi committed Mar 10, 2022
1 parent 7ce5d3f commit 088354d
Show file tree
Hide file tree
Showing 7 changed files with 40 additions and 30 deletions.
1 change: 0 additions & 1 deletion packages/next/server/web-server.ts
Expand Up @@ -131,7 +131,6 @@ export default class NextWebServer extends BaseServer {
query,
{
...renderOpts,
// supportsDynamicHTML: true,
disableOptimizedLoading: true,
runtime: 'edge',
}
Expand Down
25 changes: 19 additions & 6 deletions packages/next/server/web/sandbox/readable-stream.ts
Expand Up @@ -39,17 +39,17 @@ class ReadableStream<T> {

const pull = () => {
if (opts.pull) {
if (!pullPromise) {
const shouldPull =
controller.desiredSize !== null && controller.desiredSize > 0
if (!pullPromise && shouldPull) {
pullPromise = Promise.resolve().then(() => {
pullPromise = 0
opts.pull!(controller)
})
return pullPromise
}
}
}

if (opts.start) {
opts.start(controller)
return Promise.resolve()
}

if (opts.cancel) {
Expand All @@ -59,7 +59,20 @@ class ReadableStream<T> {
}
}

pull()
function registerPull() {
const getReader = readable.getReader.bind(readable)
readable.getReader = () => {
pull()
return getReader()
}
}

const started = opts.start && opts.start(controller)
if (started && typeof started.then === 'function') {
started.then(() => registerPull())
} else {
registerPull()
}

return readable
}
Expand Down
Expand Up @@ -54,4 +54,13 @@ export default async function basic(context, { env }) {
const html = await renderViaHTTP(context.appPort, '/err/suspense')
expect(html).toContain('error-fallback')
})

it('should support React.lazy and dynamic imports', async () => {
const html = await renderViaHTTP(context.appPort, '/dynamic-imports')
expect(html).toContain('foo.client')

const browser = await webdriver(context.appPort, '/dynamic-imports')
const content = await browser.eval(`window.document.body.innerText`)
expect(content).toMatchInlineSnapshot('"foo.client"')
})
}
Expand Up @@ -2,7 +2,6 @@

import { join } from 'path'
import fs from 'fs-extra'
import webdriver from 'next-webdriver'

import { fetchViaHTTP, findPort, killApp, renderViaHTTP } from 'next-test-utils'

Expand Down Expand Up @@ -146,11 +145,6 @@ describe('Edge runtime - prod', () => {
expect(content.clientInfo).not.toContainEqual([['/404', true]])
})

it('should support React.lazy and dynamic imports', async () => {
const html = await renderViaHTTP(context.appPort, '/dynamic-imports')
expect(html).toContain('foo.client')
})

const options = { runtime: 'edge', env: 'prod' }
basic(context, options)
streaming(context, options)
Expand All @@ -171,15 +165,6 @@ describe('Edge runtime - dev', () => {
await killApp(context.server)
})

it('should support React.lazy and dynamic imports', async () => {
const html = await renderViaHTTP(context.appPort, '/dynamic-imports')
expect(html).toContain('loading...')

const browser = await webdriver(context.appPort, '/dynamic-imports')
const content = await browser.eval(`window.document.body.innerText`)
expect(content).toMatchInlineSnapshot('"foo.client"')
})

it('should have content-type and content-encoding headers', async () => {
const res = await fetchViaHTTP(context.appPort, '/')
expect(res.headers.get('content-type')).toBe('text/html; charset=utf-8')
Expand Down
@@ -1,16 +1,9 @@
/* eslint-env jest */
import webdriver from 'next-webdriver'
import cheerio from 'cheerio'
import { renderViaHTTP, check } from 'next-test-utils'
import { join } from 'path'
import fs from 'fs-extra'

import { distDir } from './utils'

function getNodeBySelector(html, selector) {
const $ = cheerio.load(html)
return $(selector)
}
import { distDir, getNodeBySelector } from './utils'

export default function (context, { runtime, env }) {
it('should render server components correctly', async () => {
Expand Down
@@ -1,6 +1,7 @@
/* eslint-env jest */
import webdriver from 'next-webdriver'
import { fetchViaHTTP, waitFor } from 'next-test-utils'
import { getNodeBySelector } from './utils'

async function resolveStreamResponse(response, onData) {
let result = ''
Expand Down Expand Up @@ -218,6 +219,10 @@ export default function (context, { env, runtime }) {
flushCount++
})
expect(flushCount).toBe(1)
const html = await res1.text()
const body = await getNodeBySelector(html, '#__next')
// Resolve data instead of fallback
expect(body.text()).toBe('next_streaming_data')

if (runtime === 'nodejs') {
expect(res1.headers.get('etag')).toBeDefined()
Expand Down
Expand Up @@ -5,6 +5,7 @@ import {
nextBuild as _nextBuild,
nextStart as _nextStart,
} from 'next-test-utils'
import cheerio from 'cheerio'

const nodeArgs = ['-r', join(__dirname, '../../react-18/test/require-hook.js')]

Expand Down Expand Up @@ -44,3 +45,8 @@ export async function nextDev(dir, port) {
nodeArgs,
})
}

export function getNodeBySelector(html, selector) {
const $ = cheerio.load(html)
return $(selector)
}

0 comments on commit 088354d

Please sign in to comment.