diff --git a/packages/next/src/build/webpack/plugins/wellknown-errors-plugin/parseNotFoundError.ts b/packages/next/src/build/webpack/plugins/wellknown-errors-plugin/parseNotFoundError.ts
index 82403320ca86..beb6f35ff5f0 100644
--- a/packages/next/src/build/webpack/plugins/wellknown-errors-plugin/parseNotFoundError.ts
+++ b/packages/next/src/build/webpack/plugins/wellknown-errors-plugin/parseNotFoundError.ts
@@ -116,9 +116,7 @@ export async function getNotFoundError(
)
if (moduleTrace.length === 0) return ''
- return `\nImport trace for requested module:\n${moduleTrace.join(
- '\n'
- )}\n\n`
+ return `\nImport trace for requested module:\n${moduleTrace.join('\n')}`
}
let message =
@@ -127,8 +125,8 @@ export async function getNotFoundError(
'\n' +
frame +
(frame !== '' ? '\n' : '') +
- importTrace() +
- '\nhttps://nextjs.org/docs/messages/module-not-found'
+ '\nhttps://nextjs.org/docs/messages/module-not-found\n' +
+ importTrace()
let formattedFileName: string = chalk.cyan(fileName)
if (lineNumber && column) {
diff --git a/packages/next/src/client/components/react-dev-overlay/internal/components/Terminal/Terminal.tsx b/packages/next/src/client/components/react-dev-overlay/internal/components/Terminal/Terminal.tsx
index 5bcfe72a1af6..ed61d5fd13e3 100644
--- a/packages/next/src/client/components/react-dev-overlay/internal/components/Terminal/Terminal.tsx
+++ b/packages/next/src/client/components/react-dev-overlay/internal/components/Terminal/Terminal.tsx
@@ -5,13 +5,19 @@ import { EditorLink } from './EditorLink'
export type TerminalProps = { content: string }
function getImportTraceFiles(content: string): [string, string[]] {
- if (/ReactServerComponentsError:/.test(content)) {
+ if (
+ /ReactServerComponentsError:/.test(content) ||
+ /Import trace for requested module:/.test(content)
+ ) {
// It's an RSC Build Error
const lines = content.split('\n')
// Grab the lines at the end containing the files
const files = []
- while (/app\/.+\./.test(lines[lines.length - 1])) {
+ while (
+ /.+\..+/.test(lines[lines.length - 1]) &&
+ !lines[lines.length - 1].includes(':')
+ ) {
const file = lines.pop()!.trim()
files.unshift(file)
}
diff --git a/test/development/acceptance-app/__snapshots__/ReactRefreshLogBox-builtins.test.ts.snap b/test/development/acceptance-app/__snapshots__/ReactRefreshLogBox-builtins.test.ts.snap
index 6b6d37ce8191..9ba9510722cd 100644
--- a/test/development/acceptance-app/__snapshots__/ReactRefreshLogBox-builtins.test.ts.snap
+++ b/test/development/acceptance-app/__snapshots__/ReactRefreshLogBox-builtins.test.ts.snap
@@ -8,10 +8,10 @@ Module not found: Can't resolve 'b'
3 | return (
4 |
-Import trace for requested module:
-./app/page.js
+https://nextjs.org/docs/messages/module-not-found
-https://nextjs.org/docs/messages/module-not-found"
+Import trace for requested module:
+./app/page.js"
`;
exports[`ReactRefreshLogBox app default Module not found empty import trace 1`] = `
@@ -44,9 +44,9 @@ exports[`ReactRefreshLogBox app default Node.js builtins 1`] = `
"./node_modules/my-package/index.js:2:0
Module not found: Can't resolve 'dns'
+https://nextjs.org/docs/messages/module-not-found
+
Import trace for requested module:
./index.js
-./app/page.js
-
-https://nextjs.org/docs/messages/module-not-found"
+./app/page.js"
`;
diff --git a/test/development/acceptance-app/__snapshots__/ReactRefreshLogBox.test.ts.snap b/test/development/acceptance-app/__snapshots__/ReactRefreshLogBox.test.ts.snap
index f85bf0bf7411..da2c995d1e24 100644
--- a/test/development/acceptance-app/__snapshots__/ReactRefreshLogBox.test.ts.snap
+++ b/test/development/acceptance-app/__snapshots__/ReactRefreshLogBox.test.ts.snap
@@ -4,10 +4,10 @@ exports[`ReactRefreshLogBox app default Can't resolve @import in CSS file 1`] =
"./app/styles2.css
Module not found: Can't resolve './boom.css'
-Import trace for requested module:
-./app/styles1.css
+https://nextjs.org/docs/messages/module-not-found
-https://nextjs.org/docs/messages/module-not-found"
+Import trace for requested module:
+./app/styles1.css"
`;
exports[`ReactRefreshLogBox app default Import trace when module not found in layout 1`] = `
@@ -15,10 +15,10 @@ exports[`ReactRefreshLogBox app default Import trace when module not found in la
Module not found: Can't resolve 'non-existing-module'
> 1 | import \\"non-existing-module\\"
-Import trace for requested module:
-./app/layout.js
+https://nextjs.org/docs/messages/module-not-found
-https://nextjs.org/docs/messages/module-not-found"
+Import trace for requested module:
+./app/layout.js"
`;
exports[`ReactRefreshLogBox app default Should not show __webpack_exports__ when exporting anonymous arrow function 1`] = `
diff --git a/test/development/acceptance-app/editor-links.test.ts b/test/development/acceptance-app/editor-links.test.ts
new file mode 100644
index 000000000000..d9b3c6e30e1b
--- /dev/null
+++ b/test/development/acceptance-app/editor-links.test.ts
@@ -0,0 +1,148 @@
+import { check } from 'next-test-utils'
+import { createNextDescribe, FileRef } from 'e2e-utils'
+import path from 'path'
+import { sandbox } from './helpers'
+
+async function clickEditorLinks(browser: any) {
+ await browser.waitForElementByCss('[data-with-open-in-editor-link]')
+ const collapsedFrameworkGroups = await browser.elementsByCss(
+ '[data-with-open-in-editor-link]'
+ )
+ for (const collapsedFrameworkButton of collapsedFrameworkGroups) {
+ await collapsedFrameworkButton.click()
+ }
+}
+
+createNextDescribe(
+ 'Error overlay - editor links',
+ {
+ files: new FileRef(path.join(__dirname, 'fixtures', 'default-template')),
+ dependencies: {
+ react: 'latest',
+ 'react-dom': 'latest',
+ },
+ skipStart: true,
+ },
+ ({ next }) => {
+ it('should be possible to open files on RSC build error', async () => {
+ let editorRequestsCount = 0
+ const { session, browser, cleanup } = await sandbox(
+ next,
+ new Map([
+ [
+ 'app/page.js',
+ `
+ import Component from '../index'
+ export default function Page() {
+ return
+ }
+ `,
+ ],
+ ]),
+ undefined,
+ {
+ beforePageLoad(page) {
+ page.route('**/__nextjs_launch-editor**', (route) => {
+ editorRequestsCount += 1
+ route.fulfill()
+ })
+ },
+ }
+ )
+
+ await session.patch(
+ 'index.js',
+ `import { useState } from 'react'
+ export default () => 'hello world'`
+ )
+
+ expect(await session.hasRedbox(true)).toBe(true)
+ await clickEditorLinks(browser)
+ await check(() => editorRequestsCount, /2/)
+
+ await cleanup()
+ })
+
+ it('should be possible to open files on RSC parse error', async () => {
+ let editorRequestsCount = 0
+ const { session, browser, cleanup } = await sandbox(
+ next,
+ new Map([
+ [
+ 'app/page.js',
+ `
+ import Component from '../index'
+ export default function Page() {
+ return
+ }
+ `,
+ ],
+ ['mod1.js', "import './mod2.js'"],
+ ['mod2.js', '{{{{{'],
+ ]),
+ undefined,
+ {
+ beforePageLoad(page) {
+ page.route('**/__nextjs_launch-editor**', (route) => {
+ editorRequestsCount += 1
+ route.fulfill()
+ })
+ },
+ }
+ )
+
+ await session.patch(
+ 'index.js',
+ `import './mod1'
+ export default () => 'hello world'`
+ )
+
+ expect(await session.hasRedbox(true)).toBe(true)
+ await clickEditorLinks(browser)
+ await check(() => editorRequestsCount, /4/)
+
+ await cleanup()
+ })
+
+ it('should be possible to open files on module not found error', async () => {
+ let editorRequestsCount = 0
+ const { session, browser, cleanup } = await sandbox(
+ next,
+ new Map([
+ [
+ 'app/page.js',
+ `
+ import Component from '../index'
+ export default function Page() {
+ return
+ }
+ `,
+ ],
+ ['mod1.js', "import './mod2.js'"],
+ ['mod2.js', 'import "boom"'],
+ ]),
+ undefined,
+ {
+ beforePageLoad(page) {
+ page.route('**/__nextjs_launch-editor**', (route) => {
+ editorRequestsCount += 1
+ route.fulfill()
+ })
+ },
+ }
+ )
+
+ await session.patch(
+ 'index.js',
+ `import './mod1'
+ export default () => 'hello world'`
+ )
+
+ expect(await session.hasRedbox(true)).toBe(true)
+ await clickEditorLinks(browser)
+ await check(() => editorRequestsCount, /3/)
+
+ await cleanup()
+ })
+ }
+)
diff --git a/test/development/acceptance-app/rsc-build-errors.test.ts b/test/development/acceptance-app/rsc-build-errors.test.ts
index c6efdbd41697..2992540334ca 100644
--- a/test/development/acceptance-app/rsc-build-errors.test.ts
+++ b/test/development/acceptance-app/rsc-build-errors.test.ts
@@ -1,4 +1,3 @@
-import { check } from 'next-test-utils'
import { createNextDescribe, FileRef } from 'e2e-utils'
import path from 'path'
import { sandbox } from './helpers'
@@ -267,46 +266,5 @@ createNextDescribe(
await cleanup()
})
-
- it('should be possible to open the import trace files in your editor', async () => {
- let editorRequestsCount = 0
- const { session, browser, cleanup } = await sandbox(
- next,
- undefined,
- '/editor-links',
- {
- beforePageLoad(page) {
- page.route('**/__nextjs_launch-editor**', (route) => {
- editorRequestsCount += 1
- route.fulfill()
- })
- },
- }
- )
-
- const componentFile = 'app/editor-links/component.js'
- const fileContent = await next.readFile(componentFile)
-
- await session.patch(
- componentFile,
- fileContent.replace(
- "// import { useState } from 'react'",
- "import { useState } from 'react'"
- )
- )
-
- expect(await session.hasRedbox(true)).toBe(true)
- await browser.waitForElementByCss('[data-with-open-in-editor-link]')
- const collapsedFrameworkGroups = await browser.elementsByCss(
- '[data-with-open-in-editor-link]'
- )
- for (const collapsedFrameworkButton of collapsedFrameworkGroups) {
- await collapsedFrameworkButton.click()
- }
-
- await check(() => editorRequestsCount, /2/)
-
- await cleanup()
- })
}
)
diff --git a/test/development/acceptance/__snapshots__/ReactRefreshLogBox-builtins.test.ts.snap b/test/development/acceptance/__snapshots__/ReactRefreshLogBox-builtins.test.ts.snap
index 5b11d2ab4fb7..61b51fea3087 100644
--- a/test/development/acceptance/__snapshots__/ReactRefreshLogBox-builtins.test.ts.snap
+++ b/test/development/acceptance/__snapshots__/ReactRefreshLogBox-builtins.test.ts.snap
@@ -32,19 +32,19 @@ Module not found: Can't resolve 'b'
3 | return (
4 |
-Import trace for requested module:
-./pages/index.js
+https://nextjs.org/docs/messages/module-not-found
-https://nextjs.org/docs/messages/module-not-found"
+Import trace for requested module:
+./pages/index.js"
`;
exports[`ReactRefreshLogBox default Node.js builtins 1`] = `
"./node_modules/my-package/index.js:2:0
Module not found: Can't resolve 'dns'
+https://nextjs.org/docs/messages/module-not-found
+
Import trace for requested module:
./index.js
-./pages/index.js
-
-https://nextjs.org/docs/messages/module-not-found"
+./pages/index.js"
`;