From 1191757a14d6382f2d07bfcb47ff2c05b3a929bf Mon Sep 17 00:00:00 2001 From: Steven Prybylynskyi Date: Fri, 13 Dec 2024 13:45:33 +0100 Subject: [PATCH] feat(plugin): support object-based MF2 exposed modules in ModuleFederationTypesPlugin --- src/bin/make-federated-types.ts | 4 ++-- .../__tests__/compileTypesWorker.test.ts | 16 +++++++++++----- src/compileTypes/compileTypes.ts | 2 +- src/plugin.ts | 15 ++++++++++++++- 4 files changed, 28 insertions(+), 9 deletions(-) diff --git a/src/bin/make-federated-types.ts b/src/bin/make-federated-types.ts index 415d9b6..7b7007a 100644 --- a/src/bin/make-federated-types.ts +++ b/src/bin/make-federated-types.ts @@ -46,14 +46,14 @@ if (argv['federation-config']) { .mfPluginOptions as FederationConfig; } -const exposedModules = Object.values(federationConfig.exposes); +const exposedModules = federationConfig.exposes; const outDir = argv['output-types-folder'] || path.join(DEFAULT_DIR_DIST, DEFAULT_DIR_EMITTED_TYPES); const outFile = path.join(outDir, 'index.d.ts'); const dirGlobalTypes = argv['global-types'] || DEFAULT_DIR_GLOBAL_TYPES; const tsconfigPath = argv.tsconfig || TS_CONFIG_FILE; -console.log(`Emitting types for ${exposedModules.length} exposed module(s)`); +console.log(`Emitting types for ${Object.keys(exposedModules).length} exposed module(s)`); setLogger(console); diff --git a/src/compileTypes/__tests__/compileTypesWorker.test.ts b/src/compileTypes/__tests__/compileTypesWorker.test.ts index 142e9d8..d7f2c68 100644 --- a/src/compileTypes/__tests__/compileTypesWorker.test.ts +++ b/src/compileTypes/__tests__/compileTypesWorker.test.ts @@ -59,7 +59,10 @@ describe('compileTypesWorker', () => { test('handles successful compilation and rewrite', () => { const workerMessage: CompileTypesWorkerMessage = { tsconfigPath: 'tsconfig.json', - exposedModules: ['moduleA', 'moduleB'], + exposedModules: { + './moduleA': 'moduleA', + './moduleB': 'moduleB', + }, outFile: 'dist/types.d.ts', dirGlobalTypes: 'src/@types', federationConfig: {} as FederationConfig, @@ -72,7 +75,10 @@ describe('compileTypesWorker', () => { expect(mockCompileTypes).toHaveBeenCalledWith( expect.objectContaining({ tsconfigPath: 'tsconfig.json', - exposedModules: ['moduleA', 'moduleB'], + exposedModules: { + './moduleA': 'moduleA', + './moduleB': 'moduleB', + }, outFile: 'dist/types.d.ts', dirGlobalTypes: 'src/@types', }), @@ -92,7 +98,7 @@ describe('compileTypesWorker', () => { test('handles compilation failure', () => { const workerMessage: CompileTypesWorkerMessage = { tsconfigPath: 'tsconfig.json', - exposedModules: ['moduleA'], + exposedModules: { './moduleA': 'moduleA' }, outFile: 'dist/types.d.ts', dirGlobalTypes: 'src/@types', federationConfig: {} as FederationConfig, @@ -108,7 +114,7 @@ describe('compileTypesWorker', () => { test('handles errors during compilation', () => { const workerMessage: CompileTypesWorkerMessage = { tsconfigPath: 'tsconfig.json', - exposedModules: ['moduleA'], + exposedModules: { './moduleA': 'moduleA' }, outFile: 'dist/types.d.ts', dirGlobalTypes: 'src/@types', federationConfig: {} as FederationConfig, @@ -130,7 +136,7 @@ describe('compileTypesWorker', () => { test('logs performance metrics', () => { const workerMessage: CompileTypesWorkerMessage = { tsconfigPath: 'tsconfig.json', - exposedModules: ['moduleA'], + exposedModules: { './moduleA': 'moduleA' }, outFile: 'dist/types.d.ts', dirGlobalTypes: 'src/@types', federationConfig: {} as FederationConfig, diff --git a/src/compileTypes/compileTypes.ts b/src/compileTypes/compileTypes.ts index cf2fe72..5c18bac 100644 --- a/src/compileTypes/compileTypes.ts +++ b/src/compileTypes/compileTypes.ts @@ -9,7 +9,7 @@ import { getTSConfigCompilerOptions, reportCompileDiagnostic } from './helpers'; export type CompileTypesParams = { tsconfigPath: string; - exposedModules: string[]; + exposedModules: Dict; outFile: string; dirGlobalTypes: string; }; diff --git a/src/plugin.ts b/src/plugin.ts index 4b52003..ed28af3 100644 --- a/src/plugin.ts +++ b/src/plugin.ts @@ -82,6 +82,19 @@ export class ModuleFederationTypesPlugin implements WebpackPluginInstance { return; } + // In MF2 an item can be an object with `import` and `name` properties + federationPluginOptions.exposes = Object.entries(federationPluginOptions.exposes || {}).reduce( + (acc, [key, value]) => { + if (value && typeof value === 'object' && 'import' in value) { + acc[key] = (value as Dict).import[0]; + } else { + acc[key] = value; + } + return acc; + }, + {} as Dict, + ); + // Define path for the emitted typings file const { exposes, remotes } = federationPluginOptions; @@ -100,7 +113,7 @@ export class ModuleFederationTypesPlugin implements WebpackPluginInstance { await compileTypesAsync( { tsconfigPath: TS_CONFIG_FILE, - exposedModules: exposes as string[], + exposedModules: exposes as Dict, outFile, dirGlobalTypes, federationConfig: federationPluginOptions as FederationConfig,