From bae3acd48ea6eb217270f6e87f7485a32b5a8e46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leosvel=20P=C3=A9rez=20Espinosa?= Date: Thu, 27 Mar 2025 10:31:53 +0100 Subject: [PATCH] fix(misc): handle outputs with globs when normalizing tsconfig path mappings for buidable libraries (#30506) ## Current Behavior If a buildable library depends on another buildable library that has `outputs` using globs the build fails when using an executor that remaps the dependency TypeScript path mappings to the build outputs. ## Expected Behavior Building a buildable library using an executor that remaps the dependency TypeScript path mappings to the build outputs should succeed. The remapping logic should identify and replace the glob patterns and keep the fixed part of the pattern (no segment with wildcards). Note: additionally, an obsolete check was removed from the `@nx/angular:package` and `@nx/angular:delegate-build`. ## Related Issue(s) Fixes #30041 --- .../delegate-build/delegate-build.impl.ts | 12 ---- .../src/executors/package/package.impl.ts | 28 +++------ .../js/src/utils/buildable-libs-utils.spec.ts | 35 ++++++++++++ packages/js/src/utils/buildable-libs-utils.ts | 57 ++----------------- 4 files changed, 47 insertions(+), 85 deletions(-) diff --git a/packages/angular/src/executors/delegate-build/delegate-build.impl.ts b/packages/angular/src/executors/delegate-build/delegate-build.impl.ts index a1ff357dcf..663f4ef35c 100644 --- a/packages/angular/src/executors/delegate-build/delegate-build.impl.ts +++ b/packages/angular/src/executors/delegate-build/delegate-build.impl.ts @@ -2,7 +2,6 @@ import type { ExecutorContext } from '@nx/devkit'; import { joinPathFragments, parseTargetString, runExecutor } from '@nx/devkit'; import { calculateProjectBuildableDependencies, - checkDependentProjectsHaveBeenBuilt, createTmpTsConfig, } from '@nx/js/src/utils/buildable-libs-utils'; import type { DelegateBuildExecutorSchema } from './schema'; @@ -27,17 +26,6 @@ export async function* delegateBuildExecutor( dependencies ); - if ( - !checkDependentProjectsHaveBeenBuilt( - context.root, - context.projectName, - context.targetName, - dependencies - ) - ) { - return { success: false }; - } - const { buildTarget, ...targetOptions } = options; const delegateTarget = parseTargetString(buildTarget, context); diff --git a/packages/angular/src/executors/package/package.impl.ts b/packages/angular/src/executors/package/package.impl.ts index e4424764d9..f951d2ef5d 100644 --- a/packages/angular/src/executors/package/package.impl.ts +++ b/packages/angular/src/executors/package/package.impl.ts @@ -2,7 +2,6 @@ import type { ExecutorContext } from '@nx/devkit'; import { eachValueFrom } from '@nx/devkit/src/utils/rxjs-for-await'; import { calculateProjectBuildableDependencies, - checkDependentProjectsHaveBeenBuilt, createTmpTsConfig, type DependentBuildableProjectNode, } from '@nx/js/src/utils/buildable-libs-utils'; @@ -65,25 +64,14 @@ export function createLibraryExecutor( ); } - const { target, dependencies, topLevelDependencies } = - calculateProjectBuildableDependencies( - context.taskGraph, - context.projectGraph, - context.root, - context.projectName, - context.targetName, - context.configurationName - ); - if ( - !checkDependentProjectsHaveBeenBuilt( - context.root, - context.projectName, - context.targetName, - dependencies - ) - ) { - return Promise.resolve({ success: false }); - } + const { dependencies } = calculateProjectBuildableDependencies( + context.taskGraph, + context.projectGraph, + context.root, + context.projectName, + context.targetName, + context.configurationName + ); if (options.watch) { return yield* eachValueFrom( diff --git a/packages/js/src/utils/buildable-libs-utils.spec.ts b/packages/js/src/utils/buildable-libs-utils.spec.ts index 709851c3c1..e3eb80c343 100644 --- a/packages/js/src/utils/buildable-libs-utils.spec.ts +++ b/packages/js/src/utils/buildable-libs-utils.spec.ts @@ -45,6 +45,41 @@ describe('updatePaths', () => { ], }); }); + + it('should handle outputs with glob patterns', () => { + const paths: Record = { + '@proj/lib1': ['libs/lib1/src/index.ts'], + '@proj/lib2': ['libs/lib2/src/index.ts'], + '@proj/lib3': ['libs/lib3/src/index.ts'], + }; + + updatePaths( + [ + { + name: '@proj/lib1', + node: { name: 'lib1', type: 'lib', data: { root: 'libs/lib1' } }, + outputs: ['dist/libs/lib1/**/*.js'], + }, + { + name: '@proj/lib2', + node: { name: 'lib2', type: 'lib', data: { root: 'libs/lib2' } }, + outputs: ['dist/libs/lib2/*.js'], + }, + { + name: '@proj/lib3', + node: { name: 'lib3', type: 'lib', data: { root: 'libs/lib3' } }, + outputs: ['dist/libs/lib3/foo-*/*.js'], + }, + ], + paths + ); + + expect(paths).toEqual({ + '@proj/lib1': ['dist/libs/lib1'], + '@proj/lib2': ['dist/libs/lib2'], + '@proj/lib3': ['dist/libs/lib3'], + }); + }); }); describe('calculateProjectDependencies', () => { diff --git a/packages/js/src/utils/buildable-libs-utils.ts b/packages/js/src/utils/buildable-libs-utils.ts index 6107594199..3212ae55ca 100644 --- a/packages/js/src/utils/buildable-libs-utils.ts +++ b/packages/js/src/utils/buildable-libs-utils.ts @@ -8,12 +8,11 @@ import { getOutputsForTargetAndConfiguration, parseTargetString, readJsonFile, - stripIndents, writeJsonFile, } from '@nx/devkit'; import { unlinkSync } from 'fs'; import { isNpmProject } from 'nx/src/project-graph/operators'; -import { directoryExists, fileExists } from 'nx/src/utils/fileutils'; +import { fileExists } from 'nx/src/utils/fileutils'; import { output } from 'nx/src/utils/output'; import { dirname, join, relative, extname, resolve } from 'path'; import type * as ts from 'typescript'; @@ -477,56 +476,6 @@ function cleanupTmpTsConfigFile(tmpTsConfigPath) { } catch (e) {} } -export function checkDependentProjectsHaveBeenBuilt( - root: string, - projectName: string, - targetName: string, - projectDependencies: DependentBuildableProjectNode[] -): boolean { - const missing = findMissingBuildDependencies( - root, - projectName, - targetName, - projectDependencies - ); - if (missing.length > 0) { - console.error(stripIndents` - It looks like all of ${projectName}'s dependencies have not been built yet: - ${missing.map((x) => ` - ${x.node.name}`).join('\n')} - - You might be missing a "targetDefaults" configuration in your root nx.json (https://nx.dev/reference/project-configuration#target-defaults), - or "dependsOn" configured in ${projectName}'s project.json (https://nx.dev/reference/project-configuration#dependson) - `); - return false; - } else { - return true; - } -} - -export function findMissingBuildDependencies( - root: string, - projectName: string, - targetName: string, - projectDependencies: DependentBuildableProjectNode[] -): DependentBuildableProjectNode[] { - const depLibsToBuildFirst: DependentBuildableProjectNode[] = []; - - // verify whether all dependent libraries have been built - projectDependencies.forEach((dep) => { - if (dep.node.type !== 'lib') { - return; - } - - const paths = dep.outputs.map((p) => join(root, p)); - - if (!paths.some(directoryExists)) { - depLibsToBuildFirst.push(dep); - } - }); - - return depLibsToBuildFirst; -} - export function updatePaths( dependencies: DependentBuildableProjectNode[], paths: Record @@ -539,7 +488,9 @@ export function updatePaths( // If there are outputs if (dep.outputs && dep.outputs.length > 0) { // Directly map the dependency name to the output paths (dist/packages/..., etc.) - paths[dep.name] = dep.outputs; + paths[dep.name] = dep.outputs.map((output) => + output.replace(/(\*|\/[^\/]*\*).*$/, '') + ); // check for secondary entrypoints // For each registered path