diff --git a/packages/vite/package.json b/packages/vite/package.json index ad44427d28a67..f760edf98cf9c 100644 --- a/packages/vite/package.json +++ b/packages/vite/package.json @@ -35,7 +35,8 @@ "@swc/helpers": "~0.5.0", "enquirer": "~2.3.6", "@nx/js": "file:../js", - "tsconfig-paths": "^4.1.2" + "tsconfig-paths": "^4.1.2", + "minimatch": "9.0.3" }, "peerDependencies": { "vite": "^5.0.0", diff --git a/packages/vite/src/generators/convert-to-inferred/convert-to-inferred.spec.ts b/packages/vite/src/generators/convert-to-inferred/convert-to-inferred.spec.ts index 5f8845e41288e..6c42d4d1cb285 100644 --- a/packages/vite/src/generators/convert-to-inferred/convert-to-inferred.spec.ts +++ b/packages/vite/src/generators/convert-to-inferred/convert-to-inferred.spec.ts @@ -531,6 +531,20 @@ describe('Vite - Convert Executors To Plugin', () => { }, "plugin": "@nx/vite/plugin", }, + { + "include": [ + "existing/**/*", + ], + "options": { + "buildTargetName": "build", + "previewTargetName": "preview", + "serveStaticTargetName": "serve-static", + "serveTargetName": "serve", + "testTargetName": "test", + "typecheckTargetName": "typecheck", + }, + "plugin": "@nx/vite/plugin", + }, { "include": [ "myapp/**/*", @@ -542,6 +556,7 @@ describe('Vite - Convert Executors To Plugin', () => { "serveStaticTargetName": "serve-static", "serveTargetName": "serve", "testTargetName": "test", + "typecheckTargetName": "typecheck", }, "plugin": "@nx/vite/plugin", }, @@ -555,6 +570,7 @@ describe('Vite - Convert Executors To Plugin', () => { "serveStaticTargetName": "serve-static", "serveTargetName": "serve", "testTargetName": "test", + "typecheckTargetName": "typecheck", }, "plugin": "@nx/vite/plugin", }, diff --git a/packages/vite/src/plugins/__snapshots__/plugin-vitest.spec.ts.snap b/packages/vite/src/plugins/__snapshots__/plugin-vitest.spec.ts.snap index 5a4b9f8ebe6e6..5c65c5dbb0d49 100644 --- a/packages/vite/src/plugins/__snapshots__/plugin-vitest.spec.ts.snap +++ b/packages/vite/src/plugins/__snapshots__/plugin-vitest.spec.ts.snap @@ -47,6 +47,28 @@ exports[`@nx/vite/plugin root project should create nodes 1`] = ` "{projectRoot}/coverage", ], }, + "typecheck": { + "cache": true, + "command": "tsc --noEmit", + "inputs": [ + "production", + "^production", + ], + "metadata": { + "description": "Run Typechecking", + "help": { + "command": "npx tsc --help -p tsconfig.lib.json", + "example": { + "options": { + "noEmit": true, + }, + }, + }, + }, + "options": { + "cwd": ".", + }, + }, }, }, }, diff --git a/packages/vite/src/plugins/__snapshots__/plugin-with-test.spec.ts.snap b/packages/vite/src/plugins/__snapshots__/plugin-with-test.spec.ts.snap index a46944aba01a8..ad8da91a728b4 100644 --- a/packages/vite/src/plugins/__snapshots__/plugin-with-test.spec.ts.snap +++ b/packages/vite/src/plugins/__snapshots__/plugin-with-test.spec.ts.snap @@ -47,6 +47,28 @@ exports[`@nx/vite/plugin with test node root project should create nodes - with "{projectRoot}/coverage", ], }, + "typecheck": { + "cache": true, + "command": "tsc --noEmit", + "inputs": [ + "production", + "^production", + ], + "metadata": { + "description": "Run Typechecking", + "help": { + "command": "npx tsc --help -p tsconfig.lib.json", + "example": { + "options": { + "noEmit": true, + }, + }, + }, + }, + "options": { + "cwd": ".", + }, + }, }, }, }, diff --git a/packages/vite/src/plugins/plugin.ts b/packages/vite/src/plugins/plugin.ts index ae11ebe9ff6a7..03cc61d914a87 100644 --- a/packages/vite/src/plugins/plugin.ts +++ b/packages/vite/src/plugins/plugin.ts @@ -21,6 +21,7 @@ import { workspaceDataDirectory } from 'nx/src/utils/cache-directory'; import { getLockFileName } from '@nx/js'; import { loadViteDynamicImport } from '../utils/executor-utils'; import { hashObject } from 'nx/src/hasher/file-hasher'; +import { minimatch } from 'minimatch'; const pmc = getPackageManagerCommand(); @@ -30,6 +31,7 @@ export interface VitePluginOptions { serveTargetName?: string; previewTargetName?: string; serveStaticTargetName?: string; + typecheckTargetName?: string; } type ViteTargets = Pick; @@ -97,6 +99,9 @@ async function createNodesInternal( return {}; } + const tsConfigFiles = + siblingFiles.filter((p) => minimatch(p, 'tsconfig*{.json,.*.json}')) ?? []; + const normalizedOptions = normalizeOptions(options); // We do not want to alter how the hash is calculated, so appending the config file path to the hash @@ -113,6 +118,7 @@ async function createNodesInternal( configFilePath, projectRoot, normalizedOptions, + tsConfigFiles, context ); targetsCache[hash] ??= viteTargets; @@ -141,6 +147,7 @@ async function buildViteTargets( configFilePath: string, projectRoot: string, options: VitePluginOptions, + tsConfigFiles: string[], context: CreateNodesContext ): Promise { const absoluteConfigFilePath = joinPathFragments( @@ -198,6 +205,29 @@ async function buildViteTargets( } } + if (tsConfigFiles.length) { + const tsconfigToUse = tsConfigFiles.includes('tsconfig.lib.json') + ? 'tsconfig.lib.json' + : tsConfigFiles[0]; + targets[options.typecheckTargetName] = { + cache: true, + inputs: ['production', '^production'], + command: 'tsc --noEmit', + options: { cwd: joinPathFragments(projectRoot) }, + metadata: { + description: `Run Typechecking`, + help: { + command: `${pmc.exec} tsc --help -p ${tsconfigToUse}`, + example: { + options: { + noEmit: true, + }, + }, + }, + }, + }; + } + // if file is vitest.config or vite.config has definition for test, create target for test if (configFilePath.includes('vitest.config') || hasTest) { targets[options.testTargetName] = await testTarget( @@ -420,5 +450,6 @@ function normalizeOptions(options: VitePluginOptions): VitePluginOptions { options.previewTargetName ??= 'preview'; options.testTargetName ??= 'test'; options.serveStaticTargetName ??= 'serve-static'; + options.typecheckTargetName ??= 'typecheck'; return options; }