diff --git a/packages/next/server/web-server.ts b/packages/next/server/web-server.ts index 32be4de48606..d910c4882a7a 100644 --- a/packages/next/server/web-server.ts +++ b/packages/next/server/web-server.ts @@ -131,7 +131,6 @@ export default class NextWebServer extends BaseServer { query, { ...renderOpts, - // supportsDynamicHTML: true, disableOptimizedLoading: true, runtime: 'edge', } diff --git a/packages/next/server/web/sandbox/readable-stream.ts b/packages/next/server/web/sandbox/readable-stream.ts index 824260922a62..7c0a1a43bd48 100644 --- a/packages/next/server/web/sandbox/readable-stream.ts +++ b/packages/next/server/web/sandbox/readable-stream.ts @@ -39,17 +39,17 @@ class ReadableStream { 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) { @@ -59,7 +59,20 @@ class ReadableStream { } } - 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 } diff --git a/test/integration/react-streaming-and-server-components/test/basic.js b/test/integration/react-streaming-and-server-components/test/basic.js index 2c7a9eea4ad3..c46f5c428364 100644 --- a/test/integration/react-streaming-and-server-components/test/basic.js +++ b/test/integration/react-streaming-and-server-components/test/basic.js @@ -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"') + }) } diff --git a/test/integration/react-streaming-and-server-components/test/index.test.js b/test/integration/react-streaming-and-server-components/test/index.test.js index 0f5f7a498e04..4bdd329708b9 100644 --- a/test/integration/react-streaming-and-server-components/test/index.test.js +++ b/test/integration/react-streaming-and-server-components/test/index.test.js @@ -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' @@ -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) @@ -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') diff --git a/test/integration/react-streaming-and-server-components/test/rsc.js b/test/integration/react-streaming-and-server-components/test/rsc.js index 3b8ed678e33f..5e7c60d3f4f5 100644 --- a/test/integration/react-streaming-and-server-components/test/rsc.js +++ b/test/integration/react-streaming-and-server-components/test/rsc.js @@ -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 () => { diff --git a/test/integration/react-streaming-and-server-components/test/streaming.js b/test/integration/react-streaming-and-server-components/test/streaming.js index f60fa1300720..3954db13e242 100644 --- a/test/integration/react-streaming-and-server-components/test/streaming.js +++ b/test/integration/react-streaming-and-server-components/test/streaming.js @@ -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 = '' @@ -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() diff --git a/test/integration/react-streaming-and-server-components/test/utils.js b/test/integration/react-streaming-and-server-components/test/utils.js index 4e51c063272c..56e3e4527ee1 100644 --- a/test/integration/react-streaming-and-server-components/test/utils.js +++ b/test/integration/react-streaming-and-server-components/test/utils.js @@ -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')] @@ -44,3 +45,8 @@ export async function nextDev(dir, port) { nodeArgs, }) } + +export function getNodeBySelector(html, selector) { + const $ = cheerio.load(html) + return $(selector) +}