From 2f8611ec2cd6adb10ced136ce16c417d26d36e3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Born=C3=B6?= Date: Mon, 28 Nov 2022 14:18:26 +0100 Subject: [PATCH] Remove stack trace from full reload warning (#43453) Adds a new error link with possible ways to fix the cause of the full reload. Removes the stack trace and adds the file causing the error to the message. Before ![image](https://user-images.githubusercontent.com/25056922/204278894-dd773e6d-9d79-459a-abc4-243c1b22b206.png) After: ![image](https://user-images.githubusercontent.com/25056922/204278538-5e26a174-bae4-457f-aac4-f239398227f8.png) Fixes #43448 ## Bug - [ ] Related issues linked using `fixes #number` - [ ] Integration tests added - [ ] 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 - [ ] 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) --- errors/fast-refresh-reload.md | 17 ++++++++++ errors/manifest.json | 4 +++ .../dev/error-overlay/hot-dev-client.js | 1 + packages/next/server/dev/hot-reloader.ts | 29 +++++++++++++---- test/development/basic/hmr.test.ts | 32 +++++++------------ 5 files changed, 57 insertions(+), 26 deletions(-) create mode 100644 errors/fast-refresh-reload.md diff --git a/errors/fast-refresh-reload.md b/errors/fast-refresh-reload.md new file mode 100644 index 000000000000..14023d575046 --- /dev/null +++ b/errors/fast-refresh-reload.md @@ -0,0 +1,17 @@ +# Fast Refresh had to perform full reload + +#### Why This Error Occurred + +Fast Refresh had to perform a full reload when you edited a file. It may be because: + +- The file you're editing might have other exports in addition to a React component. +- Your React component is an anonymous function. + +#### Possible Ways to Fix It + +- Move your other exports to a separate file. +- Use a named function for your React component. + +### Useful Links + +[Fast Refresh documentation](https://nextjs.org/docs/basic-features/fast-refresh) diff --git a/errors/manifest.json b/errors/manifest.json index 21e8f8478245..f2ed0ae1656e 100644 --- a/errors/manifest.json +++ b/errors/manifest.json @@ -769,6 +769,10 @@ { "title": "app-dir-dynamic-href", "path": "/errors/app-dir-dynamic-href.md" + }, + { + "title": "fast-refresh-reload", + "path": "/errors/fast-refresh-reload.md" } ] } diff --git a/packages/next/client/dev/error-overlay/hot-dev-client.js b/packages/next/client/dev/error-overlay/hot-dev-client.js index 63d0256ac3a6..aafba5fa4db5 100644 --- a/packages/next/client/dev/error-overlay/hot-dev-client.js +++ b/packages/next/client/dev/error-overlay/hot-dev-client.js @@ -398,6 +398,7 @@ function performFullReload(err) { JSON.stringify({ event: 'client-full-reload', stackTrace, + hadRuntimeError: !!hadRuntimeError, }) ) diff --git a/packages/next/server/dev/hot-reloader.ts b/packages/next/server/dev/hot-reloader.ts index baa09430552b..940ab3e35e69 100644 --- a/packages/next/server/dev/hot-reloader.ts +++ b/packages/next/server/dev/hot-reloader.ts @@ -357,16 +357,33 @@ export default class HotReloader { break } case 'client-full-reload': { + const { event, stackTrace, hadRuntimeError } = payload + traceChild = { - name: payload.event, - attrs: { stackTrace: payload.stackTrace ?? '' }, + name: event, + attrs: { stackTrace: stackTrace ?? '' }, + } + + if (hadRuntimeError) { + Log.warn( + `Fast Refresh had to perform a full reload due to a runtime error.` + ) + break } + + let fileMessage = '' + if (stackTrace) { + const file = /Aborted because (.+) is not accepted/.exec( + stackTrace + )?.[1] + if (file) { + fileMessage = ` when ${file} changed` + } + } + Log.warn( - 'Fast Refresh had to perform a full reload. Read more: https://nextjs.org/docs/basic-features/fast-refresh#how-it-works' + `Fast Refresh had to perform a full reload${fileMessage}. Read more: https://nextjs.org/docs/messages/fast-refresh-reload` ) - if (payload.stackTrace) { - console.warn(payload.stackTrace) - } break } default: { diff --git a/test/development/basic/hmr.test.ts b/test/development/basic/hmr.test.ts index 4bfd3ab66c1c..13982bd06e9c 100644 --- a/test/development/basic/hmr.test.ts +++ b/test/development/basic/hmr.test.ts @@ -778,10 +778,11 @@ describe('basic HMR', () => { next.appPort, `/hmr/anonymous-page-function` ) + const cliWarning = + 'Fast Refresh had to perform a full reload when ./pages/hmr/anonymous-page-function.js changed. Read more: https://nextjs.org/docs/messages/fast-refresh-reload' + expect(await browser.elementByCss('p').text()).toBe('hello world') - expect(next.cliOutput.slice(start)).not.toContain( - 'Fast Refresh had to perform a full reload. Read more: https://nextjs.org/docs/basic-features/fast-refresh#how-it-works' - ) + expect(next.cliOutput.slice(start)).not.toContain(cliWarning) const currentFileContent = await next.readFile( './pages/hmr/anonymous-page-function.js' @@ -799,13 +800,8 @@ describe('basic HMR', () => { 'hello world!!!' ) - // CLI warning and stacktrace - expect(next.cliOutput.slice(start)).toContain( - 'Fast Refresh had to perform a full reload. Read more: https://nextjs.org/docs/basic-features/fast-refresh#how-it-works' - ) - expect(next.cliOutput.slice(start)).toContain( - 'Error: Aborted because ./pages/hmr/anonymous-page-function.js is not accepted' - ) + // CLI warning + expect(next.cliOutput.slice(start)).toContain(cliWarning) // Browser warning const browserLogs = await browser.log() @@ -821,13 +817,14 @@ describe('basic HMR', () => { it('should warn about full reload in cli output - runtime-error', async () => { const start = next.cliOutput.length const browser = await webdriver(next.appPort, `/hmr/runtime-error`) + const cliWarning = + 'Fast Refresh had to perform a full reload due to a runtime error.' + await check( () => getRedboxHeader(browser), /ReferenceError: whoops is not defined/ ) - expect(next.cliOutput.slice(start)).not.toContain( - 'Fast Refresh had to perform a full reload. Read more: https://nextjs.org/docs/basic-features/fast-refresh#how-it-works' - ) + expect(next.cliOutput.slice(start)).not.toContain(cliWarning) const currentFileContent = await next.readFile( './pages/hmr/runtime-error.js' @@ -842,13 +839,8 @@ describe('basic HMR', () => { 'whoops' ) - // CLI warning and stacktrace - expect(next.cliOutput.slice(start)).toContain( - 'Fast Refresh had to perform a full reload. Read more: https://nextjs.org/docs/basic-features/fast-refresh#how-it-works' - ) - expect(next.cliOutput.slice(start)).not.toContain( - 'Error: Aborted because ./pages/runtime-error.js is not accepted' - ) + // CLI warning + expect(next.cliOutput.slice(start)).toContain(cliWarning) // Browser warning const browserLogs = await browser.log()