Merge pull request #27846 from davidfestal/all-exports-in-exposed-modules
CLI: have module federation settings take in account all the exports defined in the `package.json`
This commit is contained in:
@@ -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,22 @@ 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,
|
||||
moduleFederation: await getModuleFederationOptions(
|
||||
packageJson,
|
||||
resolvePath(targetDir),
|
||||
options.isModuleFederationRemote,
|
||||
),
|
||||
...(await loadCliConfig({
|
||||
args: configPaths,
|
||||
fromPackage: name,
|
||||
fromPackage: packageJson.name,
|
||||
})),
|
||||
rspack,
|
||||
});
|
||||
|
||||
@@ -15,8 +15,10 @@
|
||||
*/
|
||||
|
||||
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';
|
||||
|
||||
interface StartAppOptions {
|
||||
verifyVersions?: boolean;
|
||||
@@ -30,7 +32,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,
|
||||
@@ -39,8 +43,9 @@ export async function startFrontend(options: StartAppOptions) {
|
||||
verifyVersions: options.verifyVersions,
|
||||
skipOpenBrowser: options.skipOpenBrowser,
|
||||
linkedWorkspace: options.linkedWorkspace,
|
||||
moduleFederation: getModuleFederationOptions(
|
||||
name,
|
||||
moduleFederation: await getModuleFederationOptions(
|
||||
packageJson,
|
||||
resolvePath(paths.targetDir),
|
||||
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,11 +16,18 @@
|
||||
|
||||
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(
|
||||
name: string,
|
||||
export async function getModuleFederationOptions(
|
||||
packageJson: BackstagePackageJson,
|
||||
packageDir: string,
|
||||
isModuleFederationRemote?: boolean,
|
||||
): ModuleFederationOptions | undefined {
|
||||
): Promise<ModuleFederationOptions | undefined> {
|
||||
if (
|
||||
!isModuleFederationRemote &&
|
||||
!process.env.EXPERIMENTAL_MODULE_FEDERATION
|
||||
@@ -34,11 +41,43 @@ 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
|
||||
// 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,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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