CLI: take in account package exports in module federation exposed modules
Signed-off-by: David Festal <dfestal@redhat.com>
This commit is contained in:
@@ -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,
|
||||
),
|
||||
});
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
Reference in New Issue
Block a user