From a0e51781e81ec51bd86623e623041eaa3947366a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Born=C3=B6?= Date: Tue, 15 Nov 2022 14:46:55 +0100 Subject: [PATCH] fix: Error: NEXT_REDIRECT crashing server in prod (#42793) Fixes: #42587 ## Bug - [ ] Related issues linked using `fixes #number` - [ ] Integration tests added - [ ] Errors have a 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 a helpful link attached, see `contributing.md` ## Documentation / Examples - [ ] Make sure the linting passes by running `pnpm build && pnpm lint` - [ ] The "examples guidelines" are followed from [our contributing doc](https://github.com/vercel/next.js/blob/canary/contributing/examples/adding-examples.md) --- packages/next/server/app-render.tsx | 18 ++++++++++++ .../app-dir/async-component-preload.test.ts | 29 +++++++++++++++++++ .../async-component-preload/app/layout.js | 12 ++++++++ .../async-component-preload/app/page.js | 6 ++++ .../app/success/page.js | 3 ++ .../async-component-preload/next.config.js | 5 ++++ 6 files changed, 73 insertions(+) create mode 100644 test/e2e/app-dir/async-component-preload.test.ts create mode 100644 test/e2e/app-dir/async-component-preload/app/layout.js create mode 100644 test/e2e/app-dir/async-component-preload/app/page.js create mode 100644 test/e2e/app-dir/async-component-preload/app/success/page.js create mode 100644 test/e2e/app-dir/async-component-preload/next.config.js 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, + }, +}