feat(js): infer build-deps and watch-deps targets for incremental builds (#29609)

This PR adds `build-deps` and `watch-deps` targets to buildable JS
projects to help with incremental builds.

A use-case for this is if an app (e.g. Vite React app) has buildable
dependencies that need to be rebuilt when they change.

Say, you create a React app and lib as follows:

```
nx g @nx/react:app apps/react-app --bundler vite 
nx g @nx/react:lib packages/react-lib --bundler vite
```

And import `react-lib` inside the app.

```jsx
import { ReactLib } from '@acme/react-lib';
//...
return <ReactLib />
```

The user can then run:

```
nx watch-deps react-app
```

And then serve the app in another terminal:
```
nx serve react-app
```

Then whenever code is updated for a buildable dependency, it'll be
rebuilt and then reloaded in the app.
This commit is contained in:
Jack Hsu 2025-01-14 16:13:43 -05:00 committed by GitHub
parent 65e9a6b203
commit 0ae8665a88
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
38 changed files with 634 additions and 6 deletions

View File

@ -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
);

View File

@ -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<string, Record<string, TargetConfiguration<DetoxPluginOptions>>> {
@ -141,6 +147,14 @@ function buildDetoxTargets(
},
};
addBuildAndWatchDepsTargets(
context.workspaceRoot,
projectRoot,
targets,
options,
pmc
);
return targets;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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",
],
},
},
},
},

View File

@ -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',
};
}

View File

@ -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<string, TargetConfiguration>,
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}`,
};
}
}

View File

@ -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
);

View File

@ -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",
],
},
},
},
},

View File

@ -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;
}

View File

@ -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
);

View File

@ -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",
],
},
},
},
},

View File

@ -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<string, TargetConfiguration>
@ -46,6 +50,8 @@ export interface NuxtPluginOptions {
serveTargetName?: string;
serveStaticTargetName?: string;
buildStaticTargetName?: string;
buildDepsTargetName?: string;
watchDepsTargetName?: string;
}
export const createNodes: CreateNodes<NuxtPluginOptions> = [
@ -121,6 +127,14 @@ async function buildNuxtTargets(
projectRoot
);
addBuildAndWatchDepsTargets(
context.workspaceRoot,
projectRoot,
targets,
options,
pmc
);
return targets;
}

View File

@ -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",
},

View File

@ -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

View File

@ -33,6 +33,11 @@ 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": {
@ -82,6 +87,113 @@ 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",
],
},
},
},
},
},
],
]
`;
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": {
"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",
],
},
},
},
},
@ -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",
],
},
},
},
},

View File

@ -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();
});
});
});

View File

@ -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<ProjectConfiguration, 'targets' | 'metadata'>;
function readTargetsCache(
@ -202,6 +209,14 @@ async function buildRemixTargets(
siblingFiles
);
addBuildAndWatchDepsTargets(
context.workspaceRoot,
projectRoot,
targets,
options,
pmc
);
return { targets, metadata: {} };
}

View File

@ -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
);

View File

@ -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",
],
},
},
},
},

View File

@ -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<RollupPluginOptions> {
return {
buildTargetName: options.buildTargetName ?? 'build',
buildDepsTargetName: options.buildDepsTargetName ?? 'build-deps',
watchDepsTargetName: options.watchDepsTargetName ?? 'watch-deps',
};
}

View File

@ -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
);
}

View File

@ -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",
],
},
},
},
},

View File

@ -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<ProjectConfiguration, 'targets' | 'metadata'>;
@ -238,6 +241,14 @@ async function createRsbuildTargets(
};
}
addBuildAndWatchDepsTargets(
context.workspaceRoot,
projectRoot,
targets,
options,
pmc
);
return { targets, metadata: {} };
}

View File

@ -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
);

View File

@ -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<ProjectConfiguration, 'targets' | 'metadata'>;
const pmc = getPackageManagerCommand();
function readTargetsCache(cachePath: string): Record<string, RspackTargets> {
return existsSync(cachePath) ? readJsonFile(cachePath) : {};
}
@ -213,6 +219,14 @@ async function createRspackTargets(
];
}
addBuildAndWatchDepsTargets(
context.workspaceRoot,
projectRoot,
targets,
options,
pmc
);
return { targets, metadata: {} };
}

View File

@ -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",
},

View File

@ -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
);

View File

@ -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",
],
},
},
},
},

View File

@ -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",
],
},
},
},
},

View File

@ -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",
],
},
},
},
},

View File

@ -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",
],
},
},
},
},

View File

@ -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<ProjectConfiguration, 'targets' | 'metadata'>;
@ -277,6 +280,14 @@ async function buildViteTargets(
);
}
addBuildAndWatchDepsTargets(
context.workspaceRoot,
projectRoot,
targets,
options,
pmc
);
const metadata = {};
return { targets, metadata, isLibrary: Boolean(viteBuildConfig.build?.lib) };
}

View File

@ -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",
}

View File

@ -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
);

View File

@ -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",
],
},
},
},
},

View File

@ -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<ProjectConfiguration, 'targets' | 'metadata'>;
@ -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',
};
}