Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: allow setting custom tsconfig file #28104

Merged
merged 32 commits into from Sep 23, 2021
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
c336faf
feat: allow setting custom tsconfig file
casperiv0 Aug 13, 2021
dd6490c
fix: only warn once
casperiv0 Aug 13, 2021
451964e
Merge branch 'canary' of https://github.com/vercel/next.js into feat/…
casperiv0 Aug 14, 2021
736287c
docs: add docs for custom tsconfig file
casperiv0 Aug 14, 2021
06aebc9
Merge branch 'canary' into feat/custom-tsconfig
casperiv0 Aug 14, 2021
27eead4
Merge branch 'vercel:canary' into feat/custom-tsconfig
casperiv0 Aug 16, 2021
f5c152c
Merge branch 'canary' into feat/custom-tsconfig
casperiv0 Aug 17, 2021
67d6072
Merge branch 'vercel:canary' into feat/custom-tsconfig
casperiv0 Aug 17, 2021
2227f70
Merge branch 'vercel:canary' into feat/custom-tsconfig
casperiv0 Aug 18, 2021
aa267d0
Merge branch 'canary' into feat/custom-tsconfig
casperiv0 Aug 20, 2021
b46a7e4
Merge branch 'canary' into feat/custom-tsconfig
casperiv0 Aug 25, 2021
b677c0d
Merge branch 'canary' into feat/custom-tsconfig
casperiv0 Aug 25, 2021
318faff
Merge branch 'canary' into feat/custom-tsconfig
casperiv0 Sep 19, 2021
d649c03
Apply suggestions from code review
casperiv0 Sep 21, 2021
c986876
Merge branch 'canary' into feat/custom-tsconfig
casperiv0 Sep 21, 2021
04a0ffb
test: add test for custom tsconfig path
casperiv0 Sep 21, 2021
f85848a
feat: use next.config.js instead of .env
casperiv0 Sep 21, 2021
bab181f
Merge branch 'canary' into feat/custom-tsconfig
casperiv0 Sep 21, 2021
a3517ba
docs: update docs to use next.config.js
casperiv0 Sep 21, 2021
598192f
Merge branch 'feat/custom-tsconfig' of github.com:Dev-CasperTheGhost/…
casperiv0 Sep 21, 2021
1c6ae3a
apply suggestions from code review
casperiv0 Sep 21, 2021
4657c5a
remove console log
casperiv0 Sep 21, 2021
d023f04
Merge branch 'canary' into feat/custom-tsconfig
casperiv0 Sep 22, 2021
49da632
Merge branch 'canary' into feat/custom-tsconfig
casperiv0 Sep 22, 2021
6c789b6
pass config as param
casperiv0 Sep 22, 2021
d256ad7
Merge branch 'feat/custom-tsconfig' of github.com:Dev-CasperTheGhost/…
casperiv0 Sep 22, 2021
db196fb
fix optional typescript config
casperiv0 Sep 22, 2021
3502196
test: add more tests
casperiv0 Sep 22, 2021
47efadb
apply suggestions from code review
casperiv0 Sep 22, 2021
a5994e8
Merge branch 'canary' into feat/custom-tsconfig
styfle Sep 22, 2021
83a6efb
Merge branch 'canary' into feat/custom-tsconfig
casperiv0 Sep 23, 2021
5d2e30f
Merge branch 'canary' into feat/custom-tsconfig
styfle Sep 23, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/basic-features/typescript.md
Expand Up @@ -35,6 +35,8 @@ touch tsconfig.json

Next.js will automatically configure this file with default values. Providing your own `tsconfig.json` with custom [compiler options](https://www.typescriptlang.org/docs/handbook/compiler-options.html) is also supported.

You can also provide a relative path to a tsconfig.json file by setting `typescript.tsconfigPath` prop inside your `next.config.js` file.

> Next.js uses Babel to handle TypeScript, which has some [caveats](https://babeljs.io/docs/en/babel-plugin-transform-typescript#caveats), and some [compiler options are handled differently](https://babeljs.io/docs/en/babel-plugin-transform-typescript#typescript-compiler-options).

Then, run `next` (normally `npm run dev` or `yarn dev`) and Next.js will guide you through the installation of the required packages to finish the setup:
Expand Down
1 change: 1 addition & 0 deletions packages/next/build/index.ts
Expand Up @@ -197,6 +197,7 @@ export default async function build(
pagesDir,
!ignoreTypeScriptErrors,
!config.images.disableStaticImages,
casperiv0 marked this conversation as resolved.
Show resolved Hide resolved
config,
cacheDir
)
)
Expand Down
11 changes: 10 additions & 1 deletion packages/next/build/webpack-config.ts
Expand Up @@ -203,6 +203,8 @@ const NODE_ESM_RESOLVE_OPTIONS = {
fullySpecified: true,
}

let TSCONFIG_WARNED = false

export default async function getBaseWebpackConfig(
dir: string,
{
Expand Down Expand Up @@ -378,14 +380,21 @@ export default async function getBaseWebpackConfig(
try {
typeScriptPath = require.resolve('typescript', { paths: [dir] })
} catch (_) {}
const tsConfigPath = path.join(dir, 'tsconfig.json')
const { tsconfigPath } = config.typescript
const tsConfigName = tsconfigPath
const tsConfigPath = path.join(dir, tsConfigName!)
casperiv0 marked this conversation as resolved.
Show resolved Hide resolved
const useTypeScript = Boolean(
typeScriptPath && (await fileExists(tsConfigPath))
)

let jsConfig
// jsconfig is a subset of tsconfig
if (useTypeScript) {
if (tsConfigName !== 'tsconfig.json' && TSCONFIG_WARNED === false) {
TSCONFIG_WARNED = true
Log.info(`Using tsconfig file: ${tsConfigName}`)
}

const ts = (await import(typeScriptPath!)) as typeof import('typescript')
const tsConfig = await getTypeScriptConfiguration(ts, tsConfigPath, true)
jsConfig = { compilerOptions: tsConfig.options }
Expand Down
7 changes: 5 additions & 2 deletions packages/next/lib/typescript/getTypeScriptIntent.ts
@@ -1,15 +1,18 @@
import { promises as fs } from 'fs'
import path from 'path'
import { NextConfigComplete } from '../../server/config-shared'
import { fileExists } from '../file-exists'
import { recursiveReadDir } from '../recursive-readdir'

export type TypeScriptIntent = { firstTimeSetup: boolean }

export async function getTypeScriptIntent(
baseDir: string,
pagesDir: string
pagesDir: string,
config: NextConfigComplete
): Promise<TypeScriptIntent | false> {
const tsConfigPath = path.join(baseDir, 'tsconfig.json')
const tsConfigName = config.typescript.tsconfigPath
casperiv0 marked this conversation as resolved.
Show resolved Hide resolved
const tsConfigPath = path.join(baseDir, tsConfigName!)

// The integration turns on if we find a `tsconfig.json` in the user's
// project.
Expand Down
7 changes: 5 additions & 2 deletions packages/next/lib/verifyTypeScriptSetup.ts
Expand Up @@ -14,6 +14,7 @@ import { TypeCheckResult } from './typescript/runTypeCheck'
import { writeAppTypeDeclarations } from './typescript/writeAppTypeDeclarations'
import { writeConfigurationDefaults } from './typescript/writeConfigurationDefaults'
import { missingDepsError } from './typescript/missingDependencyError'
import { NextConfigComplete } from '../server/config-shared'

const requiredPackages = [
{ file: 'typescript', pkg: 'typescript' },
Expand All @@ -26,13 +27,15 @@ export async function verifyTypeScriptSetup(
pagesDir: string,
typeCheckPreflight: boolean,
imageImportsEnabled: boolean,
config: NextConfigComplete,
cacheDir?: string
): Promise<{ result?: TypeCheckResult; version: string | null }> {
const tsConfigPath = path.join(dir, 'tsconfig.json')
const tsConfigName = config.typescript.tsconfigPath
casperiv0 marked this conversation as resolved.
Show resolved Hide resolved
const tsConfigPath = path.join(dir, tsConfigName!)
casperiv0 marked this conversation as resolved.
Show resolved Hide resolved

try {
// Check if the project uses TypeScript:
const intent = await getTypeScriptIntent(dir, pagesDir)
const intent = await getTypeScriptIntent(dir, pagesDir, config)
if (!intent) {
return { version: null }
}
Expand Down
3 changes: 3 additions & 0 deletions packages/next/server/config-shared.ts
Expand Up @@ -34,6 +34,8 @@ export interface ESLintConfig {
export interface TypeScriptConfig {
/** Do not run TypeScript during production builds (`next build`). */
ignoreBuildErrors?: boolean
/** Relative path to a custom tsconfig file */
tsconfigPath?: string
}

export type NextConfig = { [key: string]: any } & {
Expand Down Expand Up @@ -153,6 +155,7 @@ export const defaultConfig: NextConfig = {
},
typescript: {
ignoreBuildErrors: false,
tsconfigPath: 'tsconfig.json',
},
distDir: '.next',
cleanDistDir: true,
Expand Down
3 changes: 2 additions & 1 deletion packages/next/server/dev/next-dev-server.ts
Expand Up @@ -290,7 +290,8 @@ export default class DevServer extends Server {
this.dir,
this.pagesDir!,
false,
!this.nextConfig.images.disableStaticImages
!this.nextConfig.images.disableStaticImages,
this.nextConfig
)

this.customRoutes = await loadCustomRoutes(this.nextConfig)
Expand Down
5 changes: 5 additions & 0 deletions test/integration/typescript-custom-tsconfig/next.config.js
@@ -0,0 +1,5 @@
module.exports = {
typescript: {
tsconfigPath: 'web.tsconfig.json',
},
}
3 changes: 3 additions & 0 deletions test/integration/typescript-custom-tsconfig/pages/index.tsx
@@ -0,0 +1,3 @@
export default function Index() {
return <p>Hello world</p>
}
18 changes: 18 additions & 0 deletions test/integration/typescript-custom-tsconfig/test/index.test.js
@@ -0,0 +1,18 @@
/* eslint-env jest */

import { join } from 'path'
import { nextBuild } from 'next-test-utils'

const appDir = join(__dirname, '..')

const warnMessage = /Using tsconfig file:/

describe('Custom TypeScript Config', () => {
it('should warn when using custom typescript path', async () => {
casperiv0 marked this conversation as resolved.
Show resolved Hide resolved
const { stdout } = await nextBuild(appDir, [], {
stdout: true,
})

expect(stdout).toMatch(warnMessage)
})
})
20 changes: 20 additions & 0 deletions test/integration/typescript-custom-tsconfig/web.tsconfig.json
@@ -0,0 +1,20 @@
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": false,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"incremental": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve"
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
"exclude": ["node_modules"]
}