Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/swift-socks-find.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'next': patch
---

Sourcemap errors during prerender if `experimental.enablePrerenderSourceMaps` is enabled
1 change: 1 addition & 0 deletions packages/next/src/build/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -758,6 +758,7 @@ export function createStaticWorker(
progress?.clear()
},
debuggerPortOffset,
enableSourceMaps: config.experimental.enablePrerenderSourceMaps,
// remove --max-old-space-size flag as it can cause memory issues.
isolatedMemory: true,
enableWorkerThreads: config.experimental.workerThreads,
Expand Down
6 changes: 6 additions & 0 deletions packages/next/src/lib/worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export class Worker {
* `-1` if not inspectable
*/
debuggerPortOffset: number
enableSourceMaps?: boolean
/**
* True if `--max-old-space-size` should not be forwarded to the worker.
*/
Expand All @@ -57,6 +58,7 @@ export class Worker {
}
) {
let {
enableSourceMaps,
timeout,
onRestart,
logger = console,
Expand Down Expand Up @@ -91,6 +93,10 @@ export class Worker {
}
}

if (enableSourceMaps) {
nodeOptions['enable-source-maps'] = true
}

if (isolatedMemory) {
delete nodeOptions['max-old-space-size']
delete nodeOptions['max_old_space_size']
Expand Down
1 change: 1 addition & 0 deletions packages/next/src/server/config-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,7 @@ export const configSchema: zod.ZodType<NextConfig> = z.lazy(() =>
optimizeServerReact: z.boolean().optional(),
clientTraceMetadata: z.array(z.string()).optional(),
serverMinification: z.boolean().optional(),
enablePrerenderSourceMaps: z.boolean().optional(),
serverSourceMaps: z.boolean().optional(),
useWasmBinary: z.boolean().optional(),
useLightningcss: z.boolean().optional(),
Expand Down
7 changes: 7 additions & 0 deletions packages/next/src/server/config-shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,12 @@ export interface ExperimentalConfig {
*/
serverMinification?: boolean

/**
* Enables source maps while generating static pages.
* Helps with errors during the prerender phase in `next build`.
*/
enablePrerenderSourceMaps?: boolean

/**
* Enables source maps generation for the server production bundle.
*/
Expand Down Expand Up @@ -1309,6 +1315,7 @@ export const defaultConfig = {
appNavFailHandling: false,
prerenderEarlyExit: true,
serverMinification: true,
enablePrerenderSourceMaps: false,
serverSourceMaps: false,
linkNoTouchStart: false,
caseSensitiveRoutes: false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const nextConfig = {
cpus: 1,
ppr: true,
dynamicIO: true,
enablePrerenderSourceMaps: true,
serverSourceMaps: true,
},
serverExternalPackages: ['external-pkg'],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
*/
const nextConfig = {
experimental: {
cpus: 1,
enablePrerenderSourceMaps: true,
serverSourceMaps: true,
},
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ describe('app-dir - server source maps edge runtime', () => {
'\n}'
)
} else {
// TODO: Test `next build` with `--enable-source-maps`.
// Edge runtime pages are not prerendered during `next build`.
// `next start` is not sourcemapped on purpose.
}
})

Expand Down Expand Up @@ -71,7 +72,8 @@ describe('app-dir - server source maps edge runtime', () => {
)
expect(cliOutput).toMatch(/digest: '\d+'/)
} else {
// TODO: Test `next build` with `--enable-source-maps`.
// Edge runtime pages are not prerendered during `next build`.
// `next start` is not sourcemapped on purpose.
}
})

Expand Down Expand Up @@ -99,7 +101,8 @@ describe('app-dir - server source maps edge runtime', () => {
)
expect(cliOutput).toMatch(/digest: '\d+'/)
} else {
// TODO: Test `next build` with `--enable-source-maps`.
// Edge runtime pages are not prerendered during `next build`.
// `next start` is not sourcemapped on purpose.
}
})
})
111 changes: 93 additions & 18 deletions test/e2e/app-dir/server-source-maps/server-source-maps.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ describe('app-dir - server source maps', () => {
if (skipped) return

it('logged errors have a sourcemapped stack with a codeframe', async () => {
const outputIndex = next.cliOutput.length
await next.render('/rsc-error-log')

if (isNextDev) {
const outputIndex = next.cliOutput.length
await next.render('/rsc-error-log')

await retry(() => {
expect(next.cliOutput.slice(outputIndex)).toContain(
'Error: rsc-error-log'
Expand All @@ -48,15 +48,28 @@ describe('app-dir - server source maps', () => {
'\n'
)
} else {
// TODO: Test `next build` with `--enable-source-maps`.
if (isTurbopack) {
// TODO(veil): Sourcemap names
// TODO(veil): relative paths
expect(normalizeCliOutput(next.cliOutput)).toContain(
'(turbopack:///[project]/app/rsc-error-log/page.js:4:16)'
)
expect(normalizeCliOutput(next.cliOutput)).toContain(
'' +
"\n> 4 | const error = new Error('rsc-error-log')" +
'\n | ^'
)
} else {
// TODO(veil): line/column numbers are flaky in Webpack
}
}
})

it('logged errors have a sourcemapped `cause`', async () => {
const outputIndex = next.cliOutput.length
await next.render('/rsc-error-log-cause')

if (isNextDev) {
const outputIndex = next.cliOutput.length
await next.render('/rsc-error-log-cause')

await retry(() => {
expect(next.cliOutput.slice(outputIndex)).toContain(
'Error: rsc-error-log-cause'
Expand Down Expand Up @@ -84,15 +97,36 @@ describe('app-dir - server source maps', () => {
'\n'
)
} else {
// TODO: Test `next build` with `--enable-source-maps`.
if (isTurbopack) {
// TODO(veil): Sourcemap names
// TODO(veil): relative paths
expect(normalizeCliOutput(next.cliOutput)).toContain(
'(turbopack:///[project]/app/rsc-error-log-cause/page.js:2:16)'
)
expect(normalizeCliOutput(next.cliOutput)).toContain(
'(turbopack:///[project]/app/rsc-error-log-cause/page.js:7:16)'
)
expect(normalizeCliOutput(next.cliOutput)).toContain(
'' +
"\n> 2 | const error = new Error('rsc-error-log-cause', { cause })" +
'\n | ^'
)
expect(normalizeCliOutput(next.cliOutput)).toContain(
'' +
"\n > 7 | const error = new Error('Boom')" +
'\n | ^'
)
} else {
// TODO(veil): line/column numbers are flaky in Webpack
}
}
})

it('stack frames are ignore-listed in ssr', async () => {
const outputIndex = next.cliOutput.length
const browser = await next.browser('/ssr-error-log-ignore-listed')

if (isNextDev) {
const outputIndex = next.cliOutput.length
const browser = await next.browser('/ssr-error-log-ignore-listed')

await retry(() => {
expect(next.cliOutput.slice(outputIndex)).toContain(
'Error: ssr-error-log-ignore-listed'
Expand Down Expand Up @@ -189,7 +223,19 @@ describe('app-dir - server source maps', () => {
`)
}
} else {
// TODO: Test `next build` with `--enable-source-maps`.
if (isTurbopack) {
// TODO(veil): Sourcemapping line off
// TODO(veil): Sourcemap names
// TODO(veil): relative paths
expect(normalizeCliOutput(next.cliOutput)).toContain(
'(turbopack:///[project]/app/ssr-error-log-ignore-listed/page.js:24:2)'
)
expect(normalizeCliOutput(next.cliOutput)).toContain(
'\n> 24 | })\n | ^'
)
} else {
// TODO(veil): line/column numbers are flaky in Webpack
}
}
})

Expand Down Expand Up @@ -242,15 +288,28 @@ describe('app-dir - server source maps', () => {
'\n'
)
} else {
// TODO: Test `next build` with `--enable-source-maps`.
if (isTurbopack) {
// TODO(veil): Sourcemap names
// TODO(veil): relative paths
expect(normalizeCliOutput(next.cliOutput)).toContain(
'at <unknown> (turbopack:///[project]/app/rsc-error-log-ignore-listed/page.js:8:16)'
)
expect(normalizeCliOutput(next.cliOutput)).toContain(
'' +
"\n> 8 | const error = new Error('rsc-error-log-ignore-listed')" +
'\n | ^'
)
} else {
// TODO(veil): line/column numbers are flaky in Webpack
}
}
})

it('thrown SSR errors', async () => {
const outputIndex = next.cliOutput.length
const browser = await next.browser('/ssr-throw')

if (isNextDev) {
const outputIndex = next.cliOutput.length
const browser = await next.browser('/ssr-throw')

await retry(() => {
expect(next.cliOutput.slice(outputIndex)).toContain('Error: ssr-throw')
})
Expand Down Expand Up @@ -287,7 +346,7 @@ describe('app-dir - server source maps', () => {
}
`)
} else {
// TODO: Test `next build` with `--enable-source-maps`.
// SSR errors are not logged because React retries them during hydration.
}
})

Expand Down Expand Up @@ -356,7 +415,23 @@ describe('app-dir - server source maps', () => {
).toEqual(3)
}
} else {
// TODO: test `next start` with `--enable-source-maps`
if (isTurbopack) {
// Expect the invalid sourcemap warning only once per render.
expect(
normalizeCliOutput(next.cliOutput).split('Invalid source map.')
.length - 1
).toEqual(
// >= 20
// behavior in Node.js 20+ is intended
process.versions.node.startsWith('18') ? 0 : 2
)
} else {
// Webpack is silent about invalid sourcemaps for next build.
expect(
normalizeCliOutput(next.cliOutput).split('Invalid source map.')
.length - 1
).toEqual(0)
}
}
})
})
Loading