CLI: take in account package exports in module federation exposed modules

Signed-off-by: David Festal <dfestal@redhat.com>
This commit is contained in:
David Festal
2024-11-26 18:47:48 +01:00
parent 1a03dc6f69
commit 96331fa3b9
6 changed files with 51 additions and 11 deletions
+7
View File
@@ -0,0 +1,7 @@
---
'@backstage/cli': patch
---
Enhance the behavior of the experimental support for module federation in the backstage CLI,
by using the `package.json` exports (when present) to complete the list of exposed modules.
This allows, for example, using exported `alpha` definitions through module federation.
@@ -19,6 +19,7 @@ import { resolve as resolvePath } from 'path';
import { buildBundle, getModuleFederationOptions } from '../../lib/bundler';
import { getEnvironmentParallelism } from '../../lib/parallel';
import { loadCliConfig } from '../../modules/config/lib/config';
import { BackstagePackageJson } from '@backstage/cli-node';
interface BuildAppOptions {
targetDir: string;
@@ -30,20 +31,21 @@ interface BuildAppOptions {
export async function buildFrontend(options: BuildAppOptions) {
const { targetDir, writeStats, configPaths, rspack } = options;
const { name } = await fs.readJson(resolvePath(targetDir, 'package.json'));
const packageJson = (await fs.readJson(
resolvePath(targetDir, 'package.json'),
)) as BackstagePackageJson;
await buildBundle({
targetDir,
entry: 'src/index',
parallelism: getEnvironmentParallelism(),
statsJsonEnabled: writeStats,
moduleFederation: getModuleFederationOptions(
name,
packageJson,
options.isModuleFederationRemote,
),
...(await loadCliConfig({
args: configPaths,
fromPackage: name,
fromPackage: packageJson.name,
})),
rspack,
});
@@ -17,6 +17,7 @@
import { readJson } from 'fs-extra';
import { getModuleFederationOptions, serveBundle } from '../../lib/bundler';
import { paths } from '../../lib/paths';
import { BackstagePackageJson } from '@backstage/cli-node';
interface StartAppOptions {
verifyVersions?: boolean;
@@ -30,7 +31,9 @@ interface StartAppOptions {
}
export async function startFrontend(options: StartAppOptions) {
const { name } = await readJson(paths.resolveTarget('package.json'));
const packageJson = (await readJson(
paths.resolveTarget('package.json'),
)) as BackstagePackageJson;
const waitForExit = await serveBundle({
entry: options.entry,
@@ -40,7 +43,7 @@ export async function startFrontend(options: StartAppOptions) {
skipOpenBrowser: options.skipOpenBrowser,
linkedWorkspace: options.linkedWorkspace,
moduleFederation: getModuleFederationOptions(
name,
packageJson,
options.isModuleFederationRemote,
),
});
+12 -3
View File
@@ -235,13 +235,22 @@ export async function createConfig(
.ModuleFederationPlugin as unknown as typeof ModuleFederationPlugin)
: ModuleFederationPlugin;
const exposes = options.moduleFederation?.exposes
? Object.fromEntries(
Object.entries(options.moduleFederation?.exposes).map(([k, v]) => [
k,
resolvePath(paths.targetPath, v),
]),
)
: {
'.': paths.targetEntry,
};
plugins.push(
new AdaptedModuleFederationPlugin({
...(isRemote && {
filename: 'remoteEntry.js',
exposes: {
'.': paths.targetEntry,
},
exposes,
}),
name: options.moduleFederation.name,
runtime: false,
@@ -16,9 +16,11 @@
import chalk from 'chalk';
import { ModuleFederationOptions } from './types';
import { BackstagePackageJson } from '@backstage/cli-node';
import { readEntryPoints } from '../entryPoints';
export function getModuleFederationOptions(
name: string,
packageJson: BackstagePackageJson,
isModuleFederationRemote?: boolean,
): ModuleFederationOptions | undefined {
if (
@@ -39,6 +41,17 @@ export function getModuleFederationOptions(
// The default output mode requires the name to be a usable as a code
// symbol, there might be better options here but for now we need to
// sanitize the name.
name: name.replaceAll('@', '').replaceAll('/', '__').replaceAll('-', '_'),
name: packageJson.name
.replaceAll('@', '')
.replaceAll('/', '__')
.replaceAll('-', '_'),
exposes:
isModuleFederationRemote && packageJson.exports
? Object.fromEntries(
readEntryPoints(packageJson)
.filter(ep => ep.mount !== './package.json')
.map(ep => [ep.mount, ep.path]),
)
: undefined,
};
}
+6
View File
@@ -23,6 +23,12 @@ export type ModuleFederationOptions = {
name: string;
// Whether this is a host or remote bundle
mode: 'host' | 'remote';
exposes?: {
/**
* Modules that should be exposed by this container.
*/
[k: string]: string;
};
};
export type BundlingOptions = {