diff --git a/packages/detox/src/generators/init/init.ts b/packages/detox/src/generators/init/init.ts index 543ea76ed86f9..2e4c51d5eb70e 100644 --- a/packages/detox/src/generators/init/init.ts +++ b/packages/detox/src/generators/init/init.ts @@ -42,6 +42,16 @@ export async function detoxInitGeneratorInternal(host: Tree, schema: Schema) { buildTargetName: ['build', 'detox:build', 'detox-build'], startTargetName: ['start', 'detox:start', 'detox-start'], testTargetName: ['test', 'detox:test', 'detox-test'], + buildDepsTargetName: [ + 'build-deps', + 'detox:build-deps', + 'detox-build-deps', + ], + watchDepsTargetName: [ + 'watch-deps', + 'detox:watch-deps', + 'detox-watch-deps', + ], }, schema.updatePackageScripts ); diff --git a/packages/detox/src/plugins/plugin.ts b/packages/detox/src/plugins/plugin.ts index d511c8dfe88a4..e90bc6b78367c 100644 --- a/packages/detox/src/plugins/plugin.ts +++ b/packages/detox/src/plugins/plugin.ts @@ -5,6 +5,7 @@ import { CreateNodesResult, CreateNodesV2, detectPackageManager, + getPackageManagerCommand, NxJsonConfiguration, readJsonFile, TargetConfiguration, @@ -17,13 +18,18 @@ import { existsSync } from 'fs'; import { calculateHashForCreateNodes } from '@nx/devkit/src/utils/calculate-hash-for-create-nodes'; import { workspaceDataDirectory } from 'nx/src/utils/cache-directory'; import { hashObject } from 'nx/src/devkit-internals'; +import { addBuildAndWatchDepsTargets } from '@nx/js/src/plugins/typescript/util'; export interface DetoxPluginOptions { buildTargetName?: string; startTargetName?: string; testTargetName?: string; + buildDepsTargetName?: string; + watchDepsTargetName?: string; } +const pmc = getPackageManagerCommand(); + function readTargetsCache( cachePath: string ): Record>> { @@ -141,6 +147,14 @@ function buildDetoxTargets( }, }; + addBuildAndWatchDepsTargets( + context.workspaceRoot, + projectRoot, + targets, + options, + pmc + ); + return targets; } diff --git a/packages/expo/plugins/plugin.ts b/packages/expo/plugins/plugin.ts index 5cdc5342f1e3e..d3356cab05fe8 100644 --- a/packages/expo/plugins/plugin.ts +++ b/packages/expo/plugins/plugin.ts @@ -5,6 +5,7 @@ import { CreateNodesResult, CreateNodesV2, detectPackageManager, + getPackageManagerCommand, logger, NxJsonConfiguration, readJsonFile, @@ -19,6 +20,7 @@ import { calculateHashForCreateNodes } from '@nx/devkit/src/utils/calculate-hash import { workspaceDataDirectory } from 'nx/src/utils/cache-directory'; import { hashObject } from 'nx/src/devkit-internals'; import { loadConfigFile } from '@nx/devkit/src/utils/config-utils'; +import { addBuildAndWatchDepsTargets } from '@nx/js/src/plugins/typescript/util'; export interface ExpoPluginOptions { startTargetName?: string; @@ -30,7 +32,10 @@ export interface ExpoPluginOptions { installTargetName?: string; buildTargetName?: string; submitTargetName?: string; + buildDepsTargetName?: string; + watchDepsTargetName?: string; } +const pmc = getPackageManagerCommand(); function readTargetsCache( cachePath: string @@ -186,6 +191,14 @@ function buildExpoTargets( }, }; + addBuildAndWatchDepsTargets( + context.workspaceRoot, + projectRoot, + targets, + options, + pmc + ); + return targets; } diff --git a/packages/expo/src/generators/init/init.ts b/packages/expo/src/generators/init/init.ts index 5e35458920d11..8cabbcab2b0af 100644 --- a/packages/expo/src/generators/init/init.ts +++ b/packages/expo/src/generators/init/init.ts @@ -55,6 +55,16 @@ export async function expoInitGeneratorInternal(host: Tree, schema: Schema) { 'expo:run-android', 'expo-run-android', ], + buildDepsTargetName: [ + 'build-deps', + 'expo:build-deps', + 'expo-build-deps', + ], + watchDepsTargetName: [ + 'watch-deps', + 'expo:watch-deps', + 'expo-watch-deps', + ], }, schema.updatePackageScripts diff --git a/packages/js/src/generators/init/init.ts b/packages/js/src/generators/init/init.ts index a2dd121cafc9e..465be8e88a64a 100644 --- a/packages/js/src/generators/init/init.ts +++ b/packages/js/src/generators/init/init.ts @@ -105,9 +105,24 @@ export async function initGeneratorInternal( { targetName: 'tsc-typecheck' }, ], build: [ - { targetName: 'build', configName: 'tsconfig.lib.json' }, - { targetName: 'tsc:build', configName: 'tsconfig.lib.json' }, - { targetName: 'tsc-build', configName: 'tsconfig.lib.json' }, + { + targetName: 'build', + configName: 'tsconfig.lib.json', + buildDepsName: 'build-deps', + watchDepsName: 'watch-deps', + }, + { + targetName: 'tsc:build', + configName: 'tsconfig.lib.json', + buildDepsName: 'tsc:build-deps', + watchDepsName: 'tsc:watch-deps', + }, + { + targetName: 'tsc-build', + configName: 'tsconfig.lib.json', + buildDepsName: 'tsc-build-deps', + watchDepsName: 'tsc-watch-deps', + }, ], }, schema.updatePackageScripts diff --git a/packages/js/src/plugins/typescript/plugin.spec.ts b/packages/js/src/plugins/typescript/plugin.spec.ts index 56e578f4ecf93..21ae2950ddbd1 100644 --- a/packages/js/src/plugins/typescript/plugin.spec.ts +++ b/packages/js/src/plugins/typescript/plugin.spec.ts @@ -1920,6 +1920,7 @@ describe(`Plugin: ${PLUGIN_NAME}`, () => { 'libs/my-lib/tsconfig.lib.json': `{"compilerOptions": {"outDir": "dist"}}`, 'libs/my-lib/tsconfig.build.json': `{}`, 'libs/my-lib/package.json': JSON.stringify({ + name: 'my-lib', main: 'dist/index.js', types: 'dist/index.d.ts', exports: { @@ -1983,6 +1984,17 @@ describe(`Plugin: ${PLUGIN_NAME}`, () => { "@nx/js:typescript-sync", ], }, + "build-deps": { + "dependsOn": [ + "^build", + ], + }, + "watch-deps": { + "command": "npx nx watch --projects my-lib --includeDependentProjects -- npx nx build-deps my-lib", + "dependsOn": [ + "build-deps", + ], + }, }, }, }, diff --git a/packages/js/src/plugins/typescript/plugin.ts b/packages/js/src/plugins/typescript/plugin.ts index ec1f8b8c27270..28b356a058e3b 100644 --- a/packages/js/src/plugins/typescript/plugin.ts +++ b/packages/js/src/plugins/typescript/plugin.ts @@ -35,6 +35,7 @@ import { getLockFileName } from 'nx/src/plugins/js/lock-file/lock-file'; import { workspaceDataDirectory } from 'nx/src/utils/cache-directory'; import type { ParsedCommandLine } from 'typescript'; import { readTsConfig } from '../../utils/typescript/ts-config'; +import { addBuildAndWatchDepsTargets } from './util'; export interface TscPluginOptions { typecheck?: @@ -47,6 +48,8 @@ export interface TscPluginOptions { | { targetName?: string; configName?: string; + buildDepsName?: string; + watchDepsName?: string; }; } @@ -61,6 +64,8 @@ interface NormalizedPluginOptions { | { targetName: string; configName: string; + buildDepsName?: string; + watchDepsName?: string; }; } @@ -373,6 +378,17 @@ function buildTscTargets( }, }, }; + + addBuildAndWatchDepsTargets( + context.workspaceRoot, + projectRoot, + targets, + { + buildDepsTargetName: options.build.buildDepsName, + watchDepsTargetName: options.build.watchDepsName, + }, + pmc + ); } return { targets }; @@ -975,6 +991,8 @@ function normalizePluginOptions( let build: NormalizedPluginOptions['build'] = { targetName: defaultBuildTargetName, configName: defaultBuildConfigName, + buildDepsName: 'build-deps', + watchDepsName: 'watch-deps', }; // Build target is not enabled by default if (!pluginOptions.build) { @@ -983,6 +1001,8 @@ function normalizePluginOptions( build = { targetName: pluginOptions.build.targetName ?? defaultBuildTargetName, configName: pluginOptions.build.configName ?? defaultBuildConfigName, + buildDepsName: pluginOptions.build.buildDepsName ?? 'build-deps', + watchDepsName: pluginOptions.build.watchDepsName ?? 'watch-deps', }; } diff --git a/packages/js/src/plugins/typescript/util.ts b/packages/js/src/plugins/typescript/util.ts new file mode 100644 index 0000000000000..6cd334dce8938 --- /dev/null +++ b/packages/js/src/plugins/typescript/util.ts @@ -0,0 +1,41 @@ +import { readJsonFile, type TargetConfiguration } from '@nx/devkit'; +import { existsSync } from 'node:fs'; +import { type PackageManagerCommands } from 'nx/src/utils/package-manager'; +import { join } from 'path'; + +/** + * Allow uses that use incremental builds to run `nx watch-deps` to continuously build all dependencies. + */ +export function addBuildAndWatchDepsTargets( + workspaceRoot: string, + projectRoot: string, + targets: Record, + options: { buildDepsTargetName?: string; watchDepsTargetName?: string }, + pmc: PackageManagerCommands +): void { + let projectName: string; + + const projectJsonPath = join(workspaceRoot, projectRoot, 'project.json'); + const packageJsonPath = join(workspaceRoot, projectRoot, 'package.json'); + + if (existsSync(projectJsonPath)) { + const projectJson = readJsonFile(projectJsonPath); + projectName = projectJson.name; + } else if (existsSync(packageJsonPath)) { + const packageJson = readJsonFile(packageJsonPath); + projectName = packageJson.nx?.name ?? packageJson.name; + } + + if (!projectName) return; + + if (projectName) { + const buildDepsTargetName = options.buildDepsTargetName ?? 'build-deps'; + targets[buildDepsTargetName] = { + dependsOn: ['^build'], + }; + targets[options.watchDepsTargetName ?? 'watch-deps'] = { + dependsOn: [buildDepsTargetName], + command: `${pmc.exec} nx watch --projects ${projectName} --includeDependentProjects -- ${pmc.exec} nx ${buildDepsTargetName} ${projectName}`, + }; + } +} diff --git a/packages/next/src/generators/init/init.ts b/packages/next/src/generators/init/init.ts index 5d0c5e1faa865..8401b29e4d959 100644 --- a/packages/next/src/generators/init/init.ts +++ b/packages/next/src/generators/init/init.ts @@ -67,6 +67,16 @@ export async function nextInitGeneratorInternal( 'next:serve-static', 'next-serve-static', ], + buildDepsTargetName: [ + 'build-deps', + 'next:build-deps', + 'next-build-deps', + ], + watchDepsTargetName: [ + 'watch-deps', + 'next:watch-deps', + 'next-watch-deps', + ], }, schema.updatePackageScripts ); diff --git a/packages/next/src/plugins/__snapshots__/plugin.spec.ts.snap b/packages/next/src/plugins/__snapshots__/plugin.spec.ts.snap index 6224c2bbdf1c1..9fa42c5386ef0 100644 --- a/packages/next/src/plugins/__snapshots__/plugin.spec.ts.snap +++ b/packages/next/src/plugins/__snapshots__/plugin.spec.ts.snap @@ -9,6 +9,11 @@ exports[`@nx/next/plugin integrated projects should create nodes 1`] = ` "my-app": { "root": "my-app", "targets": { + "build-deps": { + "dependsOn": [ + "^build", + ], + }, "my-build": { "cache": true, "command": "next build", @@ -57,6 +62,12 @@ exports[`@nx/next/plugin integrated projects should create nodes 1`] = ` "cwd": "my-app", }, }, + "watch-deps": { + "command": "npx nx watch --projects my-app --includeDependentProjects -- npx nx build-deps my-app", + "dependsOn": [ + "build-deps", + ], + }, }, }, }, @@ -98,6 +109,11 @@ exports[`@nx/next/plugin root projects should create nodes 1`] = ` "{projectRoot}/.next/!(cache)", ], }, + "build-deps": { + "dependsOn": [ + "^build", + ], + }, "dev": { "command": "next dev", "options": { @@ -122,6 +138,12 @@ exports[`@nx/next/plugin root projects should create nodes 1`] = ` "cwd": ".", }, }, + "watch-deps": { + "command": "npx nx watch --projects next --includeDependentProjects -- npx nx build-deps next", + "dependsOn": [ + "build-deps", + ], + }, }, }, }, diff --git a/packages/next/src/plugins/plugin.ts b/packages/next/src/plugins/plugin.ts index 2621e37a6fbdf..1f4111909de9c 100644 --- a/packages/next/src/plugins/plugin.ts +++ b/packages/next/src/plugins/plugin.ts @@ -10,6 +10,7 @@ import { writeJsonFile, createNodesFromFiles, logger, + getPackageManagerCommand, } from '@nx/devkit'; import { dirname, join } from 'path'; @@ -21,14 +22,19 @@ import { calculateHashForCreateNodes } from '@nx/devkit/src/utils/calculate-hash import { getLockFileName } from '@nx/js'; import { loadConfigFile } from '@nx/devkit/src/utils/config-utils'; import { hashObject } from 'nx/src/devkit-internals'; +import { addBuildAndWatchDepsTargets } from '@nx/js/src/plugins/typescript/util'; export interface NextPluginOptions { buildTargetName?: string; devTargetName?: string; startTargetName?: string; serveStaticTargetName?: string; + buildDepsTargetName?: string; + watchDepsTargetName?: string; } +const pmc = getPackageManagerCommand(); + const nextConfigBlob = '**/next.config.{ts,js,cjs,mjs}'; function readTargetsCache( @@ -170,6 +176,14 @@ async function buildNextTargets( targets[options.serveStaticTargetName] = getStaticServeTargetConfig(options); + addBuildAndWatchDepsTargets( + context.workspaceRoot, + projectRoot, + targets, + options, + pmc + ); + return targets; } diff --git a/packages/nuxt/src/generators/init/init.ts b/packages/nuxt/src/generators/init/init.ts index 1bc971e19b904..0efba3c4c82aa 100644 --- a/packages/nuxt/src/generators/init/init.ts +++ b/packages/nuxt/src/generators/init/init.ts @@ -14,6 +14,8 @@ export async function nuxtInitGenerator(host: Tree, schema: InitSchema) { { buildTargetName: ['build', 'nuxt:build', 'nuxt-build'], serveTargetName: ['serve', 'nuxt:serve', 'nuxt-serve'], + buildDepsTargetName: ['build-deps', 'nuxt:build-deps', 'nuxt-build-deps'], + watchDepsTargetName: ['watch-deps', 'nuxt:watch-deps', 'nuxt-watch-deps'], }, schema.updatePackageScripts ); diff --git a/packages/nuxt/src/plugins/__snapshots__/plugin.spec.ts.snap b/packages/nuxt/src/plugins/__snapshots__/plugin.spec.ts.snap index e2f94bedd3d08..cfd490f872de6 100644 --- a/packages/nuxt/src/plugins/__snapshots__/plugin.spec.ts.snap +++ b/packages/nuxt/src/plugins/__snapshots__/plugin.spec.ts.snap @@ -38,6 +38,11 @@ exports[`@nx/nuxt/plugin not root project should create nodes 1`] = ` "staticFilePath": "{projectRoot}/dist", }, }, + "build-deps": { + "dependsOn": [ + "^build", + ], + }, "build-something": { "cache": true, "command": "nuxt build", @@ -67,6 +72,12 @@ exports[`@nx/nuxt/plugin not root project should create nodes 1`] = ` "cwd": "my-app", }, }, + "watch-deps": { + "command": "npx nx watch --projects my-app --includeDependentProjects -- npx nx build-deps my-app", + "dependsOn": [ + "build-deps", + ], + }, }, }, }, @@ -102,6 +113,11 @@ exports[`@nx/nuxt/plugin root project should create nodes 1`] = ` "{projectRoot}/.output", ], }, + "build-deps": { + "dependsOn": [ + "^build", + ], + }, "build-static": { "cache": true, "command": "nuxt build --prerender", @@ -140,6 +156,12 @@ exports[`@nx/nuxt/plugin root project should create nodes 1`] = ` "staticFilePath": "{projectRoot}/dist", }, }, + "watch-deps": { + "command": "npx nx watch --projects nuxt --includeDependentProjects -- npx nx build-deps nuxt", + "dependsOn": [ + "build-deps", + ], + }, }, }, }, diff --git a/packages/nuxt/src/plugins/plugin.ts b/packages/nuxt/src/plugins/plugin.ts index 503835bac7b8a..6e0012a0c938f 100644 --- a/packages/nuxt/src/plugins/plugin.ts +++ b/packages/nuxt/src/plugins/plugin.ts @@ -4,6 +4,7 @@ import { CreateNodes, CreateNodesContext, detectPackageManager, + getPackageManagerCommand, readJsonFile, TargetConfiguration, workspaceRoot, @@ -17,10 +18,13 @@ import { getLockFileName } from '@nx/js'; import { dirname, isAbsolute, join, relative } from 'path'; import { existsSync, readdirSync } from 'fs'; import { loadNuxtKitDynamicImport } from '../utils/executor-utils'; +import { addBuildAndWatchDepsTargets } from '@nx/js/src/plugins/typescript/util'; const cachePath = join(workspaceDataDirectory, 'nuxt.hash'); const targetsCache = readTargetsCache(); +const pmc = getPackageManagerCommand(); + function readTargetsCache(): Record< string, Record @@ -46,6 +50,8 @@ export interface NuxtPluginOptions { serveTargetName?: string; serveStaticTargetName?: string; buildStaticTargetName?: string; + buildDepsTargetName?: string; + watchDepsTargetName?: string; } export const createNodes: CreateNodes = [ @@ -121,6 +127,14 @@ async function buildNuxtTargets( projectRoot ); + addBuildAndWatchDepsTargets( + context.workspaceRoot, + projectRoot, + targets, + options, + pmc + ); + return targets; } diff --git a/packages/remix/src/generators/init/init.spec.ts b/packages/remix/src/generators/init/init.spec.ts index e846bdc6be251..04382c00cf6da 100644 --- a/packages/remix/src/generators/init/init.spec.ts +++ b/packages/remix/src/generators/init/init.spec.ts @@ -37,11 +37,13 @@ describe('Remix Init Generator', () => { "plugins": [ { "options": { + "buildDepsTargetName": "build-deps", "buildTargetName": "build", "devTargetName": "dev", "serveStaticTargetName": "serve-static", "startTargetName": "start", "typecheckTargetName": "typecheck", + "watchDepsTargetName": "watch-deps", }, "plugin": "@nx/remix/plugin", }, diff --git a/packages/remix/src/generators/init/init.ts b/packages/remix/src/generators/init/init.ts index c8695771c5741..f7bfde983e16a 100644 --- a/packages/remix/src/generators/init/init.ts +++ b/packages/remix/src/generators/init/init.ts @@ -57,8 +57,18 @@ export async function remixInitGeneratorInternal(tree: Tree, options: Schema) { ], serveStaticTargetName: [ 'serve-static', - 'vite:serve-static', - 'vite-serve-static', + 'remix:serve-static', + 'remix-serve-static', + ], + buildDepsTargetName: [ + 'build-deps', + 'remix:build-deps', + 'remix-build-deps', + ], + watchDepsTargetName: [ + 'watch-deps', + 'remix:watch-deps', + 'remix-watch-deps', ], }, options.updatePackageScripts diff --git a/packages/remix/src/plugins/__snapshots__/plugin.spec.ts.snap b/packages/remix/src/plugins/__snapshots__/plugin.spec.ts.snap index 8d57192912e3b..0caea03367d4f 100644 --- a/packages/remix/src/plugins/__snapshots__/plugin.spec.ts.snap +++ b/packages/remix/src/plugins/__snapshots__/plugin.spec.ts.snap @@ -33,6 +33,112 @@ exports[`@nx/remix/plugin Remix Classic Compiler non-root project should create "{workspaceRoot}/my-app/public/build", ], }, + "build-deps": { + "dependsOn": [ + "^build", + ], + }, + "dev": { + "command": "remix dev --manual", + "options": { + "cwd": "my-app", + }, + }, + "serve-static": { + "command": "remix-serve build/index.js", + "dependsOn": [ + "build", + ], + "options": { + "cwd": "my-app", + }, + }, + "start": { + "command": "remix-serve build/index.js", + "dependsOn": [ + "build", + ], + "options": { + "cwd": "my-app", + }, + }, + "static-serve": { + "command": "remix-serve build/index.js", + "dependsOn": [ + "build", + ], + "options": { + "cwd": "my-app", + }, + }, + "tsc": { + "cache": true, + "command": "tsc", + "inputs": [ + "production", + "^production", + { + "externalDependencies": [ + "typescript", + ], + }, + ], + "options": { + "cwd": "my-app", + }, + }, + "watch-deps": { + "command": "npx nx watch --projects my-app --includeDependentProjects -- npx nx build-deps my-app", + "dependsOn": [ + "build-deps", + ], + }, + }, + }, + }, + }, + ], +] +`; + +exports[`@nx/remix/plugin Remix Classic Compiler non-root project should infer watch-deps target 1`] = ` +[ + [ + "my-app/remix.config.cjs", + { + "projects": { + "my-app": { + "metadata": {}, + "root": "my-app", + "targets": { + "build": { + "cache": true, + "command": "remix build", + "dependsOn": [ + "^build", + ], + "inputs": [ + "production", + "^production", + { + "externalDependencies": [ + "@remix-run/dev", + ], + }, + ], + "options": { + "cwd": "my-app", + }, + "outputs": [ + "{workspaceRoot}/my-app/build", + "{workspaceRoot}/my-app/public/build", + ], + }, + "build-deps": { + "dependsOn": [ + "^build", + ], + }, "dev": { "command": "remix dev --manual", "options": { @@ -82,6 +188,12 @@ exports[`@nx/remix/plugin Remix Classic Compiler non-root project should create "cwd": "my-app", }, }, + "watch-deps": { + "command": "npx nx watch --projects my-app --includeDependentProjects -- npx nx build-deps my-app", + "dependsOn": [ + "build-deps", + ], + }, }, }, }, @@ -212,6 +324,11 @@ exports[`@nx/remix/plugin Remix Vite Compiler non-root project should create nod "{workspaceRoot}/my-app/build", ], }, + "build-deps": { + "dependsOn": [ + "^build", + ], + }, "dev": { "command": "remix vite:dev", "options": { @@ -261,6 +378,12 @@ exports[`@nx/remix/plugin Remix Vite Compiler non-root project should create nod "cwd": "my-app", }, }, + "watch-deps": { + "command": "npx nx watch --projects my-app --includeDependentProjects -- npx nx build-deps my-app", + "dependsOn": [ + "build-deps", + ], + }, }, }, }, diff --git a/packages/remix/src/plugins/plugin.spec.ts b/packages/remix/src/plugins/plugin.spec.ts index 57f233c7aaf96..71f3e11cebf75 100644 --- a/packages/remix/src/plugins/plugin.spec.ts +++ b/packages/remix/src/plugins/plugin.spec.ts @@ -145,6 +145,27 @@ module.exports = { // ASSERT expect(nodes).toMatchSnapshot(); }); + + it('should infer watch-deps target', async () => { + tempFs.createFileSync( + 'my-app/package.json', + JSON.stringify('{"name": "my-app"}') + ); + + const nodes = await createNodesFunction( + ['my-app/remix.config.cjs'], + { + buildTargetName: 'build', + devTargetName: 'dev', + startTargetName: 'start', + typecheckTargetName: 'tsc', + staticServeTargetName: 'static-serve', + }, + context + ); + + expect(nodes).toMatchSnapshot(); + }); }); }); diff --git a/packages/remix/src/plugins/plugin.ts b/packages/remix/src/plugins/plugin.ts index 1bff582ded622..6ff05e92dcf2b 100644 --- a/packages/remix/src/plugins/plugin.ts +++ b/packages/remix/src/plugins/plugin.ts @@ -7,6 +7,7 @@ import { createNodesFromFiles, CreateNodesV2, detectPackageManager, + getPackageManagerCommand, joinPathFragments, logger, ProjectConfiguration, @@ -19,15 +20,19 @@ import { getNamedInputs } from '@nx/devkit/src/utils/get-named-inputs'; import { loadConfigFile } from '@nx/devkit/src/utils/config-utils'; import { getLockFileName } from '@nx/js'; import { type AppConfig } from '@remix-run/dev'; -import { dirname, isAbsolute, join, relative } from 'path'; +import { dirname, join } from 'path'; import { existsSync, readdirSync, readFileSync } from 'fs'; import { loadViteDynamicImport } from '../utils/executor-utils'; +import { addBuildAndWatchDepsTargets } from '@nx/js/src/plugins/typescript/util'; export interface RemixPluginOptions { buildTargetName?: string; devTargetName?: string; startTargetName?: string; typecheckTargetName?: string; + buildDepsTargetName?: string; + watchDepsTargetName?: string; + /** * @deprecated Use serveStaticTargetName instead. This option will be removed in Nx 21. */ @@ -35,6 +40,8 @@ export interface RemixPluginOptions { serveStaticTargetName?: string; } +const pmc = getPackageManagerCommand(); + type RemixTargets = Pick; function readTargetsCache( @@ -202,6 +209,14 @@ async function buildRemixTargets( siblingFiles ); + addBuildAndWatchDepsTargets( + context.workspaceRoot, + projectRoot, + targets, + options, + pmc + ); + return { targets, metadata: {} }; } diff --git a/packages/rollup/src/generators/init/init.ts b/packages/rollup/src/generators/init/init.ts index f454ef9a86c4c..2ee2fe49fe9b1 100644 --- a/packages/rollup/src/generators/init/init.ts +++ b/packages/rollup/src/generators/init/init.ts @@ -41,6 +41,16 @@ export async function rollupInitGenerator(tree: Tree, schema: Schema) { createNodes, { buildTargetName: ['build', 'rollup:build', 'rollup-build'], + buildDepsTargetName: [ + 'build-deps', + 'rollup:build-deps', + 'rollup-build-deps', + ], + watchDepsTargetName: [ + 'watch-deps', + 'rollup:watch-deps', + 'rollup-watch-deps', + ], }, schema.updatePackageScripts ); diff --git a/packages/rollup/src/plugins/__snapshots__/plugin.spec.ts.snap b/packages/rollup/src/plugins/__snapshots__/plugin.spec.ts.snap index 6b63e71a4ee62..5061b7036714a 100644 --- a/packages/rollup/src/plugins/__snapshots__/plugin.spec.ts.snap +++ b/packages/rollup/src/plugins/__snapshots__/plugin.spec.ts.snap @@ -47,6 +47,17 @@ exports[`@nx/rollup/plugin non-root project should create nodes 1`] = ` "{workspaceRoot}/mylib/dist", ], }, + "build-deps": { + "dependsOn": [ + "^build", + ], + }, + "watch-deps": { + "command": "npx nx watch --projects mylib --includeDependentProjects -- npx nx build-deps mylib", + "dependsOn": [ + "build-deps", + ], + }, }, }, }, @@ -102,6 +113,17 @@ exports[`@nx/rollup/plugin non-root project should create nodes 2`] = ` "{workspaceRoot}/mylib/dist", ], }, + "build-deps": { + "dependsOn": [ + "^build", + ], + }, + "watch-deps": { + "command": "npx nx watch --projects mylib --includeDependentProjects -- npx nx build-deps mylib", + "dependsOn": [ + "build-deps", + ], + }, }, }, }, @@ -156,6 +178,17 @@ exports[`@nx/rollup/plugin root project should create nodes 1`] = ` "{workspaceRoot}/dist", ], }, + "build-deps": { + "dependsOn": [ + "^build", + ], + }, + "watch-deps": { + "command": "npx nx watch --projects mylib --includeDependentProjects -- npx nx build-deps mylib", + "dependsOn": [ + "build-deps", + ], + }, }, }, }, @@ -210,6 +243,17 @@ exports[`@nx/rollup/plugin root project should create nodes 2`] = ` "{workspaceRoot}/dist", ], }, + "build-deps": { + "dependsOn": [ + "^build", + ], + }, + "watch-deps": { + "command": "npx nx watch --projects mylib --includeDependentProjects -- npx nx build-deps mylib", + "dependsOn": [ + "build-deps", + ], + }, }, }, }, diff --git a/packages/rollup/src/plugins/plugin.ts b/packages/rollup/src/plugins/plugin.ts index 5b3ccafec45b2..08cc03311b94e 100644 --- a/packages/rollup/src/plugins/plugin.ts +++ b/packages/rollup/src/plugins/plugin.ts @@ -21,6 +21,7 @@ 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'; +import { addBuildAndWatchDepsTargets } from '@nx/js/src/plugins/typescript/util'; const pmc = getPackageManagerCommand(); @@ -46,6 +47,8 @@ export const createDependencies: CreateDependencies = () => { export interface RollupPluginOptions { buildTargetName?: string; + buildDepsTargetName?: string; + watchDepsTargetName?: string; } const rollupConfigGlob = '**/rollup.config.{js,cjs,mjs,ts,cts,mts}'; @@ -218,6 +221,14 @@ async function buildRollupTarget( ]; } + addBuildAndWatchDepsTargets( + context.workspaceRoot, + projectRoot, + targets, + options, + pmc + ); + return targets; } @@ -261,5 +272,7 @@ function normalizeOptions( ): Required { return { buildTargetName: options.buildTargetName ?? 'build', + buildDepsTargetName: options.buildDepsTargetName ?? 'build-deps', + watchDepsTargetName: options.watchDepsTargetName ?? 'watch-deps', }; } diff --git a/packages/rsbuild/src/generators/init/init.ts b/packages/rsbuild/src/generators/init/init.ts index e1098e73d940e..8bd251e1e4199 100644 --- a/packages/rsbuild/src/generators/init/init.ts +++ b/packages/rsbuild/src/generators/init/init.ts @@ -55,7 +55,18 @@ export async function initGeneratorInternal( 'rsbuild:typecheck', 'rsbuild-typecheck', ], + buildDepsTargetName: [ + 'build-deps', + 'rsbuild:build-deps', + 'rsbuild-build-deps', + ], + watchDepsTargetName: [ + 'watch-deps', + 'rsbuild:watch-deps', + 'rsbuild-watch-deps', + ], }, + schema.updatePackageScripts ); } diff --git a/packages/rsbuild/src/plugins/plugin.spec.ts b/packages/rsbuild/src/plugins/plugin.spec.ts index 668d54a6a731d..d464376b6e2a0 100644 --- a/packages/rsbuild/src/plugins/plugin.spec.ts +++ b/packages/rsbuild/src/plugins/plugin.spec.ts @@ -68,6 +68,11 @@ describe('@nx/rsbuild', () => { "metadata": {}, "root": "my-app", "targets": { + "build-deps": { + "dependsOn": [ + "^build", + ], + }, "build-something": { "cache": true, "command": "rsbuild build", @@ -135,6 +140,12 @@ describe('@nx/rsbuild', () => { "cwd": "my-app", }, }, + "watch-deps": { + "command": "npx nx watch --projects my-app --includeDependentProjects -- npx nx build-deps my-app", + "dependsOn": [ + "build-deps", + ], + }, }, }, }, diff --git a/packages/rsbuild/src/plugins/plugin.ts b/packages/rsbuild/src/plugins/plugin.ts index d30e2ea8f2ad3..5210b534590bd 100644 --- a/packages/rsbuild/src/plugins/plugin.ts +++ b/packages/rsbuild/src/plugins/plugin.ts @@ -20,6 +20,7 @@ import { existsSync, readdirSync } from 'fs'; import { join, dirname, isAbsolute, relative } from 'path'; import { minimatch } from 'minimatch'; import { loadConfig, type RsbuildConfig } from '@rsbuild/core'; +import { addBuildAndWatchDepsTargets } from '@nx/js/src/plugins/typescript/util'; const pmc = getPackageManagerCommand(); @@ -29,6 +30,8 @@ export interface RsbuildPluginOptions { previewTargetName?: string; inspectTargetName?: string; typecheckTargetName?: string; + buildDepsTargetName?: string; + watchDepsTargetName?: string; } type RsbuildTargets = Pick; @@ -238,6 +241,14 @@ async function createRsbuildTargets( }; } + addBuildAndWatchDepsTargets( + context.workspaceRoot, + projectRoot, + targets, + options, + pmc + ); + return { targets, metadata: {} }; } diff --git a/packages/rspack/src/generators/init/init.ts b/packages/rspack/src/generators/init/init.ts index f32af80d9c696..312c65f019d79 100644 --- a/packages/rspack/src/generators/init/init.ts +++ b/packages/rspack/src/generators/init/init.ts @@ -60,6 +60,16 @@ export async function rspackInitGenerator( 'rspack-preview', 'preview-rspack', ], + buildDepsTargetName: [ + 'build-deps', + 'rspack:build-deps', + 'rspack-build-deps', + ], + watchDepsTargetName: [ + 'watch-deps', + 'rspack:watch-deps', + 'rspack-watch-deps', + ], }, schema.updatePackageScripts ); diff --git a/packages/rspack/src/plugins/plugin.ts b/packages/rspack/src/plugins/plugin.ts index bb729b5b2f75b..f0d6af6de7e1c 100644 --- a/packages/rspack/src/plugins/plugin.ts +++ b/packages/rspack/src/plugins/plugin.ts @@ -4,6 +4,7 @@ import { createNodesFromFiles, CreateNodesV2, detectPackageManager, + getPackageManagerCommand, ProjectConfiguration, readJsonFile, workspaceRoot, @@ -19,16 +20,21 @@ import { workspaceDataDirectory } from 'nx/src/utils/cache-directory'; import { dirname, isAbsolute, join, relative, resolve } from 'path'; import { readRspackOptions } from '../utils/read-rspack-options'; import { resolveUserDefinedRspackConfig } from '../utils/resolve-user-defined-rspack-config'; +import { addBuildAndWatchDepsTargets } from '@nx/js/src/plugins/typescript/util'; export interface RspackPluginOptions { buildTargetName?: string; serveTargetName?: string; serveStaticTargetName?: string; previewTargetName?: string; + buildDepsTargetName?: string; + watchDepsTargetName?: string; } type RspackTargets = Pick; +const pmc = getPackageManagerCommand(); + function readTargetsCache(cachePath: string): Record { return existsSync(cachePath) ? readJsonFile(cachePath) : {}; } @@ -213,6 +219,14 @@ async function createRspackTargets( ]; } + addBuildAndWatchDepsTargets( + context.workspaceRoot, + projectRoot, + targets, + options, + pmc + ); + return { targets, metadata: {} }; } diff --git a/packages/vite/src/generators/init/init.spec.ts b/packages/vite/src/generators/init/init.spec.ts index b7eaf1a845008..57ade419687a5 100644 --- a/packages/vite/src/generators/init/init.spec.ts +++ b/packages/vite/src/generators/init/init.spec.ts @@ -79,12 +79,14 @@ describe('@nx/vite:init', () => { "plugins": [ { "options": { + "buildDepsTargetName": "build-deps", "buildTargetName": "build", "previewTargetName": "preview", "serveStaticTargetName": "serve-static", "serveTargetName": "serve", "testTargetName": "test", "typecheckTargetName": "typecheck", + "watchDepsTargetName": "watch-deps", }, "plugin": "@nx/vite/plugin", }, diff --git a/packages/vite/src/generators/init/init.ts b/packages/vite/src/generators/init/init.ts index c6521fef3f2b1..768a29bc0ca8d 100644 --- a/packages/vite/src/generators/init/init.ts +++ b/packages/vite/src/generators/init/init.ts @@ -79,6 +79,16 @@ export async function initGeneratorInternal( 'vite-serve-static', ], typecheckTargetName: ['typecheck', 'vite:typecheck', 'vite-typecheck'], + buildDepsTargetName: [ + 'build-deps', + 'vite:build-deps', + 'vite-build-deps', + ], + watchDepsTargetName: [ + 'watch-deps', + 'vite:watch-deps', + 'vite-watch-deps', + ], }, schema.updatePackageScripts ); 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 01c51feb3da5f..4aff15f1d8039 100644 --- a/packages/vite/src/plugins/__snapshots__/plugin-vitest.spec.ts.snap +++ b/packages/vite/src/plugins/__snapshots__/plugin-vitest.spec.ts.snap @@ -10,6 +10,11 @@ exports[`@nx/vite/plugin root project should create nodes 1`] = ` "metadata": {}, "root": ".", "targets": { + "build-deps": { + "dependsOn": [ + "^build", + ], + }, "test": { "cache": true, "command": "vitest", @@ -74,6 +79,12 @@ exports[`@nx/vite/plugin root project should create nodes 1`] = ` "cwd": ".", }, }, + "watch-deps": { + "command": "npx nx watch --projects vite --includeDependentProjects -- npx nx build-deps vite", + "dependsOn": [ + "build-deps", + ], + }, }, }, }, 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 fd64c4dfc0573..da8667e3b971b 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 @@ -10,6 +10,11 @@ exports[`@nx/vite/plugin with test node root project should create nodes - with "metadata": {}, "root": ".", "targets": { + "build-deps": { + "dependsOn": [ + "^build", + ], + }, "test": { "cache": true, "command": "vitest", @@ -74,6 +79,12 @@ exports[`@nx/vite/plugin with test node root project should create nodes - with "cwd": ".", }, }, + "watch-deps": { + "command": "npx nx watch --projects vite --includeDependentProjects -- npx nx build-deps vite", + "dependsOn": [ + "build-deps", + ], + }, }, }, }, diff --git a/packages/vite/src/plugins/__snapshots__/plugin.spec.ts.snap b/packages/vite/src/plugins/__snapshots__/plugin.spec.ts.snap index 1a419719c9407..9ee2b8b4d1983 100644 --- a/packages/vite/src/plugins/__snapshots__/plugin.spec.ts.snap +++ b/packages/vite/src/plugins/__snapshots__/plugin.spec.ts.snap @@ -48,6 +48,17 @@ exports[`@nx/vite/plugin Library mode should exclude serve and preview targets w "{workspaceRoot}/dist/{projectRoot}", ], }, + "build-deps": { + "dependsOn": [ + "^build", + ], + }, + "watch-deps": { + "command": "npx nx watch --projects my-lib --includeDependentProjects -- npx nx build-deps my-lib", + "dependsOn": [ + "build-deps", + ], + }, }, }, }, @@ -67,6 +78,11 @@ exports[`@nx/vite/plugin not root project should create nodes 1`] = ` "projectType": "application", "root": "my-app", "targets": { + "build-deps": { + "dependsOn": [ + "^build", + ], + }, "build-something": { "cache": true, "command": "vite build", @@ -154,6 +170,12 @@ exports[`@nx/vite/plugin not root project should create nodes 1`] = ` "spa": true, }, }, + "watch-deps": { + "command": "npx nx watch --projects my-app --includeDependentProjects -- npx nx build-deps my-app", + "dependsOn": [ + "build-deps", + ], + }, }, }, }, diff --git a/packages/vite/src/plugins/plugin.spec.ts b/packages/vite/src/plugins/plugin.spec.ts index 7c747813c3270..6f109fa916a94 100644 --- a/packages/vite/src/plugins/plugin.spec.ts +++ b/packages/vite/src/plugins/plugin.spec.ts @@ -316,6 +316,11 @@ describe('@nx/vite/plugin', () => { "{workspaceRoot}/dist/{projectRoot}", ], }, + "build-deps": { + "dependsOn": [ + "^build", + ], + }, "preview": { "command": "vite preview", "dependsOn": [ @@ -366,6 +371,12 @@ describe('@nx/vite/plugin', () => { "spa": true, }, }, + "watch-deps": { + "command": "npx nx watch --projects my-lib --includeDependentProjects -- npx nx build-deps my-lib", + "dependsOn": [ + "build-deps", + ], + }, }, }, }, diff --git a/packages/vite/src/plugins/plugin.ts b/packages/vite/src/plugins/plugin.ts index ccb8e8ad6c9db..f3743519fd549 100644 --- a/packages/vite/src/plugins/plugin.ts +++ b/packages/vite/src/plugins/plugin.ts @@ -23,6 +23,7 @@ import { loadViteDynamicImport } from '../utils/executor-utils'; import { hashObject } from 'nx/src/hasher/file-hasher'; import { minimatch } from 'minimatch'; import { isUsingTsSolutionSetup as _isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; +import { addBuildAndWatchDepsTargets } from '@nx/js/src/plugins/typescript/util'; const pmc = getPackageManagerCommand(); @@ -33,6 +34,8 @@ export interface VitePluginOptions { previewTargetName?: string; serveStaticTargetName?: string; typecheckTargetName?: string; + watchDepsTargetName?: string; + buildDepsTargetName?: string; } type ViteTargets = Pick; @@ -277,6 +280,14 @@ async function buildViteTargets( ); } + addBuildAndWatchDepsTargets( + context.workspaceRoot, + projectRoot, + targets, + options, + pmc + ); + const metadata = {}; return { targets, metadata, isLibrary: Boolean(viteBuildConfig.build?.lib) }; } diff --git a/packages/vue/src/generators/application/application.spec.ts b/packages/vue/src/generators/application/application.spec.ts index 39e3e5e4c9438..5633c6d1150e0 100644 --- a/packages/vue/src/generators/application/application.spec.ts +++ b/packages/vue/src/generators/application/application.spec.ts @@ -119,11 +119,13 @@ describe('application generator', () => { ).toMatchInlineSnapshot(` { "options": { + "buildDepsTargetName": "build-deps", "buildTargetName": "build", "devTargetName": "dev", "inspectTargetName": "inspect", "previewTargetName": "preview", "typecheckTargetName": "typecheck", + "watchDepsTargetName": "watch-deps", }, "plugin": "@nx/rsbuild", } diff --git a/packages/webpack/src/generators/init/init.ts b/packages/webpack/src/generators/init/init.ts index 24f10417e6036..fb3a32b12eaac 100644 --- a/packages/webpack/src/generators/init/init.ts +++ b/packages/webpack/src/generators/init/init.ts @@ -50,6 +50,16 @@ export async function webpackInitGeneratorInternal(tree: Tree, schema: Schema) { 'webpack-preview', 'preview-webpack', ], + buildDepsTargetName: [ + 'build-deps', + 'webpack:build-deps', + 'webpack-build-deps', + ], + watchDepsTargetName: [ + 'watch-deps', + 'webpack:watch-deps', + 'webpack-watch-deps', + ], }, schema.updatePackageScripts ); diff --git a/packages/webpack/src/plugins/__snapshots__/plugin.spec.ts.snap b/packages/webpack/src/plugins/__snapshots__/plugin.spec.ts.snap index ac4cb429b7f37..7cc8889a480a1 100644 --- a/packages/webpack/src/plugins/__snapshots__/plugin.spec.ts.snap +++ b/packages/webpack/src/plugins/__snapshots__/plugin.spec.ts.snap @@ -10,6 +10,11 @@ exports[`@nx/webpack/plugin should create nodes 1`] = ` "metadata": {}, "projectType": "application", "targets": { + "build-deps": { + "dependsOn": [ + "^build", + ], + }, "build-something": { "cache": true, "command": "webpack-cli build", @@ -114,6 +119,12 @@ exports[`@nx/webpack/plugin should create nodes 1`] = ` "spa": true, }, }, + "watch-deps": { + "command": "npx nx watch --projects my-app --includeDependentProjects -- npx nx build-deps my-app", + "dependsOn": [ + "build-deps", + ], + }, }, }, }, diff --git a/packages/webpack/src/plugins/plugin.ts b/packages/webpack/src/plugins/plugin.ts index fe42b91575391..be26c27cc3d7a 100644 --- a/packages/webpack/src/plugins/plugin.ts +++ b/packages/webpack/src/plugins/plugin.ts @@ -24,6 +24,7 @@ import { workspaceDataDirectory } from 'nx/src/utils/cache-directory'; import { dirname, isAbsolute, join, relative, resolve } from 'path'; import { readWebpackOptions } from '../utils/webpack/read-webpack-options'; import { resolveUserDefinedWebpackConfig } from '../utils/webpack/resolve-user-defined-webpack-config'; +import { addBuildAndWatchDepsTargets } from '@nx/js/src/plugins/typescript/util'; const pmc = getPackageManagerCommand(); @@ -32,6 +33,8 @@ export interface WebpackPluginOptions { serveTargetName?: string; serveStaticTargetName?: string; previewTargetName?: string; + buildDepsTargetName?: string; + watchDepsTargetName?: string; } type WebpackTargets = Pick; @@ -275,6 +278,14 @@ async function createWebpackTargets( ]; } + addBuildAndWatchDepsTargets( + context.workspaceRoot, + projectRoot, + targets, + options, + pmc + ); + return { targets, metadata: {} }; } @@ -317,5 +328,7 @@ function normalizeOptions( serveTargetName: options?.serveTargetName ?? 'serve', serveStaticTargetName: options?.serveStaticTargetName ?? 'serve-static', previewTargetName: options?.previewTargetName ?? 'preview', + buildDepsTargetName: 'build-deps', + watchDepsTargetName: 'watch-deps', }; }