diff --git a/packages/next/src/build/webpack/plugins/define-env-plugin.ts b/packages/next/src/build/webpack/plugins/define-env-plugin.ts
index 08348354a1898..83fc3d1a566f4 100644
--- a/packages/next/src/build/webpack/plugins/define-env-plugin.ts
+++ b/packages/next/src/build/webpack/plugins/define-env-plugin.ts
@@ -290,7 +290,9 @@ export function getDefineEnv({
}
: undefined),
'process.env.__NEXT_EXPERIMENTAL_NEW_DEV_OVERLAY':
- config.experimental.newDevOverlay ?? false,
+ config.experimental.newDevOverlay ||
+ // Enable the new dev overlay when PPR is enabled for testing.
+ process.env.__NEXT_EXPERIMENTAL_PPR === 'true',
}
const userDefines = config.compiler?.define ?? {}
diff --git a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/code-frame/code-frame.tsx b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/code-frame/code-frame.tsx
index ee870c4b0bc4f..e26a42e109526 100644
--- a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/code-frame/code-frame.tsx
+++ b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/code-frame/code-frame.tsx
@@ -36,9 +36,7 @@ export function CodeFrame({ stackFrame, codeFrame }: CodeFrameProps) {
.map((line, a) =>
~(a = line.indexOf('|'))
? line.substring(0, a) +
- line
- .substring(a + 1)
- .replace(`^\\ {${miniLeadingSpacesLength}}`, '')
+ line.substring(a).replace(`^\\ {${miniLeadingSpacesLength}}`, '')
: line
)
.join('\n')
diff --git a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/errors/dev-tools-indicator/dev-tools-indicator.tsx b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/errors/dev-tools-indicator/dev-tools-indicator.tsx
index e238741f80d85..a281ee3f099f9 100644
--- a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/errors/dev-tools-indicator/dev-tools-indicator.tsx
+++ b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/errors/dev-tools-indicator/dev-tools-indicator.tsx
@@ -126,6 +126,7 @@ const DevToolsPopover = ({
return (
@@ -205,14 +207,15 @@ const IndicatorRow = ({
label,
value,
onClick,
+ ...props
}: {
label: string
value: React.ReactNode
onClick?: () => void
-}) => {
+} & React.HTMLAttributes) => {
const Wrapper = onClick ? 'button' : 'div'
return (
-
+
{label}
{value}
diff --git a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/errors/dev-tools-indicator/internal/next-logo.tsx b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/errors/dev-tools-indicator/internal/next-logo.tsx
index 786a680d165a8..06a64fb38769d 100644
--- a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/errors/dev-tools-indicator/internal/next-logo.tsx
+++ b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/errors/dev-tools-indicator/internal/next-logo.tsx
@@ -233,7 +233,8 @@ export const NextLogo = ({
aria-label="Open issues overlay"
onClick={onIssuesClick}
>
- {issueCount} {issueCount === 1 ? 'Issue' : 'Issues'}
+ {issueCount}{' '}
+ {issueCount === 1 ? 'Issue' : 'Issues'}
diff --git a/packages/next/src/client/components/react-dev-overlay/_experimental/pages/react-dev-overlay.tsx b/packages/next/src/client/components/react-dev-overlay/_experimental/pages/react-dev-overlay.tsx
index 7cf676c91ff18..ebc72c3c14fa6 100644
--- a/packages/next/src/client/components/react-dev-overlay/_experimental/pages/react-dev-overlay.tsx
+++ b/packages/next/src/client/components/react-dev-overlay/_experimental/pages/react-dev-overlay.tsx
@@ -20,41 +20,50 @@ interface ReactDevOverlayProps {
}
export default function ReactDevOverlay({ children }: ReactDevOverlayProps) {
- const { isMounted, state, onComponentError, hasRuntimeErrors } =
- usePagesReactDevOverlay()
-
- const [isErrorOverlayOpen, setIsErrorOverlayOpen] = useState(hasRuntimeErrors)
+ const {
+ isMounted,
+ state,
+ onComponentError,
+ hasRuntimeErrors,
+ hasBuildError,
+ } = usePagesReactDevOverlay()
const { readyErrors } = useErrorHook({
errors: state.errors,
isAppDir: false,
})
+ const [isErrorOverlayOpen, setIsErrorOverlayOpen] = useState(true)
+
return (
<>
{children ?? null}
-
-
-
-
-
-
-
-
-
-
+ {isMounted && (
+
+
+
+
+
+
+
+
+ {(hasRuntimeErrors || hasBuildError) && (
+
+ )}
+
+ )}
>
)
}
diff --git a/packages/next/src/client/components/react-dev-overlay/internal/container/RuntimeError/index.tsx b/packages/next/src/client/components/react-dev-overlay/internal/container/RuntimeError/index.tsx
index d1dfabbbac359..cb4b88b5bd1ff 100644
--- a/packages/next/src/client/components/react-dev-overlay/internal/container/RuntimeError/index.tsx
+++ b/packages/next/src/client/components/react-dev-overlay/internal/container/RuntimeError/index.tsx
@@ -33,7 +33,7 @@ export function RuntimeError({ error }: RuntimeErrorProps) {
? []
: filteredFrames.slice(0, firstFirstPartyFrameIndex),
trailingCallStackFrames: filteredFrames.slice(
- firstFirstPartyFrameIndex + 1
+ firstFirstPartyFrameIndex < 0 ? 0 : firstFirstPartyFrameIndex
),
}
}, [error.frames, isIgnoredExpanded])
diff --git a/test/development/acceptance-app/ReactRefreshLogBox.test.ts b/test/development/acceptance-app/ReactRefreshLogBox.test.ts
index ef1623a5671b0..ab425f3519000 100644
--- a/test/development/acceptance-app/ReactRefreshLogBox.test.ts
+++ b/test/development/acceptance-app/ReactRefreshLogBox.test.ts
@@ -799,7 +799,12 @@ describe.each(['default', 'turbo'])('ReactRefreshLogBox app %s', () => {
const stackFrames = (
await Promise.all(stackFrameElements.map((f) => f.innerText()))
).filter(Boolean)
- expect(stackFrames).toEqual([])
+ expect(stackFrames).toEqual([
+ outdent`
+ Page
+ app/page.js (4:11)
+ `,
+ ])
})
test('Call stack for server error', async () => {
@@ -831,7 +836,12 @@ describe.each(['default', 'turbo'])('ReactRefreshLogBox app %s', () => {
const stackFrames = (
await Promise.all(stackFrameElements.map((f) => f.innerText()))
).filter(Boolean)
- expect(stackFrames).toEqual([])
+ expect(stackFrames).toEqual([
+ outdent`
+ Page
+ app/page.js (2:9)
+ `,
+ ])
})
test('should hide unrelated frames in stack trace with unknown anonymous calls', async () => {
@@ -876,12 +886,20 @@ describe.each(['default', 'turbo'])('ReactRefreshLogBox app %s', () => {
// TODO: investigate the column number is off by 1 between turbo and webpack
process.env.TURBOPACK
? [
+ outdent`
+
+ app/page.js (4:13)
+ `,
outdent`
Page
app/page.js (5:6)
`,
]
: [
+ outdent`
+ eval
+ app/page.js (4:13)
+ `,
outdent`
Page
app/page.js (5:5)
@@ -923,8 +941,8 @@ describe.each(['default', 'turbo'])('ReactRefreshLogBox app %s', () => {
stackFrameElements.map((f) => f.innerText())
)
- // No following rest of displayed stack frames by default
- expect(stackFrames.length).toBe(0)
+ // No ignore-listed frames to be displayed by default
+ expect(stackFrames.length).toBe(1)
})
test('Server component errors should open up in fullscreen', async () => {
@@ -1211,13 +1229,15 @@ export default function Home() {
if (isTurbopack) {
// FIXME: display the sourcemapped stack frames
- expect(stackFrames).toMatchInlineSnapshot(
- `"at [project]/app/page.js [app-client] (ecmascript) (app/page.js (2:1))"`
- )
+ expect(stackFrames).toMatchInlineSnapshot(`
+ "at [project]/app/utils.ts [app-client] (ecmascript) (app/utils.ts (1:7))
+ at [project]/app/page.js [app-client] (ecmascript) (app/page.js (2:1))"
+ `)
} else {
// FIXME: Webpack stack frames are not source mapped
expect(stackFrames).toMatchInlineSnapshot(`
- "at ./app/utils.ts ()
+ "at eval (app/utils.ts (1:7))
+ at ./app/utils.ts ()
at options.factory ()
at __webpack_require__ ()
at fn ()
diff --git a/test/development/acceptance/ReactRefreshLogBox.test.ts b/test/development/acceptance/ReactRefreshLogBox.test.ts
index 643a7b54f23d6..66f748ce99405 100644
--- a/test/development/acceptance/ReactRefreshLogBox.test.ts
+++ b/test/development/acceptance/ReactRefreshLogBox.test.ts
@@ -793,10 +793,19 @@ describe.each(['default', 'turbo'])('ReactRefreshLogBox %s', () => {
await session.assertHasRedbox()
const stack = await getStackFramesContent(browser)
- expect(stack).toMatchInlineSnapshot(`
- "at Array.map ()
- at Page (pages/index.js (2:13))"
- `)
+ if (process.env.TURBOPACK) {
+ expect(stack).toMatchInlineSnapshot(`
+ "at (pages/index.js (3:11))
+ at Array.map ()
+ at Page (pages/index.js (2:13))"
+ `)
+ } else {
+ expect(stack).toMatchInlineSnapshot(`
+ "at eval (pages/index.js (3:11))
+ at Array.map ()
+ at Page (pages/index.js (2:13))"
+ `)
+ }
})
test('should collapse nodejs internal stack frames from stack trace', async () => {
@@ -824,9 +833,10 @@ describe.each(['default', 'turbo'])('ReactRefreshLogBox %s', () => {
await session.assertHasRedbox()
const stack = await getStackFramesContent(browser)
- expect(stack).toMatchInlineSnapshot(
- `"at getServerSideProps (pages/index.js (8:3))"`
- )
+ expect(stack).toMatchInlineSnapshot(`
+ "at createURL (pages/index.js (4:3))
+ at getServerSideProps (pages/index.js (8:3))"
+ `)
await toggleCollapseCallStackFrames(browser)
const stackCollapsed = await getStackFramesContent(browser)
diff --git a/test/development/app-dir/capture-console-error-owner-stack/capture-console-error-owner-stack.test.ts b/test/development/app-dir/capture-console-error-owner-stack/capture-console-error-owner-stack.test.ts
index d4f3395677ec5..196b009b1e247 100644
--- a/test/development/app-dir/capture-console-error-owner-stack/capture-console-error-owner-stack.test.ts
+++ b/test/development/app-dir/capture-console-error-owner-stack/capture-console-error-owner-stack.test.ts
@@ -42,45 +42,49 @@ describe('app-dir - capture-console-error-owner-stack', () => {
// TODO(veil): Inconsistent cursor position for the "Page" frame
if (process.env.TURBOPACK) {
expect(result).toMatchInlineSnapshot(`
- {
- "callStacks": "button
- (0:0)
- Page
- app/browser/event/page.js (5:5)",
- "count": 1,
- "description": "trigger an console ",
- "source": "app/browser/event/page.js (7:17) @ onClick
-
- 5 |