diff --git a/docs/basic-features/data-fetching.md b/docs/basic-features/data-fetching.md index b63575f7f9eae..2eb8dd943e82e 100644 --- a/docs/basic-features/data-fetching.md +++ b/docs/basic-features/data-fetching.md @@ -672,7 +672,7 @@ The `context` parameter is an object containing the following keys: `getServerSideProps` should return an object with: -- `props` - An **optional** object with the props that will be received by the page component. It should be a [serializable object](https://en.wikipedia.org/wiki/Serialization) +- `props` - An **optional** object with the props that will be received by the page component. It should be a [serializable object](https://en.wikipedia.org/wiki/Serialization) or a Promise that resolves to a serializable object. - `notFound` - An **optional** boolean value to allow the page to return a 404 status and page. Below is an example of how it works: ```js diff --git a/packages/next/server/render.tsx b/packages/next/server/render.tsx index c49671aa9b22b..27e944b8d6aff 100644 --- a/packages/next/server/render.tsx +++ b/packages/next/server/render.tsx @@ -804,6 +804,10 @@ export async function renderToHTML( ;(renderOpts as any).isRedirect = true } + if ((data as any).props instanceof Promise) { + ;(data as any).props = await (data as any).props + } + if ( (dev || isBuildTimeSSG) && !isSerializableProps( diff --git a/test/integration/getserversideprops/pages/promise/index.js b/test/integration/getserversideprops/pages/promise/index.js new file mode 100644 index 0000000000000..c6871c0fbf647 --- /dev/null +++ b/test/integration/getserversideprops/pages/promise/index.js @@ -0,0 +1,15 @@ +export async function getServerSideProps() { + return { + props: (async function () { + return { + text: 'promise', + } + })(), + } +} + +export default ({ text }) => ( + <> +
hello {text}
+ +) diff --git a/test/integration/getserversideprops/test/index.test.js b/test/integration/getserversideprops/test/index.test.js index dee20cb3e6272..eb99488473fab 100644 --- a/test/integration/getserversideprops/test/index.test.js +++ b/test/integration/getserversideprops/test/index.test.js @@ -136,6 +136,12 @@ const expectedManifestRoutes = () => [ slug: 'slug', }, }, + { + dataRouteRegex: normalizeRegEx( + `^\\/_next\\/data\\/${escapeRegex(buildId)}\\/promise.json$` + ), + page: '/promise', + }, { dataRouteRegex: normalizeRegEx( `^\\/_next\\/data\\/${escapeRegex(buildId)}\\/refresh.json$` @@ -523,6 +529,11 @@ const runTests = (dev = false) => { expect(data.pageProps.post).toBe('post-1') }) + it('should return data correctly when props is a promise', async () => { + const html = await renderViaHTTP(appPort, `/promise`) + expect(html).toMatch(/hello.*?promise/) + }) + it('should navigate to a normal page and back', async () => { const browser = await webdriver(appPort, '/') let text = await browser.elementByCss('p').text()