From fe807ed5ae22153a9af4cc0df44a610be69eb777 Mon Sep 17 00:00:00 2001 From: Colum Ferry Date: Tue, 25 Feb 2025 11:56:27 +0000 Subject: [PATCH] fix(module-federation): handle parsing static remote config correctly --- .../utils/parse-static-remotes-config.spec.ts | 299 ++++++++++++++++++ .../src/utils/parse-static-remotes-config.ts | 21 +- 2 files changed, 312 insertions(+), 8 deletions(-) create mode 100644 packages/module-federation/src/utils/parse-static-remotes-config.spec.ts diff --git a/packages/module-federation/src/utils/parse-static-remotes-config.spec.ts b/packages/module-federation/src/utils/parse-static-remotes-config.spec.ts new file mode 100644 index 0000000000000..0e041e1eb6061 --- /dev/null +++ b/packages/module-federation/src/utils/parse-static-remotes-config.spec.ts @@ -0,0 +1,299 @@ +import { + parseStaticRemotesConfig, + parseStaticSsrRemotesConfig, +} from './parse-static-remotes-config'; + +describe('parseStaticRemotesConfig', () => { + it('should parse static remotes config', () => { + const staticRemotes = ['remote1', 'remote2']; + const context = { + projectGraph: { + nodes: { + remote1: { + data: { + targets: { + build: { + options: { + outputPath: 'dist/remote1', + }, + }, + serve: { + options: { + port: 4200, + }, + }, + }, + }, + }, + remote2: { + data: { + targets: { + build: { + options: { + outputPath: 'dist/remote2', + }, + }, + serve: { + options: { + port: 4201, + }, + }, + }, + }, + }, + }, + }, + }; + expect(parseStaticRemotesConfig(staticRemotes, context as any)).toEqual({ + remotes: ['remote1', 'remote2'], + config: { + remote1: { + basePath: 'dist', + outputPath: 'dist/remote1', + urlSegment: 'remote1', + port: 4200, + }, + remote2: { + basePath: 'dist', + outputPath: 'dist/remote2', + urlSegment: 'remote2', + port: 4201, + }, + }, + }); + }); + it('should parse static remotes config when dist in project root', () => { + const staticRemotes = ['remote1', 'remote2']; + const context = { + projectGraph: { + nodes: { + remote1: { + data: { + targets: { + build: { + options: { + outputPath: 'apps/remote1/dist', + }, + }, + serve: { + options: { + port: 4200, + }, + }, + }, + }, + }, + remote2: { + data: { + targets: { + build: { + options: { + outputPath: 'apps/remote2/dist', + }, + }, + serve: { + options: { + port: 4201, + }, + }, + }, + }, + }, + }, + }, + }; + expect(parseStaticRemotesConfig(staticRemotes, context as any)).toEqual({ + remotes: ['remote1', 'remote2'], + config: { + remote1: { + basePath: 'apps/remote1', + outputPath: 'apps/remote1/dist', + urlSegment: 'remote1', + port: 4200, + }, + remote2: { + basePath: 'apps/remote2', + outputPath: 'apps/remote2/dist', + urlSegment: 'remote2', + port: 4201, + }, + }, + }); + }); + it('should parse static remotes config when dist is root and different name', () => { + const staticRemotes = ['remote1', 'remote2']; + const context = { + projectGraph: { + nodes: { + remote1: { + data: { + targets: { + build: { + options: { + outputPath: 'build', + }, + }, + serve: { + options: { + port: 4200, + }, + }, + }, + }, + }, + remote2: { + data: { + targets: { + build: { + options: { + outputPath: 'dist', + }, + }, + serve: { + options: { + port: 4201, + }, + }, + }, + }, + }, + }, + }, + }; + expect(parseStaticRemotesConfig(staticRemotes, context as any)).toEqual({ + remotes: ['remote1', 'remote2'], + config: { + remote1: { + basePath: 'build', + outputPath: 'build', + urlSegment: 'remote1', + port: 4200, + }, + remote2: { + basePath: 'dist', + outputPath: 'dist', + urlSegment: 'remote2', + port: 4201, + }, + }, + }); + }); + + it('should parse ssr static remotes config', () => { + const staticRemotes = ['remote1', 'remote2']; + const context = { + projectGraph: { + nodes: { + remote1: { + data: { + targets: { + build: { + options: { + outputPath: 'dist/remote1/browser', + }, + }, + serve: { + options: { + port: 4200, + }, + }, + }, + }, + }, + remote2: { + data: { + targets: { + build: { + options: { + outputPath: 'dist/remote2/browser', + }, + }, + serve: { + options: { + port: 4201, + }, + }, + }, + }, + }, + }, + }, + }; + expect(parseStaticSsrRemotesConfig(staticRemotes, context as any)).toEqual({ + remotes: ['remote1', 'remote2'], + config: { + remote1: { + basePath: 'dist', + outputPath: 'dist/remote1', + urlSegment: 'remote1', + port: 4200, + }, + remote2: { + basePath: 'dist', + outputPath: 'dist/remote2', + urlSegment: 'remote2', + port: 4201, + }, + }, + }); + }); + + it('should parse ssr static remotes config when dist in project root', () => { + const staticRemotes = ['remote1', 'remote2']; + const context = { + projectGraph: { + nodes: { + remote1: { + data: { + targets: { + build: { + options: { + outputPath: 'apps/remote1/dist/browser', + }, + }, + serve: { + options: { + port: 4200, + }, + }, + }, + }, + }, + remote2: { + data: { + targets: { + build: { + options: { + outputPath: 'apps/remote2/dist/browser', + }, + }, + serve: { + options: { + port: 4201, + }, + }, + }, + }, + }, + }, + }, + }; + expect(parseStaticSsrRemotesConfig(staticRemotes, context as any)).toEqual({ + remotes: ['remote1', 'remote2'], + config: { + remote1: { + basePath: 'apps/remote1', + outputPath: 'apps/remote1/dist', + urlSegment: 'remote1', + port: 4200, + }, + remote2: { + basePath: 'apps/remote2', + outputPath: 'apps/remote2/dist', + urlSegment: 'remote2', + port: 4201, + }, + }, + }); + }); +}); diff --git a/packages/module-federation/src/utils/parse-static-remotes-config.ts b/packages/module-federation/src/utils/parse-static-remotes-config.ts index ef918839d18e0..0236eec76ca34 100644 --- a/packages/module-federation/src/utils/parse-static-remotes-config.ts +++ b/packages/module-federation/src/utils/parse-static-remotes-config.ts @@ -23,9 +23,11 @@ export function parseStaticRemotesConfig( const config: Record = {}; for (const app of staticRemotes) { const outputPath = - context.projectGraph.nodes[app].data.targets['build'].options.outputPath; - const basePath = dirname(outputPath); - const urlSegment = basename(outputPath); + context.projectGraph.nodes[app].data.targets['build'].options.outputPath; // dist || dist/checkout + const basePath = ['', '/', '.'].some((p) => dirname(outputPath) === p) + ? outputPath + : dirname(outputPath); // dist || dist/checkout -> dist + const urlSegment = app; const port = context.projectGraph.nodes[app].data.targets['serve'].options.port; config[app] = { basePath, outputPath, urlSegment, port }; @@ -43,11 +45,14 @@ export function parseStaticSsrRemotesConfig( } const config: Record = {}; for (const app of staticRemotes) { - const outputPath = dirname( - context.projectGraph.nodes[app].data.targets['build'].options.outputPath // dist/checkout/browser -> checkout - ) as string; - const basePath = dirname(outputPath); // dist/checkout -> dist - const urlSegment = basename(outputPath); // dist/checkout -> checkout + let outputPath = context.projectGraph.nodes[app].data.targets['build'] + .options.outputPath as string; + outputPath = dirname(outputPath); // dist/browser => dist || dist/checkout/browser -> checkout + + const basePath = ['', '/', '.'].some((p) => dirname(outputPath) === p) + ? outputPath + : dirname(outputPath); // dist || dist/checkout -> dist + const urlSegment = app; const port = context.projectGraph.nodes[app].data.targets['serve'].options.port; config[app] = { basePath, outputPath, urlSegment, port };