diff --git a/packages/next/lib/verifyTypeScriptSetup.ts b/packages/next/lib/verifyTypeScriptSetup.ts index c2c36b2d0934e..140c871240f23 100644 --- a/packages/next/lib/verifyTypeScriptSetup.ts +++ b/packages/next/lib/verifyTypeScriptSetup.ts @@ -4,8 +4,10 @@ import { hasNecessaryDependencies, NecessaryDependencies, } from './has-necessary-dependencies' +import semver from 'next/dist/compiled/semver' import { CompileError } from './compile-error' import { FatalError } from './fatal-error' +import * as log from '../build/output/log' import { getTypeScriptIntent } from './typescript/getTypeScriptIntent' import { TypeCheckResult } from './typescript/runTypeCheck' @@ -38,6 +40,12 @@ export async function verifyTypeScriptSetup( // Load TypeScript after we're sure it exists: const ts = (await import(deps.resolved)) as typeof import('typescript') + if (semver.lt(ts.version, '4.3.2')) { + log.warn( + `Minimum recommended TypeScript version is v4.3.2, older versions can potentially be incompatible with Next.js. Detected: ${ts.version}` + ) + } + // Reconfigure (or create) the user's `tsconfig.json` for them: await writeConfigurationDefaults(ts, tsConfigPath, firstTimeSetup) // Write out the necessary `next-env.d.ts` file to correctly register diff --git a/test/integration/typescript-version-warning/app/node_modules/typescript/index.js b/test/integration/typescript-version-warning/app/node_modules/typescript/index.js new file mode 100644 index 0000000000000..740559576178f --- /dev/null +++ b/test/integration/typescript-version-warning/app/node_modules/typescript/index.js @@ -0,0 +1,5 @@ +const mod = require('../../../../../../node_modules/typescript') + +mod.version = '3.8.3' + +module.exports = mod diff --git a/test/integration/typescript-version-warning/app/node_modules/typescript/package.json b/test/integration/typescript-version-warning/app/node_modules/typescript/package.json new file mode 100644 index 0000000000000..5331dd9817e33 --- /dev/null +++ b/test/integration/typescript-version-warning/app/node_modules/typescript/package.json @@ -0,0 +1,5 @@ +{ + "name": "typescript", + "version": "3.8.3", + "main": "./index.js" +} diff --git a/test/integration/typescript-version-warning/app/pages/index.tsx b/test/integration/typescript-version-warning/app/pages/index.tsx new file mode 100644 index 0000000000000..6e3b8ca6eb912 --- /dev/null +++ b/test/integration/typescript-version-warning/app/pages/index.tsx @@ -0,0 +1,3 @@ +export default function Page(props) { + return
hello world
+} diff --git a/test/integration/typescript-version-warning/app/tsconfig.json b/test/integration/typescript-version-warning/app/tsconfig.json new file mode 100644 index 0000000000000..93a83a407c40c --- /dev/null +++ b/test/integration/typescript-version-warning/app/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "target": "es5", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": false, + "forceConsistentCasingInFileNames": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve" + }, + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], + "exclude": ["node_modules"] +} diff --git a/test/integration/typescript-version-warning/test/index.test.js b/test/integration/typescript-version-warning/test/index.test.js new file mode 100644 index 0000000000000..e8dd4e63a538b --- /dev/null +++ b/test/integration/typescript-version-warning/test/index.test.js @@ -0,0 +1,76 @@ +/* eslint-env jest */ +import fs from 'fs-extra' +import { join } from 'path' +import { nextBuild, findPort, launchApp, killApp } from 'next-test-utils' + +jest.setTimeout(1000 * 60 * 2) + +const appDir = join(__dirname, '../app') + +describe('Minimum TypeScript Warning', () => { + it('should show warning during next build with old version', async () => { + const res = await nextBuild(appDir, [], { + stderr: true, + stdout: true, + }) + expect(res.stdout + res.stderr).toContain( + 'Minimum recommended TypeScript version is' + ) + }) + + it('should show warning during next dev with old version', async () => { + let output = '' + + const handleOutput = (msg) => { + output += msg + } + const app = await launchApp(appDir, await findPort(), { + onStdout: handleOutput, + onStderr: handleOutput, + }) + await killApp(app) + + expect(output).toContain('Minimum recommended TypeScript version is') + }) + + it('should not show warning during next build with new version', async () => { + await fs.rename( + join(appDir, 'node_modules/typescript'), + join(appDir, 'node_modules/typescript-back') + ) + const res = await nextBuild(appDir, [], { + stderr: true, + stdout: true, + }) + await fs.rename( + join(appDir, 'node_modules/typescript-back'), + join(appDir, 'node_modules/typescript') + ) + expect(res.stdout + res.stderr).toContain( + 'Minimum recommended TypeScript version is' + ) + }) + + it('should not show warning during next dev with new version', async () => { + let output = '' + + const handleOutput = (msg) => { + output += msg + } + await fs.rename( + join(appDir, 'node_modules/typescript'), + join(appDir, 'node_modules/typescript-back') + ) + const app = await launchApp(appDir, await findPort(), { + onStdout: handleOutput, + onStderr: handleOutput, + }) + await killApp(app) + await fs.rename( + join(appDir, 'node_modules/typescript-back'), + join(appDir, 'node_modules/typescript') + ) + + expect(output).toContain('Minimum recommended TypeScript version is') + }) +})