diff --git a/packages/cli/src/commands/build/buildFrontend.ts b/packages/cli/src/commands/build/buildFrontend.ts index ff84f4f15c..ec89008b81 100644 --- a/packages/cli/src/commands/build/buildFrontend.ts +++ b/packages/cli/src/commands/build/buildFrontend.ts @@ -39,8 +39,9 @@ export async function buildFrontend(options: BuildAppOptions) { entry: 'src/index', parallelism: getEnvironmentParallelism(), statsJsonEnabled: writeStats, - moduleFederation: getModuleFederationOptions( + moduleFederation: await getModuleFederationOptions( packageJson, + resolvePath(targetDir), options.isModuleFederationRemote, ), ...(await loadCliConfig({ diff --git a/packages/cli/src/commands/start/startFrontend.ts b/packages/cli/src/commands/start/startFrontend.ts index a06d6eaca0..d47f539527 100644 --- a/packages/cli/src/commands/start/startFrontend.ts +++ b/packages/cli/src/commands/start/startFrontend.ts @@ -15,6 +15,7 @@ */ import { readJson } from 'fs-extra'; +import { resolve as resolvePath } from 'path'; import { getModuleFederationOptions, serveBundle } from '../../lib/bundler'; import { paths } from '../../lib/paths'; import { BackstagePackageJson } from '@backstage/cli-node'; @@ -42,8 +43,9 @@ export async function startFrontend(options: StartAppOptions) { verifyVersions: options.verifyVersions, skipOpenBrowser: options.skipOpenBrowser, linkedWorkspace: options.linkedWorkspace, - moduleFederation: getModuleFederationOptions( + moduleFederation: await getModuleFederationOptions( packageJson, + resolvePath(paths.targetDir), options.isModuleFederationRemote, ), }); diff --git a/packages/cli/src/lib/bundler/moduleFederation.ts b/packages/cli/src/lib/bundler/moduleFederation.ts index 77c7356b74..26d1c4784b 100644 --- a/packages/cli/src/lib/bundler/moduleFederation.ts +++ b/packages/cli/src/lib/bundler/moduleFederation.ts @@ -18,11 +18,16 @@ import chalk from 'chalk'; import { ModuleFederationOptions } from './types'; import { BackstagePackageJson } from '@backstage/cli-node'; import { readEntryPoints } from '../entryPoints'; +import { + createTypeDistProject, + getEntryPointDefaultFeatureType, +} from '../typeDistProject'; -export function getModuleFederationOptions( +export async function getModuleFederationOptions( packageJson: BackstagePackageJson, + packageDir: string, isModuleFederationRemote?: boolean, -): ModuleFederationOptions | undefined { +): Promise { if ( !isModuleFederationRemote && !process.env.EXPERIMENTAL_MODULE_FEDERATION @@ -36,6 +41,34 @@ export function getModuleFederationOptions( ), ); + let exposes: ModuleFederationOptions['exposes']; + const packageRole = packageJson.backstage?.role; + if (isModuleFederationRemote && packageJson.exports && packageRole) { + const project = await createTypeDistProject(); + exposes = Object.fromEntries( + readEntryPoints(packageJson) + .filter(ep => { + if (ep.mount === './package.json') { + return false; + } + if (ep.mount === '.') { + return true; + } + // Include this additional entry point in the exposed modules + // if it exports a feature as default export. + return ( + getEntryPointDefaultFeatureType( + packageRole, + packageDir, + project, + ep.path, + ) !== null + ); + }) + .map(ep => [ep.mount, ep.path]), + ); + } + return { mode: isModuleFederationRemote ? 'remote' : 'host', // The default output mode requires the name to be a usable as a code @@ -45,13 +78,6 @@ export function getModuleFederationOptions( .replaceAll('@', '') .replaceAll('/', '__') .replaceAll('-', '_'), - exposes: - isModuleFederationRemote && packageJson.exports - ? Object.fromEntries( - readEntryPoints(packageJson) - .filter(ep => ep.mount !== './package.json') - .map(ep => [ep.mount, ep.path]), - ) - : undefined, + exposes, }; }