diff --git a/packages/js/src/generators/setup-build/generator.ts b/packages/js/src/generators/setup-build/generator.ts index aa7f4d73f7201f..9e9eda516a9baf 100644 --- a/packages/js/src/generators/setup-build/generator.ts +++ b/packages/js/src/generators/setup-build/generator.ts @@ -17,7 +17,7 @@ import { addBuildTargetDefaults } from '@nx/devkit/src/generators/target-default import { basename, dirname, join } from 'node:path/posix'; import { mergeTargetConfigurations } from 'nx/src/devkit-internals'; import type { PackageJson } from 'nx/src/utils/package-json'; -import { ensureProjectIsIncludedInPluginRegistrations } from '../..//utils/typescript/plugin'; +import { ensureProjectIsIncludedInPluginRegistrations } from '../../utils/typescript/plugin'; import { getImportPath } from '../../utils/get-import-path'; import { getUpdatedPackageJsonContent, diff --git a/packages/rollup/src/plugins/plugin.ts b/packages/rollup/src/plugins/plugin.ts index 0c4ec4d8c5c759..c6debbe0658af6 100644 --- a/packages/rollup/src/plugins/plugin.ts +++ b/packages/rollup/src/plugins/plugin.ts @@ -20,6 +20,7 @@ import { getLockFileName } from '@nx/js'; import { getNamedInputs } from '@nx/devkit/src/utils/get-named-inputs'; import { type RollupOptions } from 'rollup'; import { hashObject } from 'nx/src/hasher/file-hasher'; +import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; const pmc = getPackageManagerCommand(); @@ -59,7 +60,8 @@ export const createNodes: CreateNodes = [ configFilePath, normalizeOptions(options), context, - {} + {}, + isUsingTsSolutionSetup() ); }, ]; @@ -74,6 +76,7 @@ export const createNodesV2: CreateNodesV2 = [ `rollup-${optionsHash}.hash` ); const targetsCache = readTargetsCache(cachePath); + const isTsSolutionSetup = isUsingTsSolutionSetup(); try { return await createNodesFromFiles( @@ -82,7 +85,8 @@ export const createNodesV2: CreateNodesV2 = [ configFile, normalizedOptions, context, - targetsCache + targetsCache, + isTsSolutionSetup ), configFilePaths, normalizedOptions, @@ -98,7 +102,8 @@ async function createNodesInternal( configFilePath: string, options: Required, context: CreateNodesContext, - targetsCache: Record> + targetsCache: Record>, + isTsSolutionSetup: boolean ) { const projectRoot = dirname(configFilePath); const fullyQualifiedProjectRoot = join(context.workspaceRoot, projectRoot); @@ -123,7 +128,8 @@ async function createNodesInternal( configFilePath, projectRoot, options, - context + context, + isTsSolutionSetup ); return { @@ -140,7 +146,8 @@ async function buildRollupTarget( configFilePath: string, projectRoot: string, options: RollupPluginOptions, - context: CreateNodesContext + context: CreateNodesContext, + isTsSolutionSetup: boolean ): Promise> { let loadConfigFile: ( path: string, @@ -200,6 +207,13 @@ async function buildRollupTarget( }, }, }; + + if (isTsSolutionSetup) { + targets[options.buildTargetName].syncGenerators = [ + '@nx/js:typescript-sync', + ]; + } + return targets; } diff --git a/packages/rspack/src/plugins/plugin.ts b/packages/rspack/src/plugins/plugin.ts index 1e05fdaafeee2d..bb729b5b2f75ba 100644 --- a/packages/rspack/src/plugins/plugin.ts +++ b/packages/rspack/src/plugins/plugin.ts @@ -12,6 +12,7 @@ import { import { calculateHashForCreateNodes } from '@nx/devkit/src/utils/calculate-hash-for-create-nodes'; import { getNamedInputs } from '@nx/devkit/src/utils/get-named-inputs'; import { getLockFileName, getRootTsConfigPath } from '@nx/js'; +import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { existsSync, readdirSync } from 'fs'; import { hashObject } from 'nx/src/hasher/file-hasher'; import { workspaceDataDirectory } from 'nx/src/utils/cache-directory'; @@ -54,10 +55,17 @@ export const createNodesV2: CreateNodesV2 = [ `rspack-${optionsHash}.hash` ); const targetsCache = readTargetsCache(cachePath); + const isTsSolutionSetup = isUsingTsSolutionSetup(); try { return await createNodesFromFiles( (configFile, options, context) => - createNodesInternal(configFile, options, context, targetsCache), + createNodesInternal( + configFile, + options, + context, + targetsCache, + isTsSolutionSetup + ), configFilePaths, options, context @@ -72,7 +80,8 @@ async function createNodesInternal( configFilePath: string, options: RspackPluginOptions, context: CreateNodesContext, - targetsCache: Record + targetsCache: Record, + isTsSolutionSetup: boolean ) { const projectRoot = dirname(configFilePath); // Do not create a project if package.json and project.json isn't there. @@ -100,7 +109,8 @@ async function createNodesInternal( configFilePath, projectRoot, normalizedOptions, - context + context, + isTsSolutionSetup ); const { targets, metadata } = targetsCache[hash]; @@ -120,7 +130,8 @@ async function createRspackTargets( configFilePath: string, projectRoot: string, options: RspackPluginOptions, - context: CreateNodesContext + context: CreateNodesContext, + isTsSolutionSetup: boolean ): Promise { const namedInputs = getNamedInputs(projectRoot, context); @@ -187,6 +198,21 @@ async function createRspackTargets( }, }; + if (isTsSolutionSetup) { + targets[options.buildTargetName].syncGenerators = [ + '@nx/js:typescript-sync', + ]; + targets[options.serveTargetName].syncGenerators = [ + '@nx/js:typescript-sync', + ]; + targets[options.previewTargetName].syncGenerators = [ + '@nx/js:typescript-sync', + ]; + targets[options.serveStaticTargetName].syncGenerators = [ + '@nx/js:typescript-sync', + ]; + } + return { targets, metadata: {} }; } diff --git a/packages/vite/src/plugins/plugin.spec.ts b/packages/vite/src/plugins/plugin.spec.ts index 6eec64ff806a84..7c747813c3270f 100644 --- a/packages/vite/src/plugins/plugin.spec.ts +++ b/packages/vite/src/plugins/plugin.spec.ts @@ -12,13 +12,17 @@ jest.mock('../utils/executor-utils', () => ({ jest.mock('@nx/js/src/utils/typescript/ts-solution-setup', () => ({ ...jest.requireActual('@nx/js/src/utils/typescript/ts-solution-setup'), - isUsingTsSolutionSetup: jest.fn().mockReturnValue(false), + isUsingTsSolutionSetup: jest.fn(), })); describe('@nx/vite/plugin', () => { let createNodesFunction = createNodesV2[1]; let context: CreateNodesContext; + beforeEach(() => { + (isUsingTsSolutionSetup as jest.Mock).mockReturnValue(false); + }); + describe('root project', () => { let tempFs: TempFs; beforeEach(async () => { @@ -42,12 +46,11 @@ describe('@nx/vite/plugin', () => { }; tempFs.createFileSync('vite.config.ts', ''); tempFs.createFileSync('index.html', ''); - tempFs.createFileSync('package.json', ''); + tempFs.createFileSync('package.json', '{}'); }); afterEach(() => { jest.resetModules(); - tempFs.cleanup(); }); it('should create nodes', async () => { @@ -95,7 +98,7 @@ describe('@nx/vite/plugin', () => { }); it('should infer typecheck with --build flag when using TS solution setup', async () => { - (isUsingTsSolutionSetup as jest.Mock).mockResolvedValue(true); + (isUsingTsSolutionSetup as jest.Mock).mockReturnValue(true); tempFs.createFileSync('tsconfig.json', ''); const nodes = await createNodesFunction( @@ -114,6 +117,30 @@ describe('@nx/vite/plugin', () => { `tsc --build --emitDeclarationOnly --pretty --verbose` ); }); + + it('should infer the sync generator when using TS solution setup', async () => { + (isUsingTsSolutionSetup as jest.Mock).mockReturnValue(true); + tempFs.createFileSync('tsconfig.json', ''); + + const nodes = await createNodesFunction( + ['vite.config.ts'], + { + buildTargetName: 'build', + serveTargetName: 'serve', + previewTargetName: 'preview', + testTargetName: 'test', + serveStaticTargetName: 'serve-static', + }, + context + ); + + expect(nodes[0][1].projects['.'].targets.build.syncGenerators).toEqual([ + '@nx/js:typescript-sync', + ]); + expect( + nodes[0][1].projects['.'].targets.typecheck.syncGenerators + ).toEqual(['@nx/js:typescript-sync']); + }); }); describe('not root project', () => { diff --git a/packages/vite/src/plugins/plugin.ts b/packages/vite/src/plugins/plugin.ts index 79eb7fed6ee9e1..ccb8e8ad6c9dbf 100644 --- a/packages/vite/src/plugins/plugin.ts +++ b/packages/vite/src/plugins/plugin.ts @@ -38,7 +38,9 @@ export interface VitePluginOptions { type ViteTargets = Pick; function readTargetsCache(cachePath: string): Record { - return existsSync(cachePath) ? readJsonFile(cachePath) : {}; + return process.env.NX_CACHE_PROJECT_GRAPH !== 'false' && existsSync(cachePath) + ? readJsonFile(cachePath) + : {}; } function writeTargetsToCache(cachePath, results?: Record) { @@ -208,17 +210,24 @@ async function buildViteTargets( options.buildTargetName, namedInputs, buildOutputs, - projectRoot + projectRoot, + isUsingTsSolutionSetup ); // If running in library mode, then there is nothing to serve. if (!viteBuildConfig.build?.lib || hasServeConfig) { - targets[options.serveTargetName] = serveTarget(projectRoot); + targets[options.serveTargetName] = serveTarget( + projectRoot, + isUsingTsSolutionSetup + ); targets[options.previewTargetName] = previewTarget( projectRoot, options.buildTargetName ); - targets[options.serveStaticTargetName] = serveStaticTarget(options) as {}; + targets[options.serveStaticTargetName] = serveStaticTarget( + options, + isUsingTsSolutionSetup + ); } } @@ -251,6 +260,12 @@ async function buildViteTargets( }, }, }; + + if (isUsingTsSolutionSetup) { + targets[options.typecheckTargetName].syncGenerators = [ + '@nx/js:typescript-sync', + ]; + } } // if file is vitest.config or vite.config has definition for test, create target for test @@ -272,9 +287,10 @@ async function buildTarget( [inputName: string]: any[]; }, outputs: string[], - projectRoot: string + projectRoot: string, + isUsingTsSolutionSetup: boolean ) { - return { + const buildTarget: TargetConfiguration = { command: `vite build`, options: { cwd: joinPathFragments(projectRoot) }, cache: true, @@ -302,9 +318,15 @@ async function buildTarget( }, }, }; + + if (isUsingTsSolutionSetup) { + buildTarget.syncGenerators = ['@nx/js:typescript-sync']; + } + + return buildTarget; } -function serveTarget(projectRoot: string) { +function serveTarget(projectRoot: string, isUsingTsSolutionSetup: boolean) { const targetConfig: TargetConfiguration = { command: `vite serve`, options: { @@ -324,6 +346,10 @@ function serveTarget(projectRoot: string) { }, }; + if (isUsingTsSolutionSetup) { + targetConfig.syncGenerators = ['@nx/js:typescript-sync']; + } + return targetConfig; } @@ -388,7 +414,10 @@ async function testTarget( }; } -function serveStaticTarget(options: VitePluginOptions) { +function serveStaticTarget( + options: VitePluginOptions, + isUsingTsSolutionSetup: boolean +) { const targetConfig: TargetConfiguration = { executor: '@nx/web:file-server', options: { @@ -397,6 +426,10 @@ function serveStaticTarget(options: VitePluginOptions) { }, }; + if (isUsingTsSolutionSetup) { + targetConfig.syncGenerators = ['@nx/js:typescript-sync']; + } + return targetConfig; } diff --git a/packages/webpack/src/plugins/plugin.ts b/packages/webpack/src/plugins/plugin.ts index 6db7bac14f2d2e..fe42b91575391a 100644 --- a/packages/webpack/src/plugins/plugin.ts +++ b/packages/webpack/src/plugins/plugin.ts @@ -17,6 +17,7 @@ import { import { calculateHashForCreateNodes } from '@nx/devkit/src/utils/calculate-hash-for-create-nodes'; import { getNamedInputs } from '@nx/devkit/src/utils/get-named-inputs'; import { getLockFileName, getRootTsConfigPath } from '@nx/js'; +import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { existsSync, readdirSync } from 'fs'; import { hashObject } from 'nx/src/hasher/file-hasher'; import { workspaceDataDirectory } from 'nx/src/utils/cache-directory'; @@ -65,10 +66,17 @@ export const createNodesV2: CreateNodesV2 = [ ); const targetsCache = readTargetsCache(cachePath); const normalizedOptions = normalizeOptions(options); + const isTsSolutionSetup = isUsingTsSolutionSetup(); try { return await createNodesFromFiles( (configFile, options, context) => - createNodesInternal(configFile, options, context, targetsCache), + createNodesInternal( + configFile, + options, + context, + targetsCache, + isTsSolutionSetup + ), configFilePaths, normalizedOptions, context @@ -86,7 +94,13 @@ export const createNodes: CreateNodes = [ '`createNodes` is deprecated. Update your plugin to utilize createNodesV2 instead. In Nx 20, this will change to the createNodesV2 API.' ); const normalizedOptions = normalizeOptions(options); - return createNodesInternal(configFilePath, normalizedOptions, context, {}); + return createNodesInternal( + configFilePath, + normalizedOptions, + context, + {}, + isUsingTsSolutionSetup() + ); }, ]; @@ -94,7 +108,8 @@ async function createNodesInternal( configFilePath: string, options: Required, context: CreateNodesContext, - targetsCache: Record + targetsCache: Record, + isTsSolutionSetup: boolean ): Promise { const projectRoot = dirname(configFilePath); @@ -118,7 +133,8 @@ async function createNodesInternal( configFilePath, projectRoot, options, - context + context, + isTsSolutionSetup ); const { targets, metadata } = targetsCache[hash]; @@ -138,7 +154,8 @@ async function createWebpackTargets( configFilePath: string, projectRoot: string, options: Required, - context: CreateNodesContext + context: CreateNodesContext, + isTsSolutionSetup: boolean ): Promise { const namedInputs = getNamedInputs(projectRoot, context); @@ -243,6 +260,21 @@ async function createWebpackTargets( }, }; + if (isTsSolutionSetup) { + targets[options.buildTargetName].syncGenerators = [ + '@nx/js:typescript-sync', + ]; + targets[options.serveTargetName].syncGenerators = [ + '@nx/js:typescript-sync', + ]; + targets[options.previewTargetName].syncGenerators = [ + '@nx/js:typescript-sync', + ]; + targets[options.serveStaticTargetName].syncGenerators = [ + '@nx/js:typescript-sync', + ]; + } + return { targets, metadata: {} }; }