feat(next): revise server component error message (#65468)
### What Coming from internal feedback: https://vercel.slack.com/archives/C046HAU4H7F/p1714858224393659
This commit is contained in:
parent
a7ebbdef7e
commit
531348d864
9 changed files with 65 additions and 49 deletions
2
.github/workflows/build_reusable.yml
vendored
2
.github/workflows/build_reusable.yml
vendored
|
@ -175,7 +175,7 @@ jobs:
|
|||
- run: turbo run get-test-timings -- --build ${{ github.sha }}
|
||||
|
||||
- run: /bin/bash -c "${{ inputs.afterBuild }}"
|
||||
timeout-minutes: 15
|
||||
timeout-minutes: 30
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
|
|
|
@ -257,9 +257,9 @@ fn report_error(app_dir: &Option<PathBuf>, filepath: &str, error_kind: RSCErrorK
|
|||
.unwrap_or_default();
|
||||
|
||||
let msg = if !is_app_dir {
|
||||
format!("You're importing a component that needs {}. That only works in a Server Component which is not supported in the pages/ directory. Read more: https://nextjs.org/docs/getting-started/react-essentials#server-components\n\n", source)
|
||||
format!("You're importing a component that needs \"{}\". That only works in a Server Component which is not supported in the pages/ directory. Read more: https://nextjs.org/docs/getting-started/react-essentials#server-components\n\n", source)
|
||||
} else {
|
||||
format!("You're importing a component that needs {}. That only works in a Server Component but one of its parents is marked with \"use client\", so it's a Client Component.\nLearn more: https://nextjs.org/docs/getting-started/react-essentials\n\n", source)
|
||||
format!("You're importing a component that needs \"{}\". That only works in a Server Component but one of its parents is marked with \"use client\", so it's a Client Component.\nLearn more: https://nextjs.org/docs/getting-started/react-essentials\n\n", source)
|
||||
};
|
||||
(msg, span)
|
||||
}
|
||||
|
@ -267,7 +267,7 @@ fn report_error(app_dir: &Option<PathBuf>, filepath: &str, error_kind: RSCErrorK
|
|||
let msg = if source == "Component" {
|
||||
"You’re importing a class component. It only works in a Client Component but none of its parents are marked with \"use client\", so they're Server Components by default.\nLearn more: https://nextjs.org/docs/getting-started/react-essentials#client-components\n\n".to_string()
|
||||
} else {
|
||||
format!("You're importing a component that needs {}. It only works in a Client Component but none of its parents are marked with \"use client\", so they're Server Components by default.\nLearn more: https://nextjs.org/docs/getting-started/react-essentials\n\n", source)
|
||||
format!("You're importing a component that needs `{}`. This React hook only works in a client component. To fix, mark the file (or its parent) with the `\"use client\"` directive.\n\n Learn more: https://nextjs.org/docs/app/building-your-application/rendering/client-components\n\n", source)
|
||||
};
|
||||
|
||||
(msg,span)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
x You're importing a component that needs server-only. That only works in a Server Component which is not supported in the pages/ directory. Read more: https://nextjs.org/docs/getting-started/
|
||||
x You're importing a component that needs "server-only". That only works in a Server Component which is not supported in the pages/ directory. Read more: https://nextjs.org/docs/getting-started/
|
||||
| react-essentials#server-components
|
||||
|
|
||||
|
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
|
||||
x You're importing a component that needs useState. It only works in a Client Component but none of its parents are marked with "use client", so they're Server Components by default.
|
||||
| Learn more: https://nextjs.org/docs/getting-started/react-essentials
|
||||
x You're importing a component that needs `useState`. This React hook only works in a client component. To fix, mark the file (or its parent) with the `"use client"` directive.
|
||||
|
|
||||
| Learn more: https://nextjs.org/docs/app/building-your-application/rendering/client-components
|
||||
|
|
||||
|
|
||||
,-[input.js:1:1]
|
||||
|
@ -8,8 +9,9 @@
|
|||
: ^^^^^^^^
|
||||
`----
|
||||
|
||||
x You're importing a component that needs createContext. It only works in a Client Component but none of its parents are marked with "use client", so they're Server Components by default.
|
||||
| Learn more: https://nextjs.org/docs/getting-started/react-essentials
|
||||
x You're importing a component that needs `createContext`. This React hook only works in a client component. To fix, mark the file (or its parent) with the `"use client"` directive.
|
||||
|
|
||||
| Learn more: https://nextjs.org/docs/app/building-your-application/rendering/client-components
|
||||
|
|
||||
|
|
||||
,-[input.js:2:1]
|
||||
|
@ -18,8 +20,9 @@
|
|||
: ^^^^^^^^^^^^^
|
||||
`----
|
||||
|
||||
x You're importing a component that needs useEffect. It only works in a Client Component but none of its parents are marked with "use client", so they're Server Components by default.
|
||||
| Learn more: https://nextjs.org/docs/getting-started/react-essentials
|
||||
x You're importing a component that needs `useEffect`. This React hook only works in a client component. To fix, mark the file (or its parent) with the `"use client"` directive.
|
||||
|
|
||||
| Learn more: https://nextjs.org/docs/app/building-your-application/rendering/client-components
|
||||
|
|
||||
|
|
||||
,-[input.js:4:1]
|
||||
|
@ -28,8 +31,9 @@
|
|||
: ^^^^^^^^^
|
||||
`----
|
||||
|
||||
x You're importing a component that needs useImperativeHandle. It only works in a Client Component but none of its parents are marked with "use client", so they're Server Components by default.
|
||||
| Learn more: https://nextjs.org/docs/getting-started/react-essentials
|
||||
x You're importing a component that needs `useImperativeHandle`. This React hook only works in a client component. To fix, mark the file (or its parent) with the `"use client"` directive.
|
||||
|
|
||||
| Learn more: https://nextjs.org/docs/app/building-your-application/rendering/client-components
|
||||
|
|
||||
|
|
||||
,-[input.js:4:1]
|
||||
|
@ -49,8 +53,9 @@
|
|||
9 | createFactory,
|
||||
`----
|
||||
|
||||
x You're importing a component that needs createFactory. It only works in a Client Component but none of its parents are marked with "use client", so they're Server Components by default.
|
||||
| Learn more: https://nextjs.org/docs/getting-started/react-essentials
|
||||
x You're importing a component that needs `createFactory`. This React hook only works in a client component. To fix, mark the file (or its parent) with the `"use client"` directive.
|
||||
|
|
||||
| Learn more: https://nextjs.org/docs/app/building-your-application/rendering/client-components
|
||||
|
|
||||
|
|
||||
,-[input.js:8:1]
|
||||
|
@ -60,8 +65,9 @@
|
|||
10 | PureComponent,
|
||||
`----
|
||||
|
||||
x You're importing a component that needs PureComponent. It only works in a Client Component but none of its parents are marked with "use client", so they're Server Components by default.
|
||||
| Learn more: https://nextjs.org/docs/getting-started/react-essentials
|
||||
x You're importing a component that needs `PureComponent`. This React hook only works in a client component. To fix, mark the file (or its parent) with the `"use client"` directive.
|
||||
|
|
||||
| Learn more: https://nextjs.org/docs/app/building-your-application/rendering/client-components
|
||||
|
|
||||
|
|
||||
,-[input.js:9:1]
|
||||
|
@ -71,8 +77,9 @@
|
|||
11 | useDeferredValue,
|
||||
`----
|
||||
|
||||
x You're importing a component that needs useDeferredValue. It only works in a Client Component but none of its parents are marked with "use client", so they're Server Components by default.
|
||||
| Learn more: https://nextjs.org/docs/getting-started/react-essentials
|
||||
x You're importing a component that needs `useDeferredValue`. This React hook only works in a client component. To fix, mark the file (or its parent) with the `"use client"` directive.
|
||||
|
|
||||
| Learn more: https://nextjs.org/docs/app/building-your-application/rendering/client-components
|
||||
|
|
||||
|
|
||||
,-[input.js:10:1]
|
||||
|
@ -82,8 +89,9 @@
|
|||
12 | useInsertionEffect,
|
||||
`----
|
||||
|
||||
x You're importing a component that needs useInsertionEffect. It only works in a Client Component but none of its parents are marked with "use client", so they're Server Components by default.
|
||||
| Learn more: https://nextjs.org/docs/getting-started/react-essentials
|
||||
x You're importing a component that needs `useInsertionEffect`. This React hook only works in a client component. To fix, mark the file (or its parent) with the `"use client"` directive.
|
||||
|
|
||||
| Learn more: https://nextjs.org/docs/app/building-your-application/rendering/client-components
|
||||
|
|
||||
|
|
||||
,-[input.js:11:1]
|
||||
|
@ -93,8 +101,9 @@
|
|||
13 | useLayoutEffect,
|
||||
`----
|
||||
|
||||
x You're importing a component that needs useLayoutEffect. It only works in a Client Component but none of its parents are marked with "use client", so they're Server Components by default.
|
||||
| Learn more: https://nextjs.org/docs/getting-started/react-essentials
|
||||
x You're importing a component that needs `useLayoutEffect`. This React hook only works in a client component. To fix, mark the file (or its parent) with the `"use client"` directive.
|
||||
|
|
||||
| Learn more: https://nextjs.org/docs/app/building-your-application/rendering/client-components
|
||||
|
|
||||
|
|
||||
,-[input.js:12:1]
|
||||
|
@ -104,8 +113,9 @@
|
|||
14 | useReducer,
|
||||
`----
|
||||
|
||||
x You're importing a component that needs useReducer. It only works in a Client Component but none of its parents are marked with "use client", so they're Server Components by default.
|
||||
| Learn more: https://nextjs.org/docs/getting-started/react-essentials
|
||||
x You're importing a component that needs `useReducer`. This React hook only works in a client component. To fix, mark the file (or its parent) with the `"use client"` directive.
|
||||
|
|
||||
| Learn more: https://nextjs.org/docs/app/building-your-application/rendering/client-components
|
||||
|
|
||||
|
|
||||
,-[input.js:13:1]
|
||||
|
@ -115,8 +125,9 @@
|
|||
15 | useRef,
|
||||
`----
|
||||
|
||||
x You're importing a component that needs useRef. It only works in a Client Component but none of its parents are marked with "use client", so they're Server Components by default.
|
||||
| Learn more: https://nextjs.org/docs/getting-started/react-essentials
|
||||
x You're importing a component that needs `useRef`. This React hook only works in a client component. To fix, mark the file (or its parent) with the `"use client"` directive.
|
||||
|
|
||||
| Learn more: https://nextjs.org/docs/app/building-your-application/rendering/client-components
|
||||
|
|
||||
|
|
||||
,-[input.js:14:1]
|
||||
|
@ -126,8 +137,9 @@
|
|||
16 | useSyncExternalStore,
|
||||
`----
|
||||
|
||||
x You're importing a component that needs useSyncExternalStore. It only works in a Client Component but none of its parents are marked with "use client", so they're Server Components by default.
|
||||
| Learn more: https://nextjs.org/docs/getting-started/react-essentials
|
||||
x You're importing a component that needs `useSyncExternalStore`. This React hook only works in a client component. To fix, mark the file (or its parent) with the `"use client"` directive.
|
||||
|
|
||||
| Learn more: https://nextjs.org/docs/app/building-your-application/rendering/client-components
|
||||
|
|
||||
|
|
||||
,-[input.js:15:1]
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
|
||||
x You're importing a component that needs flushSync. It only works in a Client Component but none of its parents are marked with "use client", so they're Server Components by default.
|
||||
| Learn more: https://nextjs.org/docs/getting-started/react-essentials
|
||||
x You're importing a component that needs `flushSync`. This React hook only works in a client component. To fix, mark the file (or its parent) with the `"use client"` directive.
|
||||
|
|
||||
| Learn more: https://nextjs.org/docs/app/building-your-application/rendering/client-components
|
||||
|
|
||||
|
|
||||
,-[input.js:1:1]
|
||||
|
@ -8,9 +9,9 @@
|
|||
: ^^^^^^^^^
|
||||
`----
|
||||
|
||||
x You're importing a component that needs unstable_batchedUpdates. It only works in a Client Component but none of its parents are marked with "use client", so they're Server Components by
|
||||
| default.
|
||||
| Learn more: https://nextjs.org/docs/getting-started/react-essentials
|
||||
x You're importing a component that needs `unstable_batchedUpdates`. This React hook only works in a client component. To fix, mark the file (or its parent) with the `"use client"` directive.
|
||||
|
|
||||
| Learn more: https://nextjs.org/docs/app/building-your-application/rendering/client-components
|
||||
|
|
||||
|
|
||||
,-[input.js:1:1]
|
||||
|
@ -18,8 +19,9 @@
|
|||
: ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
`----
|
||||
|
||||
x You're importing a component that needs useActionState. It only works in a Client Component but none of its parents are marked with "use client", so they're Server Components by default.
|
||||
| Learn more: https://nextjs.org/docs/getting-started/react-essentials
|
||||
x You're importing a component that needs `useActionState`. This React hook only works in a client component. To fix, mark the file (or its parent) with the `"use client"` directive.
|
||||
|
|
||||
| Learn more: https://nextjs.org/docs/app/building-your-application/rendering/client-components
|
||||
|
|
||||
|
|
||||
,-[input.js:2:1]
|
||||
|
@ -28,8 +30,9 @@
|
|||
: ^^^^^^^^^^^^^^
|
||||
`----
|
||||
|
||||
x You're importing a component that needs useFormStatus. It only works in a Client Component but none of its parents are marked with "use client", so they're Server Components by default.
|
||||
| Learn more: https://nextjs.org/docs/getting-started/react-essentials
|
||||
x You're importing a component that needs `useFormStatus`. This React hook only works in a client component. To fix, mark the file (or its parent) with the `"use client"` directive.
|
||||
|
|
||||
| Learn more: https://nextjs.org/docs/app/building-your-application/rendering/client-components
|
||||
|
|
||||
|
|
||||
,-[input.js:4:1]
|
||||
|
@ -38,8 +41,9 @@
|
|||
: ^^^^^^^^^^^^^
|
||||
`----
|
||||
|
||||
x You're importing a component that needs useFormState. It only works in a Client Component but none of its parents are marked with "use client", so they're Server Components by default.
|
||||
| Learn more: https://nextjs.org/docs/getting-started/react-essentials
|
||||
x You're importing a component that needs `useFormState`. This React hook only works in a client component. To fix, mark the file (or its parent) with the `"use client"` directive.
|
||||
|
|
||||
| Learn more: https://nextjs.org/docs/app/building-your-application/rendering/client-components
|
||||
|
|
||||
|
|
||||
,-[input.js:4:1]
|
||||
|
|
|
@ -34,7 +34,7 @@ function formatRSCErrorMessage(
|
|||
} else {
|
||||
formattedMessage = message.replace(
|
||||
NEXT_RSC_ERR_REACT_API,
|
||||
`\n\nYou're importing a component that needs $1. It only works in a Client Component but none of its parents are marked with "use client", so they're Server Components by default.\nLearn more: https://nextjs.org/docs/getting-started/react-essentials\n\n`
|
||||
`\n\nYou're importing a component that needs $1. This React hook only works in a client component. To fix, mark the file (or its parent) with the \`"use client"\` directive. \n\nLearn more: https://nextjs.org/docs/app/building-your-application/rendering/client-components\n\n`
|
||||
)
|
||||
}
|
||||
formattedVerboseMessage =
|
||||
|
|
|
@ -277,7 +277,7 @@ describe('Error overlay - RSC build errors', () => {
|
|||
// `Component` has a custom error message
|
||||
api === 'Component'
|
||||
? `You’re importing a class component. It only works in a Client Component but none of its parents are marked with "use client", so they're Server Components by default.`
|
||||
: `You're importing a component that needs ${api}. It only works in a Client Component but none of its parents are marked with "use client", so they're Server Components by default.`
|
||||
: `You're importing a component that needs \`${api}\`. This React hook only works in a client component. To fix, mark the file (or its parent) with the \`"use client"\` directive.`
|
||||
)
|
||||
|
||||
await cleanup()
|
||||
|
@ -300,7 +300,7 @@ describe('Error overlay - RSC build errors', () => {
|
|||
|
||||
expect(await session.hasRedbox()).toBe(true)
|
||||
expect(await session.getRedboxSource()).toInclude(
|
||||
`You're importing a component that needs ${api}. It only works in a Client Component but none of its parents are marked with "use client", so they're Server Components`
|
||||
`You're importing a component that needs \`${api}\`. This React hook only works in a client component. To fix, mark the file (or its parent) with the \`"use client"\` directive.`
|
||||
)
|
||||
|
||||
await cleanup()
|
||||
|
@ -326,7 +326,7 @@ describe('Error overlay - RSC build errors', () => {
|
|||
|
||||
expect(await session.hasRedbox()).toBe(true)
|
||||
expect(await session.getRedboxSource()).toInclude(
|
||||
`You're importing a component that needs server-only. That only works in a Server Component but one of its parents is marked with "use client", so it's a Client Component.`
|
||||
`You're importing a component that needs "server-only". That only works in a Server Component but one of its parents is marked with "use client", so it's a Client Component.`
|
||||
)
|
||||
|
||||
await cleanup()
|
||||
|
|
|
@ -550,7 +550,7 @@ describe('Error Overlay for server components', () => {
|
|||
// So we need to check for the first part of the message.
|
||||
const normalizedSource = await session.getRedboxSource()
|
||||
expect(normalizedSource).toContain(
|
||||
`You're importing a component that needs ${hook}. It only works in a Client Component but none of its parents are marked with "use client"`
|
||||
`You're importing a component that needs \`${hook}\`. This React hook only works in a client component. To fix, mark the file (or its parent) with the \`"use client"\` directive.`
|
||||
)
|
||||
expect(normalizedSource).toContain(
|
||||
`import { ${hook} } from 'next/navigation'`
|
||||
|
|
|
@ -65,14 +65,14 @@ describe('Error Overlay for server components compiler errors in pages', () => {
|
|||
3 | export default function Page() {
|
||||
4 | return <p>hello world</p>
|
||||
|
||||
You're importing a component that needs next/headers. That only works in a Server Component which is not supported in the pages/ directory. Read more: https://nextjs.org/docs/getting-started/react-essentials#server-components"
|
||||
You're importing a component that needs "next/headers". That only works in a Server Component which is not supported in the pages/ directory. Read more: https://nextjs.org/docs/getting-started/react-essentials#server-components"
|
||||
`)
|
||||
} else {
|
||||
expect(next.normalizeTestDirContent(await session.getRedboxSource()))
|
||||
.toMatchInlineSnapshot(`
|
||||
"./components/Comp.js
|
||||
Error:
|
||||
x You're importing a component that needs next/headers. That only works in a Server Component which is not supported in the pages/ directory. Read more: https://nextjs.org/docs/getting-started/
|
||||
x You're importing a component that needs "next/headers". That only works in a Server Component which is not supported in the pages/ directory. Read more: https://nextjs.org/docs/getting-started/
|
||||
| react-essentials#server-components
|
||||
|
|
||||
|
|
||||
|
@ -124,14 +124,14 @@ describe('Error Overlay for server components compiler errors in pages', () => {
|
|||
3 | export default function Page() {
|
||||
4 | return 'hello world'
|
||||
|
||||
You're importing a component that needs server-only. That only works in a Server Component which is not supported in the pages/ directory. Read more: https://nextjs.org/docs/getting-started/react-essentials#server-components"
|
||||
You're importing a component that needs "server-only". That only works in a Server Component which is not supported in the pages/ directory. Read more: https://nextjs.org/docs/getting-started/react-essentials#server-components"
|
||||
`)
|
||||
} else {
|
||||
expect(next.normalizeTestDirContent(await session.getRedboxSource()))
|
||||
.toMatchInlineSnapshot(`
|
||||
"./components/Comp.js
|
||||
Error:
|
||||
x You're importing a component that needs server-only. That only works in a Server Component which is not supported in the pages/ directory. Read more: https://nextjs.org/docs/getting-started/
|
||||
x You're importing a component that needs "server-only". That only works in a Server Component which is not supported in the pages/ directory. Read more: https://nextjs.org/docs/getting-started/
|
||||
| react-essentials#server-components
|
||||
|
|
||||
|
|
||||
|
|
Loading…
Reference in a new issue