diff --git a/packages/next/lib/typescript/writeConfigurationDefaults.ts b/packages/next/lib/typescript/writeConfigurationDefaults.ts index c534f63154eb..0aad82db632f 100644 --- a/packages/next/lib/typescript/writeConfigurationDefaults.ts +++ b/packages/next/lib/typescript/writeConfigurationDefaults.ts @@ -3,10 +3,11 @@ import chalk from 'next/dist/compiled/chalk' import * as CommentJson from 'next/dist/compiled/comment-json' import semver from 'next/dist/compiled/semver' import os from 'os' +import type { CompilerOptions } from 'typescript' import { getTypeScriptConfiguration } from './getTypeScriptConfiguration' type DesiredCompilerOptionsShape = { - [key: string]: + [K in keyof CompilerOptions]: | { suggested: any } | { parsedValue?: any @@ -58,8 +59,11 @@ function getDesiredCompilerOptions( parsedValues: [ ts.ModuleResolutionKind.NodeJs, ts.ModuleResolutionKind.Node12, + // only newer TypeScript versions have this field, it + // will be filtered for older ones + (ts.ModuleResolutionKind as any).Node16, ts.ModuleResolutionKind.NodeNext, - ], + ].filter((val) => typeof val !== 'undefined'), value: 'node', reason: 'to match webpack resolution', }, @@ -86,6 +90,9 @@ export function getRequiredConfiguration( const desiredCompilerOptions = getDesiredCompilerOptions(ts) for (const optionKey of Object.keys(desiredCompilerOptions)) { const ev = desiredCompilerOptions[optionKey] + if (optionKey === 'moduleResolution') { + console.log({ optionKey, ev, current: res[optionKey] }) + } if (!('value' in ev)) { continue } diff --git a/test/development/correct-tsconfig-defaults/index.test.ts b/test/development/correct-tsconfig-defaults/index.test.ts new file mode 100644 index 000000000000..c271bd9cbb89 --- /dev/null +++ b/test/development/correct-tsconfig-defaults/index.test.ts @@ -0,0 +1,41 @@ +import { createNext } from 'e2e-utils' +import fs from 'fs' +import { waitFor } from 'next-test-utils' +import path from 'path' +import { NextInstance } from 'test/lib/next-modes/base' + +describe('correct tsconfig.json defaults', () => { + let next: NextInstance + + beforeAll(async () => { + next = await createNext({ + files: { + 'pages/index.tsx': 'export default function Page() {}', + }, + skipStart: true, + dependencies: { + typescript: 'latest', + '@types/react': 'latest', + '@types/node': 'latest', + }, + }) + }) + afterAll(() => next.destroy()) + + it('should add `moduleResoution` when generating tsconfig.json in dev', async () => { + const tsconfigPath = path.join(next.testDir, 'tsconfig.json') + expect(fs.existsSync(tsconfigPath)).toBeFalse() + + await next.start() + await waitFor(1000) + await next.stop() + + expect(fs.existsSync(tsconfigPath)).toBeTrue() + + const tsconfig = JSON.parse(await next.readFile('tsconfig.json')) + + expect(tsconfig.compilerOptions).toEqual( + expect.objectContaining({ moduleResolution: 'node' }) + ) + }) +})