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,
+ },
+}