diff --git a/packages/next/server/app-render.tsx b/packages/next/server/app-render.tsx index 037941da7e89d..1fab5b58f7fc3 100644 --- a/packages/next/server/app-render.tsx +++ b/packages/next/server/app-render.tsx @@ -993,6 +993,33 @@ export async function renderToHTMLOrFlight( ? interopDefault(layoutOrPageMod) : undefined + if (dev) { + const { isValidElementType } = require('next/dist/compiled/react-is') + if (!isValidElementType(Component)) { + throw new Error( + `The default export is not a React Component in page: "${pathname}"` + ) + } + + if (ErrorComponent && !isValidElementType(ErrorComponent)) { + throw new Error( + `The default export of error is not a React Component in page: ${segment}` + ) + } + + if (Loading && !isValidElementType(Loading)) { + throw new Error( + `The default export of loading is not a React Component in ${segment}` + ) + } + + if (NotFound && !isValidElementType(NotFound)) { + throw new Error( + `The default export of notFound is not a React Component in ${segment}` + ) + } + } + // Handle dynamic segment params. const segmentParam = getDynamicParamFromSegment(segment) /** diff --git a/test/e2e/app-dir/rsc-errors.test.ts b/test/e2e/app-dir/rsc-errors.test.ts index d905b871522e2..ef729d6de2649 100644 --- a/test/e2e/app-dir/rsc-errors.test.ts +++ b/test/e2e/app-dir/rsc-errors.test.ts @@ -89,4 +89,14 @@ describe('app dir - rsc basics', () => { 'This module cannot be imported from a Server Component module. It should only be used from a Client Component.' ) }) + + it('should error when page component export is not valid', async () => { + const html = await renderViaHTTP( + next.url, + '/server-with-errors/page-export' + ) + expect(html).toContain( + 'The default export is not a React Component in page: \\"/server-with-errors/page-export\\"' + ) + }) }) diff --git a/test/e2e/app-dir/rsc-errors/app/server-with-errors/page-export/page.js b/test/e2e/app-dir/rsc-errors/app/server-with-errors/page-export/page.js new file mode 100644 index 0000000000000..f910fbf5ea050 --- /dev/null +++ b/test/e2e/app-dir/rsc-errors/app/server-with-errors/page-export/page.js @@ -0,0 +1 @@ +export default 'invalid-page-export' diff --git a/test/lib/react-channel-require-hook.js b/test/lib/react-channel-require-hook.js index 370884bda2731..b4a1ab01e225b 100644 --- a/test/lib/react-channel-require-hook.js +++ b/test/lib/react-channel-require-hook.js @@ -3,8 +3,6 @@ const mod = require('module') // The value will be '17' or 'exp' to alias the actual react channel const reactVersion = process.env.__NEXT_REACT_CHANNEL -console.log('reactVersion', reactVersion) - const reactDir = `react-${reactVersion}` const reactDomDir = `react-dom-${reactVersion}`