diff --git a/packages/next/server/app-render.tsx b/packages/next/server/app-render.tsx index 2aca0f414f8a..b8d6bd9fc606 100644 --- a/packages/next/server/app-render.tsx +++ b/packages/next/server/app-render.tsx @@ -59,6 +59,24 @@ function preloadComponent(Component: any, props: any) { } try { let result = Component(props) + if (result && result.then) { + result = result + .then((res: any) => { + return { success: res } + }) + .catch((err: Error) => { + return { error: err } + }) + return async () => { + const res = await result + if (res.error) { + throw res.error + } + if (res.success) { + return res.success + } + } + } return function () { // We know what this component will render already. return result diff --git a/test/e2e/app-dir/async-component-preload.test.ts b/test/e2e/app-dir/async-component-preload.test.ts new file mode 100644 index 000000000000..813892ac949e --- /dev/null +++ b/test/e2e/app-dir/async-component-preload.test.ts @@ -0,0 +1,29 @@ +import { createNext, FileRef } from 'e2e-utils' +import { NextInstance } from 'test/lib/next-modes/base' +import webdriver from 'next-webdriver' +import path from 'path' + +describe('async-component-preload', () => { + if ((global as any).isNextDeploy) { + it('should skip next deploy for now', () => {}) + return + } + + let next: NextInstance + + beforeAll(async () => { + next = await createNext({ + files: new FileRef(path.join(__dirname, 'async-component-preload')), + dependencies: { + react: 'latest', + 'react-dom': 'latest', + }, + }) + }) + afterAll(() => next.destroy()) + + it('should handle redirect in an async page', async () => { + const browser = await webdriver(next.url, '/') + expect(await browser.waitForElementByCss('#success').text()).toBe('Success') + }) +}) diff --git a/test/e2e/app-dir/async-component-preload/app/layout.js b/test/e2e/app-dir/async-component-preload/app/layout.js new file mode 100644 index 000000000000..4bd4188663bd --- /dev/null +++ b/test/e2e/app-dir/async-component-preload/app/layout.js @@ -0,0 +1,12 @@ +export const revalidate = 0 + +export default async function RootLayout({ children }) { + await new Promise((resolve) => setTimeout(resolve, 0)) + + return ( + + + {children} + + ) +} diff --git a/test/e2e/app-dir/async-component-preload/app/page.js b/test/e2e/app-dir/async-component-preload/app/page.js new file mode 100644 index 000000000000..653523d875aa --- /dev/null +++ b/test/e2e/app-dir/async-component-preload/app/page.js @@ -0,0 +1,6 @@ +import { redirect } from 'next/navigation' + +export default async function Home() { + redirect('success') + return

Home

+} diff --git a/test/e2e/app-dir/async-component-preload/app/success/page.js b/test/e2e/app-dir/async-component-preload/app/success/page.js new file mode 100644 index 000000000000..3e3cf2bf3b8a --- /dev/null +++ b/test/e2e/app-dir/async-component-preload/app/success/page.js @@ -0,0 +1,3 @@ +export default function Success() { + return

Success

+} diff --git a/test/e2e/app-dir/async-component-preload/next.config.js b/test/e2e/app-dir/async-component-preload/next.config.js new file mode 100644 index 000000000000..cfa3ac3d7aa9 --- /dev/null +++ b/test/e2e/app-dir/async-component-preload/next.config.js @@ -0,0 +1,5 @@ +module.exports = { + experimental: { + appDir: true, + }, +}