Skip to content

Commit

Permalink
feat(next): revise server component error message
Browse files Browse the repository at this point in the history
  • Loading branch information
kwonoj committed May 8, 2024
1 parent 78507bc commit 26aa0a9
Show file tree
Hide file tree
Showing 9 changed files with 65 additions and 49 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build_reusable.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -257,17 +257,17 @@ 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)
}
RSCErrorKind::NextRscErrReactApi((source, span)) => {
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)
Expand Down
Original file line number Diff line number Diff line change
@@ -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
|
|
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@

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]
1 | import { useState } from 'react'
: ^^^^^^^^
`----

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]
Expand All @@ -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]
Expand All @@ -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]
Expand All @@ -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]
Expand All @@ -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]
Expand All @@ -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]
Expand All @@ -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]
Expand All @@ -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]
Expand All @@ -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]
Expand All @@ -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]
Expand All @@ -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]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,27 @@

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]
1 | import { flushSync, unstable_batchedUpdates } from 'react-dom'
: ^^^^^^^^^
`----

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]
1 | import { flushSync, unstable_batchedUpdates } from 'react-dom'
: ^^^^^^^^^^^^^^^^^^^^^^^
`----

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]
Expand All @@ -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]
Expand All @@ -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]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down
6 changes: 3 additions & 3 deletions test/development/acceptance-app/rsc-build-errors.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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()
Expand All @@ -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()
Expand Down
2 changes: 1 addition & 1 deletion test/development/acceptance-app/server-components.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
|
|
Expand Down Expand Up @@ -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
|
|
Expand Down

0 comments on commit 26aa0a9

Please sign in to comment.