Files
Sebastian "Sebbie" SilbermannandGitHub 35a566b383 [strict-route-types] Ensure cache profiles and routes are type-checked even if .next is excluded (#87768)
Flagged behind `experimental.strictRouteTypes`

This fixes issues where cache profiles where not included or routes not validated if `.next` was excluded to squeeze out every bit of TypeScript performance.

It also fixes a redundant type-check since we have separate dev and prod dist folders.  If you run `next dev` and (`next build` or `next typegen`), you'd type-check routes and links twice. Now `next-env.d.ts` only exists once where we decide which dist folder to type-check.

Going forward, new Next.js type-checking should be added to `next-env.d.ts`. That file is fully controlled by Next.js and churning it, does not churn users since it's not in version control.

`next-env.d.ts` will be moved into `.next` in a follow-up. Ideally independent of the dist folder i.e.  independent of `next dev` vs `next build`.

Closes https://linear.app/vercel/issue/NXT-124/

https://github.com/vercel/next.js/pull/87319 but flagged.
2026-01-06 16:21:25 +01:00

108 lines
2.7 KiB
TypeScript

import { nextTestSetup } from 'e2e-utils'
import { retry } from 'next-test-utils'
import stripAnsi from 'strip-ansi'
const strictRouteTypes =
process.env.__NEXT_EXPERIMENTAL_STRICT_ROUTE_TYPES === 'true'
describe('tsconfig module: preserve', () => {
const { next, skipped } = nextTestSetup({
files: {
'tsconfig.json': JSON.stringify({
compilerOptions: { module: 'preserve' },
}),
'pages/index.tsx': `
export default function Page() {
return <p>hello world</p>
}
`,
},
// This test is skipped because it relies on `next.readFile`
skipDeployment: true,
dependencies: {
typescript: '5.4.4',
},
})
if (skipped) return
it('allows you to skip moduleResolution, esModuleInterop and resolveJsonModule when using "module: preserve"', async () => {
let output = ''
await retry(() => {
output = stripAnsi(next.cliOutput)
expect(output).toContain(
'The following mandatory changes were made to your tsconfig.json'
)
})
expect(output).not.toContain('moduleResolution')
expect(output).not.toContain('esModuleInterop')
expect(output).not.toContain('resolveJsonModule')
if (strictRouteTypes) {
expect(await next.readFile('tsconfig.json')).toMatchInlineSnapshot(`
"{
"compilerOptions": {
"module": "preserve",
"target": "ES2017",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"strict": false,
"noEmit": true,
"incremental": true,
"isolatedModules": true,
"jsx": "react-jsx"
},
"include": [
"next-env.d.ts",
"**/*.mts",
"**/*.ts",
"**/*.tsx"
],
"exclude": [
"node_modules"
]
}
"
`)
} else {
expect(await next.readFile('tsconfig.json')).toMatchInlineSnapshot(`
"{
"compilerOptions": {
"module": "preserve",
"target": "ES2017",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"strict": false,
"noEmit": true,
"incremental": true,
"isolatedModules": true,
"jsx": "react-jsx"
},
"include": [
"next-env.d.ts",
"**/*.mts",
"**/*.ts",
"**/*.tsx"
],
"exclude": [
"node_modules"
]
}
"
`)
}
})
})