feat(webpack): add option to opt out of watching buildable dependencies (#29984)

Add a `watchDependencies` options to the relevant webpack executors and
plugins to allow opting out of watching buildable dependencies.

## Current Behavior

## Expected Behavior

## Related Issue(s)

Fixes #29961
This commit is contained in:
Leosvel Pérez Espinosa 2025-02-13 17:00:54 +01:00 committed by GitHub
parent 9234241570
commit 9e204f973c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 77 additions and 14 deletions

View File

@ -150,6 +150,11 @@
"type": "string", "type": "string",
"description": "The path to the middleware function. Relative to the workspace root." "description": "The path to the middleware function. Relative to the workspace root."
} }
},
"watchDependencies": {
"type": "boolean",
"description": "Watch buildable dependencies and rebuild when they change.",
"default": true
} }
}, },
"additionalProperties": false, "additionalProperties": false,

View File

@ -561,6 +561,11 @@
"type": "boolean", "type": "boolean",
"description": "Read buildable libraries from source instead of building them separately.", "description": "Read buildable libraries from source instead of building them separately.",
"default": true "default": true
},
"watchDependencies": {
"type": "boolean",
"description": "Watch buildable dependencies and rebuild when they change.",
"default": true
} }
}, },
"additionalProperties": false, "additionalProperties": false,

View File

@ -301,6 +301,12 @@ Type: `boolean`
Watch for file changes. Watch for file changes.
##### watchDependencies
Type: `boolean`
Watch for buildable dependencies and rebuild when they change. Default is `true`.
#### Example #### Example
```js ```js

View File

@ -214,7 +214,8 @@ export function executeDevServerBuilder(
new WebpackNxBuildCoordinationPlugin( new WebpackNxBuildCoordinationPlugin(
`nx run-many --target=${ `nx run-many --target=${
parsedBuildTarget.target parsedBuildTarget.target
} --projects=${workspaceDependencies.join(',')}` } --projects=${workspaceDependencies.join(',')}`,
{ skipWatchingDeps: !options.watchDependencies }
) )
); );
} }
@ -269,6 +270,7 @@ function getDelegateBuilderOptions(
// delete extra option not supported by the delegate builder // delete extra option not supported by the delegate builder
delete delegateBuilderOptions.buildLibsFromSource; delete delegateBuilderOptions.buildLibsFromSource;
delete delegateBuilderOptions.watchDependencies;
return delegateBuilderOptions; return delegateBuilderOptions;
} }

View File

@ -24,5 +24,6 @@ export function normalizeOptions(schema: Schema): NormalizedSchema {
hmr: schema.hmr ?? (angularMajorVersion < 19 ? false : undefined), hmr: schema.hmr ?? (angularMajorVersion < 19 ? false : undefined),
open: schema.open ?? false, open: schema.open ?? false,
ssl: schema.ssl ?? false, ssl: schema.ssl ?? false,
watchDependencies: schema.watchDependencies ?? true,
}; };
} }

View File

@ -21,6 +21,7 @@ interface BaseSchema {
prebundle?: boolean | { exclude: string[] }; prebundle?: boolean | { exclude: string[] };
buildLibsFromSource?: boolean; buildLibsFromSource?: boolean;
esbuildMiddleware?: string[]; esbuildMiddleware?: string[];
watchDependencies?: boolean;
} }
export type SchemaWithBrowserTarget = BaseSchema & { export type SchemaWithBrowserTarget = BaseSchema & {

View File

@ -156,6 +156,11 @@
"type": "string", "type": "string",
"description": "The path to the middleware function. Relative to the workspace root." "description": "The path to the middleware function. Relative to the workspace root."
} }
},
"watchDependencies": {
"type": "boolean",
"description": "Watch buildable dependencies and rebuild when they change.",
"default": true
} }
}, },
"additionalProperties": false, "additionalProperties": false,

View File

@ -6,8 +6,10 @@ export type BrowserBuilderSchema = Schema & {
}; };
indexHtmlTransformer?: string; indexHtmlTransformer?: string;
buildLibsFromSource?: boolean; buildLibsFromSource?: boolean;
watchDependencies?: boolean;
/** /**
* @deprecated Use `indexHtmlTransformer` instead. It will be removed in Nx 20. * @deprecated Use `indexHtmlTransformer` instead. It will be removed in Nx 21.
*/ */
indexFileTransformer?: string; indexFileTransformer?: string;
}; };

View File

@ -464,6 +464,11 @@
"type": "boolean", "type": "boolean",
"description": "Read buildable libraries from source instead of building them separately.", "description": "Read buildable libraries from source instead of building them separately.",
"default": true "default": true
},
"watchDependencies": {
"type": "boolean",
"description": "Watch buildable dependencies and rebuild when they change.",
"default": true
} }
}, },
"additionalProperties": false, "additionalProperties": false,

View File

@ -51,12 +51,14 @@ export function executeWebpackBrowserBuilder(
context: import('@angular-devkit/architect').BuilderContext context: import('@angular-devkit/architect').BuilderContext
): Observable<import('@angular-devkit/architect').BuilderOutput> { ): Observable<import('@angular-devkit/architect').BuilderOutput> {
options.buildLibsFromSource ??= true; options.buildLibsFromSource ??= true;
options.watchDependencies ??= true;
const { const {
buildLibsFromSource, buildLibsFromSource,
customWebpackConfig, customWebpackConfig,
indexHtmlTransformer, indexHtmlTransformer,
indexFileTransformer, indexFileTransformer,
watchDependencies,
...delegateBuilderOptions ...delegateBuilderOptions
} = options; } = options;
@ -124,7 +126,7 @@ export function executeWebpackBrowserBuilder(
`nx run-many --target=${ `nx run-many --target=${
context.target.target context.target.target
} --projects=${workspaceDependencies.join(',')}`, } --projects=${workspaceDependencies.join(',')}`,
skipInitialRun { skipInitialRun, skipWatchingDeps: !watchDependencies }
) )
); );
} }

View File

@ -46,7 +46,7 @@ export class NxTsconfigPathsWebpackPlugin {
handleBuildLibsFromSource( handleBuildLibsFromSource(
config: Partial<WebpackOptionsNormalized | Configuration>, config: Partial<WebpackOptionsNormalized | Configuration>,
options options: NormalizedNxAppWebpackPluginOptions
): void { ): void {
if (!options.buildLibsFromSource && options.targetName) { if (!options.buildLibsFromSource && options.targetName) {
const remappedTarget = const remappedTarget =
@ -75,7 +75,11 @@ export class NxTsconfigPathsWebpackPlugin {
const buildCommand = `nx run-many --target=build --projects=${buildableDependencies}`; const buildCommand = `nx run-many --target=build --projects=${buildableDependencies}`;
config.plugins.push(new WebpackNxBuildCoordinationPlugin(buildCommand)); config.plugins.push(
new WebpackNxBuildCoordinationPlugin(buildCommand, {
skipWatchingDeps: options.watchDependencies === false,
})
);
} }
} }
} }

View File

@ -235,6 +235,10 @@ export interface NxAppWebpackPluginOptions {
* Whether to rebase absolute path for assets in postcss cli resources. * Whether to rebase absolute path for assets in postcss cli resources.
*/ */
rebaseRootRelative?: boolean; rebaseRootRelative?: boolean;
/**
* Watch buildable dependencies and rebuild when they change.
*/
watchDependencies?: boolean;
} }
export interface NormalizedNxAppWebpackPluginOptions export interface NormalizedNxAppWebpackPluginOptions

View File

@ -4,21 +4,42 @@ import { daemonClient, isDaemonEnabled } from 'nx/src/daemon/client/client';
import { BatchFunctionRunner } from 'nx/src/command-line/watch/watch'; import { BatchFunctionRunner } from 'nx/src/command-line/watch/watch';
import { output } from 'nx/src/utils/output'; import { output } from 'nx/src/utils/output';
type PluginOptions = {
skipInitialBuild?: boolean;
skipWatchingDeps?: boolean;
};
export class WebpackNxBuildCoordinationPlugin { export class WebpackNxBuildCoordinationPlugin {
private currentlyRunning: 'none' | 'nx-build' | 'webpack-build' = 'none'; private currentlyRunning: 'none' | 'nx-build' | 'webpack-build' = 'none';
private buildCmdProcess: ReturnType<typeof exec> | null = null; private buildCmdProcess: ReturnType<typeof exec> | null = null;
constructor(private readonly buildCmd: string, skipInitialBuild?: boolean) { constructor(buildCmd: string);
if (!skipInitialBuild) { /**
* @deprecated Use the constructor with the `options` parameter instead.
*/
constructor(buildCmd: string, skipInitialBuild?: boolean);
constructor(buildCmd: string, options?: PluginOptions);
constructor(
private readonly buildCmd: string,
skipInitialBuildOrOptions?: boolean | PluginOptions
) {
const options =
typeof skipInitialBuildOrOptions === 'boolean'
? { skipInitialBuild: skipInitialBuildOrOptions }
: skipInitialBuildOrOptions;
if (!options?.skipInitialBuild) {
this.buildChangedProjects(); this.buildChangedProjects();
} }
if (isDaemonEnabled()) { if (!options?.skipWatchingDeps) {
this.startWatchingBuildableLibs(); if (isDaemonEnabled()) {
} else { this.startWatchingBuildableLibs();
output.warn({ } else {
title: output.warn({
'Nx Daemon is not enabled. Buildable libs will not be rebuilt on file changes.', title:
}); 'Nx Daemon is not enabled. Buildable libs will not be rebuilt on file changes.',
});
}
} }
} }