Files
Luke SandbergandGitHub e0b2cebde5 Improve the NFT error message and ignore comment handling (#95144)
Fixes #95125 in two ways

The OP admits that they misread the message in a few ways, but we can
fix all of them

1. Be specific about what function might need an annotation in the error
message. A user with a nearby `path.join` might think that that is where
the annotation belongs instead of on the function with the warning.

2. Be more flexible with how these `ignore` comments are interpreted
`fs.readFileSync(path.join(process.cwd(), someVar))` shouldn't require 2
annotations. Handle this by checking for and detecting `turbopackIgnore`
comments in all expressions! This will then bubble up through the linker
and just cause us to ignore corresponding fs access apis.
2026-07-14 08:13:12 +02:00

171 lines
6.1 KiB
TypeScript

import { nextTestSetup } from 'e2e-utils'
import stripAnsi from 'strip-ansi'
// Only Turbopack prints these warnings
;(process.env.IS_TURBOPACK_TEST ? describe : describe.skip)(
'build-tracing-message',
() => {
describe('default', () => {
const { next } = nextTestSetup({
files: __dirname,
skipStart: true,
})
it('should warn when tracing all files in the project', async () => {
const { exitCode } = await next.build()
expect(exitCode).toBe(0)
const cliOutput = stripAnsi(next.cliOutput)
// Warnings are deferred until after static generation so that
// prerender errors are more prominent than compile warnings.
expect(
cliOutput.indexOf('Turbopack build encountered')
).toBeGreaterThan(cliOutput.indexOf('✓ Compiled successfully'))
const output = cliOutput
.slice(
cliOutput.indexOf('Turbopack build encountered'),
cliOutput.indexOf('Finalizing page optimization')
)
.trim()
expect(stripAnsi(output)).toMatchInlineSnapshot(`
"Turbopack build encountered 1 warning:
./app/join-cwd.js:4:10
Warning: Dynamic filesystem access causes tracing of the whole project
2 |
3 | export default function (f) {
> 4 | return path.join(process.cwd(), f)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
5 | }
6 |
Static analysis determined that this filesystem access causes the whole project to be traced and included in the output.
This is usually unintentional and leads to all source files (including the public folder) to be deployed as part of the server code.
This can slow down deployments or lead to failures when size limits are exceeded.
To resolve this, you can
- make sure the path is statically scoped to some subfolder, for example path.join(process.cwd(), 'data', bar), or
- only use them in development, or
- opt out by adding an ignore comment to the highlighted call: path.join(/*turbopackIgnore: true*/ ...), or
- remove them.
Import trace:
Server Component:
./app/join-cwd.js
./app/page.js"
`)
})
it('should not warn for fs calls annotated with turbopackIgnore', async () => {
// The build above (in the previous test) already ran; assert that none of
// the `turbopackIgnore`-annotated accesses in ./app/read-ignored.js produced
// a warning. This covers both the comment on the fs call's own argument
// (`readBareArg`) and the comment on a nested `path.join(...)` argument
// (`readJoinedArg`, issue #95125). Only ./app/join-cwd.js should warn.
expect(next.cliOutput).toContain(
'Turbopack build encountered 1 warning:'
)
expect(next.cliOutput).not.toContain('./app/read-ignored.js')
})
})
describe('with a prerender error', () => {
const { next } = nextTestSetup({
files: __dirname,
skipStart: true,
overrideFiles: {
'app/boom/page.js': `export default function Page() {
throw new Error('boom during prerender')
}`,
},
})
it('should print warnings after prerender errors', async () => {
const { exitCode } = await next.build()
expect(exitCode).not.toBe(0)
const cliOutput = stripAnsi(next.cliOutput)
const prerenderErrorIndex = cliOutput.indexOf(
'Error occurred prerendering page "/boom"'
)
const exitingBuildIndex = cliOutput.indexOf(
'Export encountered an error on /boom/page: /boom, exiting the build.'
)
const warningIndex = cliOutput.indexOf(
'Turbopack build encountered 1 warning'
)
expect(prerenderErrorIndex).not.toBe(-1)
expect(exitingBuildIndex).not.toBe(-1)
expect(warningIndex).not.toBe(-1)
// The prerender error comes first, the deferred compile warnings
// after.
expect(warningIndex).toBeGreaterThan(prerenderErrorIndex)
expect(warningIndex).toBeGreaterThan(exitingBuildIndex)
})
})
describe('with a prerender error and prerenderEarlyExit disabled', () => {
const { next } = nextTestSetup({
files: __dirname,
skipStart: true,
overrideFiles: {
'app/boom/page.js': `export default function Page() {
throw new Error('boom during prerender')
}`,
'next.config.js': `/** @type {import('next').NextConfig} */
module.exports = {
experimental: { prerenderEarlyExit: false },
}`,
},
})
it('should print warnings after prerender errors and before the failure summary', async () => {
const { exitCode } = await next.build()
expect(exitCode).not.toBe(0)
const cliOutput = stripAnsi(next.cliOutput)
const prerenderErrorIndex = cliOutput.indexOf(
'Error occurred prerendering page "/boom"'
)
const warningIndex = cliOutput.indexOf(
'Turbopack build encountered 1 warning'
)
const exportErrorIndex = cliOutput.indexOf('Export encountered errors')
expect(prerenderErrorIndex).not.toBe(-1)
expect(warningIndex).not.toBe(-1)
expect(exportErrorIndex).not.toBe(-1)
// Prerender errors come first, then the deferred compile warnings,
// and the failure summary is printed last.
expect(warningIndex).toBeGreaterThan(prerenderErrorIndex)
expect(exportErrorIndex).toBeGreaterThan(warningIndex)
})
})
describe('output: export', () => {
const { next } = nextTestSetup({
files: __dirname,
skipStart: true,
overrideFiles: {
'next.config.js': `module.exports = { output: 'export' }`,
},
})
it('should not warn', async () => {
const { exitCode } = await next.build()
expect(exitCode).toBe(0)
expect(next.cliOutput).not.toContain(
'Dynamic filesystem access causes tracing of the whole project'
)
})
})
}
)