未验证 提交 5ed89d30 编写于 作者: J Joe Haddad 提交者: GitHub

Render a helpful message for null GS(S)P return (#14252)

This makes Next.js render a better error message when `undefined` (or null) is returned from `getStaticProps` or `getServerSideProps`.

---

Fixes #11139
上级 4152e0ce
......@@ -34,6 +34,11 @@ export const PAGES_404_GET_INITIAL_PROPS_ERROR = `\`pages/404\` can not have get
export const SERVER_PROPS_EXPORT_ERROR = `pages with \`getServerSideProps\` can not be exported. See more info here: https://err.sh/next.js/gssp-export`
export const GSP_NO_RETURNED_VALUE =
'Your `getStaticProps` function did not return an object. Did you forget to add a `return`?'
export const GSSP_NO_RETURNED_VALUE =
'Your `getServerSideProps` function did not return an object. Did you forget to add a `return`?'
export const UNSTABLE_REVALIDATE_RENAME_ERROR =
'The `revalidate` property is not yet available for general use.\n' +
'To try the experimental implementation, please use `unstable_revalidate` instead.\n' +
......
......@@ -2,26 +2,30 @@ import { IncomingMessage, ServerResponse } from 'http'
import { ParsedUrlQuery } from 'querystring'
import React from 'react'
import { renderToStaticMarkup, renderToString } from 'react-dom/server'
import { UnwrapPromise } from '../../lib/coalesced-function'
import {
GSP_NO_RETURNED_VALUE,
GSSP_COMPONENT_MEMBER_ERROR,
GSSP_NO_RETURNED_VALUE,
PAGES_404_GET_INITIAL_PROPS_ERROR,
SERVER_PROPS_GET_INIT_PROPS_CONFLICT,
SERVER_PROPS_SSG_CONFLICT,
SSG_GET_INITIAL_PROPS_CONFLICT,
UNSTABLE_REVALIDATE_RENAME_ERROR,
GSSP_COMPONENT_MEMBER_ERROR,
} from '../../lib/constants'
import { isSerializableProps } from '../../lib/is-serializable-props'
import { GetServerSideProps, GetStaticProps } from '../../types'
import { isInAmpMode } from '../lib/amp'
import { AmpStateContext } from '../lib/amp-context'
import {
AMP_RENDER_TARGET,
STATIC_PROPS_ID,
SERVER_PROPS_ID,
STATIC_PROPS_ID,
} from '../lib/constants'
import { defaultHead } from '../lib/head'
import { HeadManagerContext } from '../lib/head-manager-context'
import Loadable from '../lib/loadable'
import { LoadableContext } from '../lib/loadable-context'
import { HeadManagerContext } from '../lib/head-manager-context'
import mitt, { MittEmitter } from '../lib/mitt'
import { RouterContext } from '../lib/router-context'
import { NextRouter } from '../lib/router/router'
......@@ -41,8 +45,6 @@ import { tryGetPreviewData, __ApiPreviewProps } from './api-utils'
import { getPageFiles } from './get-page-files'
import { LoadComponentsReturnType, ManifestItem } from './load-components'
import optimizeAmp from './optimize-amp'
import { UnwrapPromise } from '../../lib/coalesced-function'
import { GetStaticProps, GetServerSideProps } from '../../types'
function noRouter() {
const message =
......@@ -515,6 +517,10 @@ export async function renderToHTML(
throw staticPropsError
}
if (data == null) {
throw new Error(GSP_NO_RETURNED_VALUE)
}
const invalidKeys = Object.keys(data).filter(
(key) => key !== 'unstable_revalidate' && key !== 'props'
)
......@@ -601,6 +607,10 @@ export async function renderToHTML(
throw serverSidePropsError
}
if (data == null) {
throw new Error(GSSP_NO_RETURNED_VALUE)
}
const invalidKeys = Object.keys(data).filter((key) => key !== 'props')
if (invalidKeys.length) {
......
/* eslint-env jest */
import fs from 'fs-extra'
import { join } from 'path'
import {
nextBuild,
launchApp,
findPort,
renderViaHTTP,
killApp,
launchApp,
nextBuild,
renderViaHTTP,
} from 'next-test-utils'
import { join } from 'path'
import {
GSP_NO_RETURNED_VALUE,
GSSP_NO_RETURNED_VALUE,
} from '../../../../packages/next/dist/lib/constants'
jest.setTimeout(1000 * 60 * 2)
const appDir = join(__dirname, '..')
......@@ -88,9 +91,37 @@ const runTests = (isDev = false) => {
`getStaticPaths can not be attached to a page's component and must be exported from the page`
)
})
it('should show error for undefined getStaticProps', async () => {
await fs.writeFile(
indexPage,
`
export function getStaticProps() {}
export default function Page() {
return <div />;
}
`
)
expect(await getStderr()).toContain(GSP_NO_RETURNED_VALUE)
})
if (isDev) {
it('should show error for undefined getServerSideProps', async () => {
await fs.writeFile(
indexPage,
`
export function getServerSideProps() {}
export default function Page() {
return <div />;
}
`
)
expect(await getStderr()).toContain(GSSP_NO_RETURNED_VALUE)
})
}
}
describe('GSSP Page Component Member Error', () => {
describe('GS(S)P Page Errors', () => {
beforeAll(async () => {
origIndexPage = await fs.readFile(indexPage, 'utf8')
})
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册