chore: improve error when exporting metadata from client component (#46334)

<!--
Thanks for opening a PR! Your contribution is much appreciated.
To make sure your PR is handled as smoothly as possible we request that
you follow the checklist sections below.
Choose the right checklist for the change(s) that you're making:
-->

This improves the ambiguous error seen when exporting `metadata` or
`generateMetadata` from a component marked with the `"use client";`
directive.

Example output from tests (`pnpm test-dev
test/development/acceptance-app/rsc-build-errors.test`)

```console
File path:
  app/client-with-errors/metadata-export/page.js
  console.log
    browser log: ./app/client-with-errors/metadata-export/page.js
    ReactServerComponentsError:
    
    You are attempting to export "generateMetadata" from a component marked with "use client", which is disallowed. Either remove the export, or the "use client" directive. Read more: https://beta.nextjs.org/docs/api-reference/metadata
    
       ,-[6:1]
     6 | 
     7 | // export const metadata = { title: 'client-metadata' }
     8 | 
     9 | export async function generateMetadata() { return { title: 'client-metadata' } }
       :                       ^^^^^^^^^^^^^^^^
       `----
    
    File path:
      app/client-with-errors/metadata-export/page.js
```

## Bug

- [ ] Related issues linked using `fixes #number`
- [x] Integration tests added
- [x] Errors have a helpful link attached, see
[`contributing.md`](https://github.com/vercel/next.js/blob/canary/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`
- [ ]
[e2e](https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs)
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`](https://github.com/vercel/next.js/blob/canary/contributing.md)

## Documentation / Examples

- [x] 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)

---------

Co-authored-by: Jiachi Liu <inbox@huozhi.im>
This commit is contained in:
Kevin Wang 2023-02-25 00:23:32 -05:00 committed by GitHub
parent ccdb86979f
commit b942a6f494
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 16 additions and 4 deletions

View file

@ -470,8 +470,11 @@ impl<C: Comments> ReactServerComponents<C> {
handler
.struct_span_err(
span,
format!("NEXT_RSC_ERR_INVALID_API: {}", invalid_export_name)
.as_str(),
format!(
"NEXT_RSC_ERR_CLIENT_METADATA_EXPORT: {}",
invalid_export_name
)
.as_str(),
)
.emit()
})

View file

@ -16,6 +16,8 @@ function formatRSCErrorMessage(
const NEXT_RSC_ERR_REACT_API = /.+NEXT_RSC_ERR_REACT_API: (.*?)\n/s
const NEXT_RSC_ERR_SERVER_IMPORT = /.+NEXT_RSC_ERR_SERVER_IMPORT: (.*?)\n/s
const NEXT_RSC_ERR_CLIENT_IMPORT = /.+NEXT_RSC_ERR_CLIENT_IMPORT: (.*?)\n/s
const NEXT_RSC_ERR_CLIENT_METADATA_EXPORT =
/.+NEXT_RSC_ERR_CLIENT_METADATA_EXPORT: (.*?)\n/s
const NEXT_RSC_ERR_CLIENT_DIRECTIVE = /.+NEXT_RSC_ERR_CLIENT_DIRECTIVE\n/s
const NEXT_RSC_ERR_CLIENT_DIRECTIVE_PAREN =
/.+NEXT_RSC_ERR_CLIENT_DIRECTIVE_PAREN\n/s
@ -93,6 +95,13 @@ function formatRSCErrorMessage(
`\n\n${fileName} must be a Client Component. Add the "use client" directive the top of the file to resolve this issue.\n\n`
)
formattedVerboseMessage = '\n\nImport path:\n'
} else if (NEXT_RSC_ERR_CLIENT_METADATA_EXPORT.test(message)) {
formattedMessage = message.replace(
NEXT_RSC_ERR_CLIENT_METADATA_EXPORT,
`\n\nYou are attempting to export "$1" from a component marked with "use client", which is disallowed. Either remove the export, or the "use client" directive. Read more: https://beta.nextjs.org/docs/api-reference/metadata\n\n`
)
formattedVerboseMessage = '\n\nFile path:\n'
}
return [formattedMessage, formattedVerboseMessage]

View file

@ -55,7 +55,7 @@ createNextDescribe(
await session.patch(pageFile, uncomment)
expect(await session.hasRedbox(true)).toBe(true)
expect(await session.getRedboxSource()).toInclude(
'"metadata" is not supported in app/'
'You are attempting to export "metadata" from a component marked with "use client", which is disallowed.'
)
// Restore file
@ -70,7 +70,7 @@ createNextDescribe(
await session.patch(pageFile, uncomment)
expect(await session.hasRedbox(true)).toBe(true)
expect(await session.getRedboxSource()).toInclude(
'"generateMetadata" is not supported in app/'
'You are attempting to export "generateMetadata" from a component marked with "use client", which is disallowed.'
)
await cleanup()