Skip to content

Commit dd315fd

Browse files
committed
[build-sourcemaps] Sourcemap errors during prerender if experimental.enablePrerenderSourceMaps is enabled
Plan is to enable it internally and track build times for a week. I don't expect any noticeable difference. The plan is to make it the default. You can already op-in today by including `--enable-source-maps` in `NODE_OPTIONS` during `next build`.
1 parent 94cc82e commit dd315fd

File tree

7 files changed

+121
-29
lines changed

7 files changed

+121
-29
lines changed

packages/next/src/build/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -758,6 +758,7 @@ export function createStaticWorker(
758758
progress?.clear()
759759
},
760760
debuggerPortOffset,
761+
enableSourceMaps: config.experimental.enablePrerenderSourceMaps,
761762
// remove --max-old-space-size flag as it can cause memory issues.
762763
isolatedMemory: true,
763764
enableWorkerThreads: config.experimental.workerThreads,

packages/next/src/lib/worker.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ export class Worker {
4343
* `-1` if not inspectable
4444
*/
4545
debuggerPortOffset: number
46+
enableSourceMaps?: boolean
4647
/**
4748
* True if `--max-old-space-size` should not be forwarded to the worker.
4849
*/
@@ -57,6 +58,7 @@ export class Worker {
5758
}
5859
) {
5960
let {
61+
enableSourceMaps,
6062
timeout,
6163
onRestart,
6264
logger = console,
@@ -91,6 +93,10 @@ export class Worker {
9193
}
9294
}
9395

96+
if (enableSourceMaps) {
97+
nodeOptions['enable-source-maps'] = true
98+
}
99+
94100
if (isolatedMemory) {
95101
delete nodeOptions['max-old-space-size']
96102
delete nodeOptions['max_old_space_size']

packages/next/src/server/config-schema.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,7 @@ export const configSchema: zod.ZodType<NextConfig> = z.lazy(() =>
463463
optimizeServerReact: z.boolean().optional(),
464464
clientTraceMetadata: z.array(z.string()).optional(),
465465
serverMinification: z.boolean().optional(),
466+
enablePrerenderSourceMaps: z.boolean().optional(),
466467
serverSourceMaps: z.boolean().optional(),
467468
useWasmBinary: z.boolean().optional(),
468469
useLightningcss: z.boolean().optional(),

packages/next/src/server/config-shared.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,11 @@ export interface ExperimentalConfig {
551551
*/
552552
serverMinification?: boolean
553553

554+
/**
555+
* Enables source maps while exporting pages.
556+
*/
557+
enablePrerenderSourceMaps?: boolean
558+
554559
/**
555560
* Enables source maps generation for the server production bundle.
556561
*/
@@ -1293,6 +1298,7 @@ export const defaultConfig: NextConfig = {
12931298
appNavFailHandling: false,
12941299
prerenderEarlyExit: true,
12951300
serverMinification: true,
1301+
enablePrerenderSourceMaps: false,
12961302
serverSourceMaps: false,
12971303
linkNoTouchStart: false,
12981304
caseSensitiveRoutes: false,

test/e2e/app-dir/server-source-maps/fixtures/default/next.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ const nextConfig = {
55
experimental: {
66
cpus: 1,
77
dynamicIO: true,
8+
enablePrerenderSourceMaps: true,
89
serverSourceMaps: true,
910
},
1011
serverExternalPackages: ['external-pkg'],

test/e2e/app-dir/server-source-maps/fixtures/edge/next.config.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
*/
44
const nextConfig = {
55
experimental: {
6+
cpus: 1,
7+
enablePrerenderSourceMaps: true,
68
serverSourceMaps: true,
79
},
810
}

test/e2e/app-dir/server-source-maps/server-source-maps.test.ts

Lines changed: 104 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@ describe('app-dir - server source maps', () => {
2525
if (skipped) return
2626

2727
it('logged errors have a sourcemapped stack with a codeframe', async () => {
28-
const outputIndex = next.cliOutput.length
29-
await next.render('/rsc-error-log')
30-
3128
if (isNextDev) {
29+
const outputIndex = next.cliOutput.length
30+
await next.render('/rsc-error-log')
31+
3232
await retry(() => {
3333
expect(next.cliOutput.slice(outputIndex)).toContain(
3434
'Error: rsc-error-log'
@@ -48,15 +48,28 @@ describe('app-dir - server source maps', () => {
4848
'\n'
4949
)
5050
} else {
51-
// TODO: Test `next build` with `--enable-source-maps`.
51+
if (isTurbopack) {
52+
// TODO(veil): Sourcemap names
53+
// TODO(veil): relative paths
54+
expect(normalizeCliOutput(next.cliOutput)).toContain(
55+
'(turbopack:///[project]/app/rsc-error-log/page.js:4:16)'
56+
)
57+
expect(normalizeCliOutput(next.cliOutput)).toContain(
58+
'' +
59+
"\n> 4 | const error = new Error('rsc-error-log')" +
60+
'\n | ^'
61+
)
62+
} else {
63+
// TODO(veil): Webpack's sourcemaps are flaky. lol.
64+
}
5265
}
5366
})
5467

5568
it('logged errors have a sourcemapped `cause`', async () => {
56-
const outputIndex = next.cliOutput.length
57-
await next.render('/rsc-error-log-cause')
58-
5969
if (isNextDev) {
70+
const outputIndex = next.cliOutput.length
71+
await next.render('/rsc-error-log-cause')
72+
6073
await retry(() => {
6174
expect(next.cliOutput.slice(outputIndex)).toContain(
6275
'Error: rsc-error-log-cause'
@@ -84,15 +97,36 @@ describe('app-dir - server source maps', () => {
8497
'\n'
8598
)
8699
} else {
87-
// TODO: Test `next build` with `--enable-source-maps`.
100+
if (isTurbopack) {
101+
// TODO(veil): Sourcemap names
102+
// TODO(veil): relative paths
103+
expect(normalizeCliOutput(next.cliOutput)).toContain(
104+
'(turbopack:///[project]/app/rsc-error-log-cause/page.js:2:16)'
105+
)
106+
expect(normalizeCliOutput(next.cliOutput)).toContain(
107+
'(turbopack:///[project]/app/rsc-error-log-cause/page.js:7:16)'
108+
)
109+
expect(normalizeCliOutput(next.cliOutput)).toContain(
110+
'' +
111+
"\n> 2 | const error = new Error('rsc-error-log-cause', { cause })" +
112+
'\n | ^'
113+
)
114+
expect(normalizeCliOutput(next.cliOutput)).toContain(
115+
'' +
116+
"\n > 7 | const error = new Error('Boom')" +
117+
'\n | ^'
118+
)
119+
} else {
120+
// TODO(veil): Webpack's sourcemaps are flaky. lol.
121+
}
88122
}
89123
})
90124

91125
it('stack frames are ignore-listed in ssr', async () => {
92-
const outputIndex = next.cliOutput.length
93-
const browser = await next.browser('/ssr-error-log-ignore-listed')
94-
95126
if (isNextDev) {
127+
const outputIndex = next.cliOutput.length
128+
const browser = await next.browser('/ssr-error-log-ignore-listed')
129+
96130
await retry(() => {
97131
expect(next.cliOutput.slice(outputIndex)).toContain(
98132
'Error: ssr-error-log-ignore-listed'
@@ -189,7 +223,19 @@ describe('app-dir - server source maps', () => {
189223
`)
190224
}
191225
} else {
192-
// TODO: Test `next build` with `--enable-source-maps`.
226+
if (isTurbopack) {
227+
// TODO(veil): Sourcemapping line off
228+
// TODO(veil): Sourcemap names
229+
// TODO(veil): relative paths
230+
expect(normalizeCliOutput(next.cliOutput)).toContain(
231+
'(turbopack:///[project]/app/ssr-error-log-ignore-listed/page.js:24:2)'
232+
)
233+
expect(normalizeCliOutput(next.cliOutput)).toContain(
234+
'\n> 24 | })\n | ^'
235+
)
236+
} else {
237+
// TODO(veil): Webpack's sourcemaps are flaky. lol.
238+
}
193239
}
194240
})
195241

@@ -242,15 +288,28 @@ describe('app-dir - server source maps', () => {
242288
'\n'
243289
)
244290
} else {
245-
// TODO: Test `next build` with `--enable-source-maps`.
291+
if (isTurbopack) {
292+
// TODO(veil): Sourcemap names
293+
// TODO(veil): relative paths
294+
expect(normalizeCliOutput(next.cliOutput)).toContain(
295+
'at <unknown> (turbopack:///[project]/app/rsc-error-log-ignore-listed/page.js:8:16)'
296+
)
297+
expect(normalizeCliOutput(next.cliOutput)).toContain(
298+
'' +
299+
"\n> 8 | const error = new Error('rsc-error-log-ignore-listed')" +
300+
'\n | ^'
301+
)
302+
} else {
303+
// TODO(veil): Webpack's sourcemaps are flaky. lol.
304+
}
246305
}
247306
})
248307

249308
it('thrown SSR errors', async () => {
250-
const outputIndex = next.cliOutput.length
251-
const browser = await next.browser('/ssr-throw')
252-
253309
if (isNextDev) {
310+
const outputIndex = next.cliOutput.length
311+
const browser = await next.browser('/ssr-throw')
312+
254313
await retry(() => {
255314
expect(next.cliOutput.slice(outputIndex)).toContain('Error: ssr-throw')
256315
})
@@ -287,13 +346,16 @@ describe('app-dir - server source maps', () => {
287346
}
288347
`)
289348
} else {
290-
// TODO: Test `next build` with `--enable-source-maps`.
349+
// SSR errors are not logged because React retries them during hydration.
291350
}
292351
})
293352

294353
it('logged errors preserve their name', async () => {
295-
const outputIndex = next.cliOutput.length
296-
await next.render('/rsc-error-log-custom-name')
354+
let outputIndex = 0
355+
if (isNextDev) {
356+
outputIndex = next.cliOutput.length
357+
await next.render('/rsc-error-log-custom-name')
358+
}
297359

298360
await retry(() => {
299361
expect(next.cliOutput.slice(outputIndex)).toContain(
@@ -313,16 +375,15 @@ describe('app-dir - server source maps', () => {
313375
})
314376

315377
it('handles invalid sourcemaps gracefully', async () => {
316-
const outputIndex = next.cliOutput.length
317-
await next.render('/bad-sourcemap')
318-
319-
await retry(() => {
320-
expect(normalizeCliOutput(next.cliOutput.slice(outputIndex))).toContain(
321-
'Error: bad-sourcemap'
322-
)
323-
})
324-
325378
if (isNextDev) {
379+
const outputIndex = next.cliOutput.length
380+
await next.render('/bad-sourcemap')
381+
382+
await retry(() => {
383+
expect(normalizeCliOutput(next.cliOutput.slice(outputIndex))).toContain(
384+
'Error: bad-sourcemap'
385+
)
386+
})
326387
if (isTurbopack) {
327388
expect(normalizeCliOutput(next.cliOutput.slice(outputIndex))).toContain(
328389
// Node.js is fine with invalid URLs in index maps apparently.
@@ -353,7 +414,21 @@ describe('app-dir - server source maps', () => {
353414
).toEqual(3)
354415
}
355416
} else {
356-
// TODO: test `next start` with `--enable-source-maps`
417+
if (isTurbopack) {
418+
// Expect the invalid sourcemap warning only once per render.
419+
// Dynamic I/O renders two times.
420+
expect(
421+
normalizeCliOutput(next.cliOutput).split('Invalid source map.')
422+
.length - 1
423+
).toEqual(2)
424+
} else {
425+
// Webpack is silent about invalid sourcemaps for next build.
426+
427+
expect(
428+
normalizeCliOutput(next.cliOutput).split('Invalid source map.')
429+
.length - 1
430+
).toEqual(0)
431+
}
357432
}
358433
})
359434
})

0 commit comments

Comments
 (0)