fix(bundling): include tsconfig solution input for webpack (#35477)

## Current Behavior

The `@nx/webpack` executor, inferred plugin, and config builder all call
`isUsingTsSolutionSetup()` and let its result influence task outputs
(e.g. `useTsconfigPaths`). However, the root `tsconfig.json` is not part
of the build task's cache inputs — so edits to root `tsconfig.json`
(`extends`, `files`, `include`) don't invalidate webpack task caches and
stale outputs are reused.

The same gap exists in `@nx/node`'s webpack-bundler branch of the
application generator: it calls `addBuildTargetDefaults(tree,
'@nx/webpack:webpack')` without the tsconfig input, even though the
parallel esbuild branch in the same file already passes
`TS_SOLUTION_SETUP_TSCONFIG_INPUT`.

## Expected Behavior

Matches the rollup fix in #35476: the root `tsconfig.json` is included
as a structured input (`{ json: '{workspaceRoot}/tsconfig.json', fields:
['extends', 'files', 'include'] }`) on `@nx/webpack:webpack` task
defaults and in the inferred plugin's build target inputs, so changes to
the relevant fields invalidate caches.

### Changes
- `packages/webpack/src/plugins/plugin.ts` — append
`TS_SOLUTION_SETUP_TSCONFIG_INPUT` to the inferred build target's
`inputs`. Also gate the targets cache on `NX_CACHE_PROJECT_GRAPH`
(mirrors the rollup PR) and update the spec accordingly.
- `packages/webpack/src/generators/configuration/configuration.ts` —
pass `'build', [TS_SOLUTION_SETUP_TSCONFIG_INPUT]` to
`addBuildTargetDefaults`.
- `packages/node/src/generators/application/lib/create-project.ts` —
same on the webpack branch (the esbuild branch already had it).
- `packages/webpack/src/plugins/plugin.spec.ts` — mock spreads
`requireActual` so the constant is real; sets/restores
`NX_CACHE_PROJECT_GRAPH`; snapshot updated to include the new input.

<!-- polygraph-session-start -->
---
[View session information
↗](https://snapshot.app.trypolygraph.com/orgs/69cdc268b6aa527e4129c2b4/sessions/73d1eed2)
<!-- polygraph-session-end -->

Co-authored-by: Leosvel Pérez Espinosa <leosvel.perez.espinosa@gmail.com>
This commit is contained in:
polygraph-app[bot]
2026-04-28 17:56:56 -04:00
committed by GitHub
parent 7a6f796047
commit ca7671afd6
4 changed files with 37 additions and 5 deletions
@@ -38,7 +38,9 @@ export function addProject(
project.targets.build = getEsBuildConfig(tree, project, options);
} else if (options.bundler === 'webpack') {
if (!hasWebpackPlugin(tree) && options.addPlugin === false) {
addBuildTargetDefaults(tree, `@nx/webpack:webpack`);
addBuildTargetDefaults(tree, `@nx/webpack:webpack`, 'build', [
TS_SOLUTION_SETUP_TSCONFIG_INPUT,
]);
project.targets.build = getWebpackBuildConfig(tree, project, options);
} else if (options.isNest) {
// If we are using Nest that has the webpack plugin we need to override the
@@ -16,6 +16,7 @@ import { ConfigurationGeneratorSchema } from './schema';
import { WebpackExecutorOptions } from '../../executors/webpack/schema';
import { hasPlugin } from '../../utils/has-plugin';
import { addBuildTargetDefaults } from '@nx/devkit/src/generators/target-defaults-utils';
import { TS_SOLUTION_SETUP_TSCONFIG_INPUT } from '@nx/js/src/utils/typescript/ts-solution-setup';
import { ensureDependencies } from '../../utils/ensure-dependencies';
export function configurationGenerator(
@@ -179,7 +180,9 @@ module.exports = composePlugins(withNx(), (config) => {
}
function addBuildTarget(tree: Tree, options: ConfigurationGeneratorSchema) {
addBuildTargetDefaults(tree, '@nx/webpack:webpack');
addBuildTargetDefaults(tree, '@nx/webpack:webpack', 'build', [
TS_SOLUTION_SETUP_TSCONFIG_INPUT,
]);
const project = readProjectConfiguration(tree, options.project);
const buildOptions: WebpackExecutorOptions = {
@@ -8,6 +8,7 @@ jest.mock('@nx/devkit', () => ({
// Needed so the current environment is not used
jest.mock('@nx/js/src/utils/typescript/ts-solution-setup', () => ({
...jest.requireActual('@nx/js/src/utils/typescript/ts-solution-setup'),
isUsingTsSolutionSetup: jest.fn(() => false),
}));
@@ -20,8 +21,10 @@ describe('@nx/webpack/plugin', () => {
let createNodesFunction = createNodesV2[1];
let context: CreateNodesContextV2;
let tempFs: TempFs;
let originalCacheProjectGraph = process.env.NX_CACHE_PROJECT_GRAPH;
beforeEach(() => {
process.env.NX_CACHE_PROJECT_GRAPH = 'false';
tempFs = new TempFs('webpack-plugin');
context = {
@@ -44,6 +47,11 @@ describe('@nx/webpack/plugin', () => {
afterEach(() => {
jest.resetModules();
if (originalCacheProjectGraph !== undefined) {
process.env.NX_CACHE_PROJECT_GRAPH = originalCacheProjectGraph;
} else {
delete process.env.NX_CACHE_PROJECT_GRAPH;
}
});
it('should create nodes', async () => {
@@ -95,6 +103,14 @@ describe('@nx/webpack/plugin', () => {
"webpack-cli",
],
},
{
"fields": [
"extends",
"files",
"include",
],
"json": "{workspaceRoot}/tsconfig.json",
},
],
"metadata": {
"description": "Runs Webpack build",
+14 -3
View File
@@ -16,8 +16,11 @@ 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 {
isUsingTsSolutionSetup,
TS_SOLUTION_SETUP_TSCONFIG_INPUT,
} from '@nx/js/src/utils/typescript/ts-solution-setup';
import { readdirSync } from 'fs';
import { hashObject } from 'nx/src/hasher/file-hasher';
import { workspaceDataDirectory } from 'nx/src/utils/cache-directory';
import { dirname, isAbsolute, join, relative, resolve } from 'path';
@@ -37,7 +40,13 @@ export interface WebpackPluginOptions {
type WebpackTargets = Pick<ProjectConfiguration, 'targets' | 'metadata'>;
function readTargetsCache(cachePath: string): Record<string, WebpackTargets> {
return existsSync(cachePath) ? readJsonFile(cachePath) : {};
try {
return process.env.NX_CACHE_PROJECT_GRAPH !== 'false'
? readJsonFile(cachePath)
: {};
} catch {
return {};
}
}
function writeTargetsToCache(
@@ -181,6 +190,7 @@ async function createWebpackTargets(
{
externalDependencies: ['webpack-cli'],
},
TS_SOLUTION_SETUP_TSCONFIG_INPUT,
]
: [
'default',
@@ -188,6 +198,7 @@ async function createWebpackTargets(
{
externalDependencies: ['webpack-cli'],
},
TS_SOLUTION_SETUP_TSCONFIG_INPUT,
],
outputs,
metadata: {