Skip to content

Commit af6c26c

Browse files
qrohlfshudingkodiakhq[bot]
authored
Stop overriding the user's TS config with defaults during next build (#45670)
## Bug The `next build` command is silently overriding the user's tsconfig when it shouldn't be; this results in mismatched behavior between `tsc --noEmit` and `yarn build` and user confusion. For example, a configuration option like `"moduleResolution": "nodenext"`, which is preserved and respected by `next dev`, will be silently overridden to `"moduleResolution": "node"` during `next build`. This change: - Fixes #38854 - (probably fixes) #45452 (I have not verified) - (probably fixes) #41189 (I have not verified) ## Details Next has a concept of both _defaults_ and _permitted options_ when modifying/validating the user's tsconfig. The user's config is only modified if it does not match the _permitted options_. This means that if the user has specified a permitted value like `"moduleResolution": "nodenext"`, it will not be overwritten in the user's config file. However, there was some logic in `runTypeCheck.ts` that did not adequately capture this nuance – instead, it spread all of the defaults into the tsconfig it was building before running typecheck, which meant that if a user had specified an option that was _permitted_ but _non-default_, it would be overwritten, silently, during `yarn build` only. Because Next is already (1) rewriting the TSconfig in `writeConfigurationDefaults` when the user's config doesn't line up with what we're expecting and (2) verifying the user's TSConfig remains correct (in `verifyTypeScriptSetup`) during a `next build`, I believe that it is safe to remove this config-steamrolling behavior. ## Documentation / Examples I believe this is strictly a bugfix; it updates the behavior of `next build` to conform to the same configuration behavior exhibited by `tsc --noEmit` and `next dev`. Since this is already the user expectation, it should not require documentation changes. --------- Co-authored-by: Shu Ding <[email protected]> Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
1 parent 087aa6e commit af6c26c

File tree

8 files changed

+66
-4
lines changed

8 files changed

+66
-4
lines changed

packages/next/src/lib/typescript/runTypeCheck.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ export async function runTypeCheck(
4141
const requiredConfig = getRequiredConfiguration(ts)
4242

4343
const options = {
44-
...effectiveConfiguration.options,
4544
...requiredConfig,
45+
...effectiveConfiguration.options,
4646
declarationMap: false,
4747
emitDeclarationOnly: false,
4848
noEmit: true,
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
1+
/* eslint-disable @typescript-eslint/no-unused-vars */
22
const blah: boolean = false
3-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
4-
const blah2 = import('../value').then((r) => r.default)
3+
// @ts-expect-error ignore the import issue here caused by https://github.com/microsoft/TypeScript/issues/49083
4+
const blah2 = import('../value.ts').then((r) => r.default)
55

66
export default () => <h3>Hello TypeScript</h3>
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import helloWorldString from 'pkg/sub-export'
2+
3+
export default function Page() {
4+
return <p>{helloWorldString}</p>
5+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"name": "pkg",
3+
"version": "1.0.0",
4+
"type": "module",
5+
"exports": {
6+
"./sub-export": "./src/some-file.js"
7+
}
8+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
declare const _default: 'Hello, world'
2+
export default _default
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export default 'Hello, world'
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { createNextDescribe, FileRef } from 'e2e-utils'
2+
import { join } from 'path'
3+
4+
// regression test suite for https://github.com/vercel/next.js/issues/38854
5+
createNextDescribe(
6+
'Does not override tsconfig moduleResolution field during build',
7+
{
8+
packageJson: { type: 'module' },
9+
files: {
10+
'tsconfig.json': new FileRef(join(__dirname, 'tsconfig.json')),
11+
pages: new FileRef(join(__dirname, 'pages')),
12+
pkg: new FileRef(join(__dirname, 'pkg')),
13+
},
14+
dependencies: {
15+
typescript: 'latest',
16+
'@types/react': 'latest',
17+
'@types/node': 'latest',
18+
pkg: './pkg',
19+
},
20+
},
21+
({ next }) => {
22+
it('boots and renders without throwing an error', async () => {
23+
await next.render$('/')
24+
})
25+
}
26+
)
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"compilerOptions": {
3+
"esModuleInterop": true,
4+
"module": "esnext",
5+
"jsx": "preserve",
6+
"target": "es5",
7+
"lib": ["dom", "dom.iterable", "esnext"],
8+
"allowJs": true,
9+
"skipLibCheck": true,
10+
"strict": true,
11+
"forceConsistentCasingInFileNames": true,
12+
"noEmit": true,
13+
"incremental": true,
14+
"moduleResolution": "nodenext",
15+
"resolveJsonModule": true,
16+
"isolatedModules": true
17+
},
18+
"exclude": ["node_modules"],
19+
"include": ["next-env.d.ts", "components", "pages"]
20+
}

0 commit comments

Comments
 (0)