diff --git a/docs/content/1.getting-started/3.bridge.md b/docs/content/1.getting-started/3.bridge.md index eebb7c2820..b37fc5fe8a 100644 --- a/docs/content/1.getting-started/3.bridge.md +++ b/docs/content/1.getting-started/3.bridge.md @@ -65,6 +65,18 @@ export default defineNuxtConfig({ }) ``` +### Update `tsconfig.json` + +If you are using TypeScript, you can edit your `tsconfig.json` to benefit from autogenerated Nuxt types: + +**tsconfig.json** + +```diff +{ ++ "extends": "./.nuxt/tsconfig.json", + "compilerOptions": { +``` + ### Avoid CommonJS syntax Nuxt 3 natively supports TypeScript and ECMAScript Modules. diff --git a/examples/hello-world/tsconfig.json b/examples/hello-world/tsconfig.json new file mode 100644 index 0000000000..4b34df1571 --- /dev/null +++ b/examples/hello-world/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./.nuxt/tsconfig.json" +} diff --git a/examples/use-async-data/tsconfig.json b/examples/use-async-data/tsconfig.json new file mode 100644 index 0000000000..4b34df1571 --- /dev/null +++ b/examples/use-async-data/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./.nuxt/tsconfig.json" +} diff --git a/examples/use-fetch/tsconfig.json b/examples/use-fetch/tsconfig.json new file mode 100644 index 0000000000..4b34df1571 --- /dev/null +++ b/examples/use-fetch/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./.nuxt/tsconfig.json" +} diff --git a/examples/use-meta/tsconfig.json b/examples/use-meta/tsconfig.json new file mode 100644 index 0000000000..4b34df1571 --- /dev/null +++ b/examples/use-meta/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./.nuxt/tsconfig.json" +} diff --git a/examples/use-state/tsconfig.json b/examples/use-state/tsconfig.json new file mode 100644 index 0000000000..4b34df1571 --- /dev/null +++ b/examples/use-state/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./.nuxt/tsconfig.json" +} diff --git a/examples/with-components/tsconfig.json b/examples/with-components/tsconfig.json new file mode 100644 index 0000000000..4b34df1571 --- /dev/null +++ b/examples/with-components/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./.nuxt/tsconfig.json" +} diff --git a/examples/with-layouts/tsconfig.json b/examples/with-layouts/tsconfig.json new file mode 100644 index 0000000000..4b34df1571 --- /dev/null +++ b/examples/with-layouts/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./.nuxt/tsconfig.json" +} diff --git a/examples/with-pages/tsconfig.json b/examples/with-pages/tsconfig.json new file mode 100644 index 0000000000..4b34df1571 --- /dev/null +++ b/examples/with-pages/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./.nuxt/tsconfig.json" +} diff --git a/examples/with-wasm/tsconfig.json b/examples/with-wasm/tsconfig.json new file mode 100644 index 0000000000..4b34df1571 --- /dev/null +++ b/examples/with-wasm/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./.nuxt/tsconfig.json" +} diff --git a/packages/kit/package.json b/packages/kit/package.json index 0ee8d58a31..c314a20b7d 100644 --- a/packages/kit/package.json +++ b/packages/kit/package.json @@ -30,6 +30,7 @@ "lodash.template": "^4.5.0", "mlly": "^0.2.6", "pathe": "^0.2.0", + "pkg-types": "^0.1.3", "rc9": "^1.2.0", "scule": "^0.2.1", "semver": "^7.3.5", diff --git a/packages/kit/src/types/hooks.ts b/packages/kit/src/types/hooks.ts index 98621cf226..4efee1a169 100644 --- a/packages/kit/src/types/hooks.ts +++ b/packages/kit/src/types/hooks.ts @@ -1,6 +1,7 @@ import type { IncomingMessage, ServerResponse } from 'http' import type { HookCallback } from 'hookable' import type { Compiler, Configuration, Stats } from 'webpack' +import type { TSConfig } from 'pkg-types' import type { NuxtConfig, NuxtOptions } from '..' import type { ModuleContainer } from '../module/container' import type { NuxtTemplate, Nuxt, NuxtApp } from '../types/nuxt' @@ -61,7 +62,7 @@ export interface NuxtHooks extends Record { 'run:before': (options: { argv: string[], cmd: { name: string, usage: string, description: string, options: Record }, rootDir: string }) => HookResult // nuxi - 'prepare:types': (options: { references: TSReference[], declarations: string[] }) => HookResult + 'prepare:types': (options: { references: TSReference[], declarations: string[], tsConfig: TSConfig }) => HookResult // @nuxt/core 'ready': (nuxt: Nuxt) => HookResult diff --git a/packages/nuxi/package.json b/packages/nuxi/package.json index 8c902b4f3c..e8b486b9be 100644 --- a/packages/nuxi/package.json +++ b/packages/nuxi/package.json @@ -42,6 +42,7 @@ "mri": "^1.2.0", "p-debounce": "^4.0.0", "pathe": "^0.2.0", + "pkg-types": "^0.1.3", "scule": "^0.2.1", "superb": "^4.0.0", "unbuild": "latest" diff --git a/packages/nuxi/src/utils/prepare.ts b/packages/nuxi/src/utils/prepare.ts index 4eda3271e4..67e7b6a122 100644 --- a/packages/nuxi/src/utils/prepare.ts +++ b/packages/nuxi/src/utils/prepare.ts @@ -2,6 +2,7 @@ import { promises as fsp } from 'fs' import { relative, resolve } from 'pathe' import { cyan } from 'colorette' import { Nuxt, TSReference } from '@nuxt/kit' +import type { TSConfig } from 'pkg-types' import consola from 'consola' import { getModulePaths, getNearestPackage } from './cjs' @@ -9,6 +10,38 @@ export const writeTypes = async (nuxt: Nuxt) => { const modulePaths = getModulePaths(nuxt.options.modulesDir) const rootDir = nuxt.options.rootDir + const tsConfig: TSConfig = { + compilerOptions: { + target: 'ESNext', + module: 'ESNext', + moduleResolution: 'Node', + strict: true, + allowJs: true, + noEmit: true, + resolveJsonModule: true, + types: ['node'], + baseUrl: relative(nuxt.options.buildDir, nuxt.options.rootDir), + paths: {} + } + } + + const aliases = { + ...nuxt.options.alias, + '#build': nuxt.options.buildDir + } + + for (const alias in aliases) { + const relativePath = relative(nuxt.options.rootDir, aliases[alias]).replace(/(?<=\w)\.\w+$/g, '') /* remove extension */ || '.' + tsConfig.compilerOptions.paths[alias] = [relativePath] + + try { + const { isDirectory } = await fsp.stat(resolve(nuxt.options.rootDir, relativePath)) + if (isDirectory) { + tsConfig.compilerOptions.paths[`${alias}/*`] = [`${relativePath}/*`] + } + } catch { } + } + const references: TSReference[] = [ ...nuxt.options.buildModules, ...nuxt.options.modules, @@ -20,7 +53,7 @@ export const writeTypes = async (nuxt: Nuxt) => { const declarations: string[] = [] await nuxt.callHook('builder:generateApp') - await nuxt.callHook('prepare:types', { references, declarations }) + await nuxt.callHook('prepare:types', { references, declarations, tsConfig }) const declarationPath = resolve(`${rootDir}/nuxt.d.ts`) @@ -42,6 +75,10 @@ export const writeTypes = async (nuxt: Nuxt) => { await fsp.writeFile(declarationPath, declaration) consola.success('Generated', cyan(relative(process.cwd(), declarationPath))) + + const tsConfigPath = resolve(nuxt.options.buildDir, 'tsconfig.json') + await fsp.mkdir(nuxt.options.buildDir, { recursive: true }) + await fsp.writeFile(tsConfigPath, JSON.stringify(tsConfig, null, 2)) } function renderAttrs (obj: Record) { diff --git a/playground/tsconfig.json b/playground/tsconfig.json new file mode 100644 index 0000000000..4b34df1571 --- /dev/null +++ b/playground/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./.nuxt/tsconfig.json" +} diff --git a/yarn.lock b/yarn.lock index 8773efeb62..136871920f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2593,6 +2593,7 @@ __metadata: lodash.template: ^4.5.0 mlly: ^0.2.6 pathe: ^0.2.0 + pkg-types: ^0.1.3 rc9: ^1.2.0 scule: ^0.2.1 semver: ^7.3.5 @@ -13679,6 +13680,7 @@ fsevents@~2.3.2: mri: ^1.2.0 p-debounce: ^4.0.0 pathe: ^0.2.0 + pkg-types: ^0.1.3 scule: ^0.2.1 superb: ^4.0.0 unbuild: latest @@ -14568,6 +14570,13 @@ fsevents@~2.3.2: languageName: node linkType: hard +"pkg-types@npm:^0.1.3": + version: 0.1.3 + resolution: "pkg-types@npm:0.1.3" + checksum: 3d1d9c9c39e8ed5299dbd1e729bca16154ae59b2dfe3703a8f24b1fe58280662663f7531b48a431feeecf4b5a7785a42f37cfe1541ff612ec6394bc5a1f61060 + languageName: node + linkType: hard + "pkg-up@npm:^2.0.0": version: 2.0.0 resolution: "pkg-up@npm:2.0.0"