From a9a676a570b2ef225464504a76d5251e20980e28 Mon Sep 17 00:00:00 2001 From: Colum Ferry Date: Fri, 15 Dec 2023 16:07:13 +0000 Subject: [PATCH] fix(module-federation): support buildable libs (#20786) --- .../module-federation-dev-server.json | 5 +++ .../builders/dev-server/dev-server.impl.ts | 5 +++ .../webpack-browser/webpack-browser.impl.ts | 5 +++ .../webpack-server/webpack-server.impl.ts | 9 +++++- .../lib/normalize-options.ts | 3 ++ .../module-federation-dev-server/schema.d.ts | 1 + .../module-federation-dev-server/schema.json | 5 +++ .../executors/dev-server/dev-server.impl.ts | 6 ++++ .../src/executors/webpack/webpack.impl.ts | 15 ++++++++- .../utils/module-federation/dependencies.ts | 31 +++++++++++++++++-- 10 files changed, 80 insertions(+), 5 deletions(-) diff --git a/docs/generated/packages/angular/executors/module-federation-dev-server.json b/docs/generated/packages/angular/executors/module-federation-dev-server.json index 0500c82b50..fd9fabfe5c 100644 --- a/docs/generated/packages/angular/executors/module-federation-dev-server.json +++ b/docs/generated/packages/angular/executors/module-federation-dev-server.json @@ -135,6 +135,11 @@ "staticRemotesPort": { "type": "number", "description": "The port at which to serve the file-server for the static remotes." + }, + "buildLibsFromSource": { + "type": "boolean", + "description": "Read buildable libraries from source instead of building them separately. If not set, it will take the value specified in the `browserTarget` options, or it will default to `true` if it's also not set in the `browserTarget` options.", + "x-priority": "important" } }, "additionalProperties": false, diff --git a/packages/angular/src/builders/dev-server/dev-server.impl.ts b/packages/angular/src/builders/dev-server/dev-server.impl.ts index 22a9f62d63..8e9f7adada 100644 --- a/packages/angular/src/builders/dev-server/dev-server.impl.ts +++ b/packages/angular/src/builders/dev-server/dev-server.impl.ts @@ -11,6 +11,7 @@ import { parseTargetString, readCachedProjectGraph, type Target, + targetToTargetString, } from '@nx/devkit'; import { getRootTsConfigPath } from '@nx/js'; import type { DependentBuildableProjectNode } from '@nx/js/src/utils/buildable-libs-utils'; @@ -82,6 +83,9 @@ export function executeDevServerBuilder( buildTargetOptions.buildLibsFromSource ?? true; + process.env.NX_BUILD_LIBS_FROM_SOURCE = `${buildLibsFromSource}`; + process.env.NX_BUILD_TARGET = options.buildTarget; + let pathToWebpackConfig: string; if (buildTargetOptions.customWebpackConfig?.path) { pathToWebpackConfig = joinPathFragments( @@ -251,6 +255,7 @@ const executorToBuilderMap = new Map([ ], ['@nx/angular:application', '@angular-devkit/build-angular:application'], ]); + function patchBuilderContext( context: BuilderContext, isUsingEsbuildBuilder: boolean, diff --git a/packages/angular/src/builders/webpack-browser/webpack-browser.impl.ts b/packages/angular/src/builders/webpack-browser/webpack-browser.impl.ts index c570c3e530..35a9325338 100644 --- a/packages/angular/src/builders/webpack-browser/webpack-browser.impl.ts +++ b/packages/angular/src/builders/webpack-browser/webpack-browser.impl.ts @@ -1,8 +1,10 @@ import { joinPathFragments, normalizePath, + parseTargetString, ProjectGraph, readCachedProjectGraph, + targetToTargetString, } from '@nx/devkit'; import type { DependentBuildableProjectNode } from '@nx/js/src/utils/buildable-libs-utils'; import { WebpackNxBuildCoordinationPlugin } from '@nx/webpack/src/plugins/webpack-nx-build-coordination-plugin'; @@ -57,6 +59,9 @@ export function executeWebpackBrowserBuilder( ...delegateBuilderOptions } = options; + process.env.NX_BUILD_LIBS_FROM_SOURCE = `${buildLibsFromSource}`; + process.env.NX_BUILD_TARGET = targetToTargetString({ ...context.target }); + const pathToWebpackConfig = customWebpackConfig?.path && joinPathFragments(context.workspaceRoot, customWebpackConfig.path); diff --git a/packages/angular/src/builders/webpack-server/webpack-server.impl.ts b/packages/angular/src/builders/webpack-server/webpack-server.impl.ts index a3bfd89e93..97b44bb9e8 100644 --- a/packages/angular/src/builders/webpack-server/webpack-server.impl.ts +++ b/packages/angular/src/builders/webpack-server/webpack-server.impl.ts @@ -1,4 +1,8 @@ -import { joinPathFragments, normalizePath } from '@nx/devkit'; +import { + joinPathFragments, + normalizePath, + targetToTargetString, +} from '@nx/devkit'; import { existsSync } from 'fs'; import { relative } from 'path'; import { Observable, from } from 'rxjs'; @@ -96,6 +100,9 @@ export function executeWebpackServerBuilder( options.buildLibsFromSource ??= true; + process.env.NX_BUILD_LIBS_FROM_SOURCE = `${options.buildLibsFromSource}`; + process.env.NX_BUILD_TARGET = targetToTargetString({ ...context.target }); + if (!options.buildLibsFromSource) { const { tsConfigPath } = createTmpTsConfigForBuildableLibs( options.tsConfig, diff --git a/packages/angular/src/executors/module-federation-dev-server/lib/normalize-options.ts b/packages/angular/src/executors/module-federation-dev-server/lib/normalize-options.ts index 7cc9cb1f1e..c942bcc373 100644 --- a/packages/angular/src/executors/module-federation-dev-server/lib/normalize-options.ts +++ b/packages/angular/src/executors/module-federation-dev-server/lib/normalize-options.ts @@ -11,6 +11,9 @@ export function normalizeOptions(schema: Schema): NormalizedSchema { buildTarget ??= (schema as SchemaWithBrowserTarget).browserTarget; delete (schema as SchemaWithBrowserTarget).browserTarget; } + schema.buildLibsFromSource ??= true; + process.env.NX_BUILD_LIBS_FROM_SOURCE = `${schema.buildLibsFromSource}`; + process.env.NX_BUILD_TARGET = `${buildTarget}`; return { ...schema, diff --git a/packages/angular/src/executors/module-federation-dev-server/schema.d.ts b/packages/angular/src/executors/module-federation-dev-server/schema.d.ts index 71e3625e03..d976455d9f 100644 --- a/packages/angular/src/executors/module-federation-dev-server/schema.d.ts +++ b/packages/angular/src/executors/module-federation-dev-server/schema.d.ts @@ -23,6 +23,7 @@ interface BaseSchema { isInitialHost?: boolean; parallel?: number; staticRemotesPort?: number; + buildLibsFromSource?: boolean; } export type SchemaWithBrowserTarget = BaseSchema & { diff --git a/packages/angular/src/executors/module-federation-dev-server/schema.json b/packages/angular/src/executors/module-federation-dev-server/schema.json index cacf9e7589..9b9c99312c 100644 --- a/packages/angular/src/executors/module-federation-dev-server/schema.json +++ b/packages/angular/src/executors/module-federation-dev-server/schema.json @@ -145,6 +145,11 @@ "staticRemotesPort": { "type": "number", "description": "The port at which to serve the file-server for the static remotes." + }, + "buildLibsFromSource": { + "type": "boolean", + "description": "Read buildable libraries from source instead of building them separately. If not set, it will take the value specified in the `browserTarget` options, or it will default to `true` if it's also not set in the `browserTarget` options.", + "x-priority": "important" } }, "additionalProperties": false, diff --git a/packages/webpack/src/executors/dev-server/dev-server.impl.ts b/packages/webpack/src/executors/dev-server/dev-server.impl.ts index 0e33e323bb..4fe775f473 100644 --- a/packages/webpack/src/executors/dev-server/dev-server.impl.ts +++ b/packages/webpack/src/executors/dev-server/dev-server.impl.ts @@ -3,6 +3,7 @@ import { ExecutorContext, parseTargetString, readTargetOptions, + targetToTargetString, } from '@nx/devkit'; import { eachValueFrom } from '@nx/devkit/src/utils/rxjs-for-await'; @@ -38,6 +39,9 @@ export async function* devServerExecutor( sourceRoot ); + process.env.NX_BUILD_LIBS_FROM_SOURCE = `${buildOptions.buildLibsFromSource}`; + process.env.NX_BUILD_TARGET = serveOptions.buildTarget; + // TODO(jack): Figure out a way to port this into NxWebpackPlugin if (!buildOptions.buildLibsFromSource) { if (!buildOptions.tsConfig) { @@ -59,6 +63,8 @@ export async function* devServerExecutor( target.data.root, dependencies ); + + process.env.NX_TSCONFIG_PATH = buildOptions.tsConfig; } let config; diff --git a/packages/webpack/src/executors/webpack/webpack.impl.ts b/packages/webpack/src/executors/webpack/webpack.impl.ts index 9e44337fd8..c6f4ccf405 100644 --- a/packages/webpack/src/executors/webpack/webpack.impl.ts +++ b/packages/webpack/src/executors/webpack/webpack.impl.ts @@ -1,4 +1,9 @@ -import { ExecutorContext, logger, stripIndents } from '@nx/devkit'; +import { + ExecutorContext, + logger, + stripIndents, + targetToTargetString, +} from '@nx/devkit'; import { eachValueFrom } from '@nx/devkit/src/utils/rxjs-for-await'; import type { Configuration, Stats } from 'webpack'; import { from, of } from 'rxjs'; @@ -116,6 +121,13 @@ export async function* webpackExecutor( ? 'production' : 'development'; + process.env.NX_BUILD_LIBS_FROM_SOURCE = `${options.buildLibsFromSource}`; + process.env.NX_BUILD_TARGET = targetToTargetString({ + project: context.projectName, + target: context.targetName, + configuration: context.configurationName, + }); + if (options.compiler === 'swc') { try { require.resolve('swc-loader'); @@ -146,6 +158,7 @@ export async function* webpackExecutor( metadata.root, dependencies ); + process.env.NX_TSCONFIG_PATH = options.tsConfig; } // Delete output path before bundling diff --git a/packages/webpack/src/utils/module-federation/dependencies.ts b/packages/webpack/src/utils/module-federation/dependencies.ts index 6ac108d680..27f0bc3f33 100644 --- a/packages/webpack/src/utils/module-federation/dependencies.ts +++ b/packages/webpack/src/utils/module-federation/dependencies.ts @@ -1,6 +1,11 @@ import type { ProjectGraph } from '@nx/devkit'; import type { WorkspaceLibrary } from './models'; import { readTsPathMappings } from './typescript'; +import { + getOutputsForTargetAndConfiguration, + parseTargetString, +} from '@nx/devkit'; +import { interpolate } from 'nx/src/tasks-runner/utils'; export function getDependentPackagesForProject( projectGraph: ProjectGraph, @@ -57,12 +62,32 @@ function getLibraryImportPath( library: string, projectGraph: ProjectGraph ): string | undefined { + let buildLibsFromSource = true; + if (process.env.NX_BUILD_LIBS_FROM_SOURCE) { + buildLibsFromSource = process.env.NX_BUILD_LIBS_FROM_SOURCE === 'true'; + } + const libraryNode = projectGraph.nodes[library]; + let sourceRoots = [libraryNode.data.sourceRoot]; + + if (!buildLibsFromSource && process.env.NX_BUILD_TARGET) { + const buildTarget = parseTargetString( + process.env.NX_BUILD_TARGET, + projectGraph + ); + sourceRoots = getOutputsForTargetAndConfiguration( + buildTarget, + {}, + libraryNode + ); + } + const tsConfigPathMappings = readTsPathMappings(); - const sourceRoot = projectGraph.nodes[library].data.sourceRoot; for (const [key, value] of Object.entries(tsConfigPathMappings)) { - if (value.find((path) => path.startsWith(sourceRoot))) { - return key; + for (const src of sourceRoots) { + if (value.find((path) => path.startsWith(src))) { + return key; + } } }