-
Notifications
You must be signed in to change notification settings - Fork 27.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Improve error messages of server compilation (#41136)
We used to format RSC errors (which are from the SWC loader) before outputting them to the CLI. This PR moves that to a better place in `WellknownErrorPlugin`. ## Bug - [ ] Related issues linked using `fixes #number` - [ ] Integration tests added - [ ] Errors have a helpful link attached, see `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` - [ ] Integration 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` ## Documentation / Examples - [ ] Make sure the linting passes by running `pnpm lint` - [ ] The "examples guidelines" are followed from [our contributing doc](https://github.com/vercel/next.js/blob/canary/contributing/examples/adding-examples.md)
- Loading branch information
Showing
4 changed files
with
108 additions
and
36 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
90 changes: 90 additions & 0 deletions
90
packages/next/build/webpack/plugins/wellknown-errors-plugin/parseRSC.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
import type { webpack } from 'next/dist/compiled/webpack/webpack' | ||
|
||
import { relative } from 'path' | ||
import { SimpleWebpackError } from './simpleWebpackError' | ||
|
||
export function formatRSCErrorMessage( | ||
message: string | ||
): null | [string, string] { | ||
if (message && /NEXT_RSC_ERR_/.test(message)) { | ||
let formattedMessage = message | ||
let formattedVerboseMessage = '' | ||
|
||
// Comes from the "React Server Components" transform in SWC, always | ||
// attach the module trace. | ||
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 | ||
|
||
if (NEXT_RSC_ERR_REACT_API.test(message)) { | ||
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 "client", so they're Server Components by default.\n\n` | ||
) | ||
formattedVerboseMessage = | ||
'\n\nMaybe one of these should be marked as a "client" entry:\n' | ||
} else if (NEXT_RSC_ERR_SERVER_IMPORT.test(message)) { | ||
formattedMessage = message.replace( | ||
NEXT_RSC_ERR_SERVER_IMPORT, | ||
`\n\nYou're importing a component that imports $1. It only works in a Client Component but none of its parents are marked with "client", so they're Server Components by default.\n\n` | ||
) | ||
formattedVerboseMessage = | ||
'\n\nMaybe one of these should be marked as a "client" entry:\n' | ||
} else if (NEXT_RSC_ERR_CLIENT_IMPORT.test(message)) { | ||
formattedMessage = message.replace( | ||
NEXT_RSC_ERR_CLIENT_IMPORT, | ||
`\n\nYou're importing a component that needs $1. That only works in a Server Component but one of its parents is marked with "client", so it's a Client Component.\n\n` | ||
) | ||
formattedVerboseMessage = | ||
'\n\nOne of these is marked as a "client" entry:\n' | ||
} | ||
|
||
return [formattedMessage, formattedVerboseMessage] | ||
} | ||
|
||
return null | ||
} | ||
|
||
// Check if the error is specifically related to React Server Components. | ||
// If so, we'll format the error message to be more helpful. | ||
export function getRscError( | ||
fileName: string, | ||
err: Error, | ||
module: any, | ||
compilation: webpack.Compilation, | ||
compiler: webpack.Compiler | ||
): SimpleWebpackError | false { | ||
const formattedError = formatRSCErrorMessage(err.message) | ||
if (!formattedError) return false | ||
|
||
// Get the module trace: | ||
// https://cs.github.com/webpack/webpack/blob/9fcaa243573005d6fdece9a3f8d89a0e8b399613/lib/stats/DefaultStatsFactoryPlugin.js#L414 | ||
const visitedModules = new Set() | ||
const moduleTrace = [] | ||
let current = module | ||
while (current) { | ||
if (visitedModules.has(current)) break | ||
visitedModules.add(current) | ||
moduleTrace.push(current) | ||
const origin = compilation.moduleGraph.getIssuer(current) | ||
if (!origin) break | ||
current = origin | ||
} | ||
|
||
const error = new SimpleWebpackError( | ||
fileName, | ||
formattedError[0] + | ||
formattedError[1] + | ||
moduleTrace | ||
.map((m) => | ||
m.resource ? ' ' + relative(compiler.context, m.resource) : '' | ||
) | ||
.filter(Boolean) | ||
.join('\n') | ||
) | ||
|
||
// Delete the stack because it's created here. | ||
error.stack = '' | ||
|
||
return error | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters