Skip to content

fix(module-federation): re-add support for mf aliases #31347

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,7 @@ The scope must be one of the following:
- express - anything Express specific
- js - anything related to @nx/js package or general js/ts support
- linter - anything Linter specific
- module-federation - anything Nx Module Federation specific
- nest - anything Nest specific
- nextjs - anything Next specific
- node - anything Node specific
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { Tree } from '@nx/devkit';
import type { NormalizedOptions } from '../schema';
import { joinPathFragments, readProjectConfiguration } from '@nx/devkit';
import { addTsConfigPath } from '@nx/js';
import { normalizeProjectName } from '@nx/module-federation';

export function setupTspathForRemote(tree: Tree, options: NormalizedOptions) {
const project = readProjectConfiguration(tree, options.appName);
Expand All @@ -12,7 +13,7 @@ export function setupTspathForRemote(tree: Tree, options: NormalizedOptions) {

const exportName = options.standalone ? 'Routes' : 'Module';

addTsConfigPath(tree, `${options.appName.replace(/-/g, '_')}/${exportName}`, [
addTsConfigPath(tree, `${normalizeProjectName(options.appName)}/${exportName}`, [
joinPathFragments(project.root, exportPath),
]);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
getBuildTargetNameFromMFDevServer,
getModuleFederationConfig,
getRemotes,
normalizeProjectName,
parseStaticRemotesConfig,
parseStaticSsrRemotesConfig,
startRemoteProxies,
Expand Down Expand Up @@ -65,8 +66,8 @@ export async function startRemoteIterators(
remotes.devRemotes.map((r) =>
typeof r === 'string' ? r : r.remoteName
) ?? []
).map((r) => r.replace(/-/g, '_')),
project.name.replace(/-/g, '_'),
).map((r) => normalizeProjectName(r)),
normalizeProjectName(project.name),
]);

const staticRemotesConfig = isServer
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
NxModuleFederationConfigOverride,
} from '../../../utils/models';
import { getModuleFederationConfigSync } from '../../../with-module-federation/angular/utils';
import { normalizeProjectName } from '../../../utils';

export class NxModuleFederationPlugin implements RspackPluginInstance {
constructor(
Expand Down Expand Up @@ -60,7 +61,7 @@ export class NxModuleFederationPlugin implements RspackPluginInstance {
}

new (require('@module-federation/enhanced/rspack').ModuleFederationPlugin)({
name: this._options.config.name.replace(/-/g, '_'),
name: normalizeProjectName(this._options.config.name),
filename: 'remoteEntry.js',
exposes: this._options.config.exposes,
remotes: mappedRemotes,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
NxModuleFederationConfigOverride,
} from '../../../utils/models';
import { getModuleFederationConfig } from '../../../with-module-federation/rspack/utils';
import { normalizeProjectName } from '../../../utils';

export class NxModuleFederationPlugin implements RspackPluginInstance {
constructor(
Expand Down Expand Up @@ -53,7 +54,7 @@ export class NxModuleFederationPlugin implements RspackPluginInstance {
}

new (require('@module-federation/enhanced/rspack').ModuleFederationPlugin)({
name: this._options.config.name.replace(/-/g, '_'),
name: normalizeProjectName(this._options.config.name),
filename: 'remoteEntry.js',
exposes: this._options.config.exposes,
remotes: mappedRemotes,
Expand Down
1 change: 1 addition & 0 deletions packages/module-federation/src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export * from './dependencies';
export * from './package-json';
export * from './remotes';
export * from './models';
export * from './normalize-project-name';
export * from './get-remotes-for-host';
export * from './parse-static-remotes-config';
export * from './start-remote-proxies';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// normalize to allow only JavaScript var valid names
export function normalizeProjectName(name: string) {
// Replace invalid starting characters with '_'
const normalized = name.replace(/^[^a-zA-Z_$]/, '_');
// Replace invalid subsequent characters with '_'
return normalized.replace(/[^a-zA-Z0-9_$]/g, '_');
}
3 changes: 3 additions & 0 deletions packages/module-federation/src/utils/public-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import {
shareWorkspaceLibraries,
} from './share';

import { normalizeProjectName } from './normalize-project-name';

import { mapRemotes, mapRemotesForSSR } from './remotes';

import { getDependentPackagesForProject } from './dependencies';
Expand All @@ -43,6 +45,7 @@ export {
sharePackages,
mapRemotes,
mapRemotesForSSR,
normalizeProjectName,
getDependentPackagesForProject,
readRootPackageJson,
};
30 changes: 30 additions & 0 deletions packages/module-federation/src/utils/remotes.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,34 @@ describe('mapRemotes', () => {
remote3: 'remote3@http://localhost:4203/mf-manifest.json',
});
});

it('should map string remotes using aliases for scoped names', () => {
expect(
mapRemotes(
['@nx-mf/remote'],
'js',
(remote) => {
return `http://localhost:3001/remoteEntry.js`;
},
true
)
).toEqual({
'@nx-mf/remote': '_nx_mf_remote@http://localhost:3001/remoteEntry.js',
});
});

it('should map array remotes using aliases for scoped names', () => {
expect(
mapRemotes(
[
['@nx-mf/remote', 'http://localhost:4201/remoteEntry.js'],
],
'js',
(remote) => remote,
true
)
).toEqual({
'@nx-mf/remote': '_nx_mf_remote@http://localhost:4201/remoteEntry.js',
});
});
});
21 changes: 8 additions & 13 deletions packages/module-federation/src/utils/remotes.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Remotes } from './models';
import { extname } from 'path';
import { normalizeProjectName } from './normalize-project-name';

/**
* Map remote names to a format that can be understood and used by Module
Expand All @@ -19,17 +20,15 @@ export function mapRemotes(

for (const nxRemoteProjectName of remotes) {
if (Array.isArray(nxRemoteProjectName)) {
const mfRemoteName = normalizeRemoteName(nxRemoteProjectName[0]);
const mfRemoteName = nxRemoteProjectName[0];
mappedRemotes[mfRemoteName] = handleArrayRemote(
nxRemoteProjectName,
remoteEntryExt,
isRemoteGlobal
);
} else if (typeof nxRemoteProjectName === 'string') {
const mfRemoteName = normalizeRemoteName(nxRemoteProjectName);
mappedRemotes[mfRemoteName] = handleStringRemote(
mappedRemotes[nxRemoteProjectName] = handleStringRemote(
nxRemoteProjectName,

determineRemoteUrl,
isRemoteGlobal
);
Expand All @@ -46,7 +45,7 @@ function handleArrayRemote(
isRemoteGlobal: boolean
): string {
const [nxRemoteProjectName, remoteLocation] = remote;
const mfRemoteName = normalizeRemoteName(nxRemoteProjectName);
const mfRemoteName = normalizeProjectName(nxRemoteProjectName);

// Remote string starts like "promise new Promise(...)" – return as-is
if (remoteLocation.startsWith('promise new Promise')) {
Expand Down Expand Up @@ -75,7 +74,7 @@ function handleStringRemote(
isRemoteGlobal: boolean
): string {
const globalPrefix = isRemoteGlobal
? `${normalizeRemoteName(nxRemoteProjectName)}@`
? `${normalizeProjectName(nxRemoteProjectName)}@`
: '';

return `${globalPrefix}${determineRemoteUrl(nxRemoteProjectName)}`;
Expand All @@ -99,7 +98,7 @@ export function mapRemotesForSSR(
for (const remote of remotes) {
if (Array.isArray(remote)) {
let [nxRemoteProjectName, remoteLocation] = remote;
const mfRemoteName = normalizeRemoteName(nxRemoteProjectName);
const mfRemoteName = normalizeProjectName(nxRemoteProjectName);

const resolvedUrl = new URL(remoteLocation);
const remoteLocationExt = extname(resolvedUrl.pathname);
Expand All @@ -115,16 +114,12 @@ export function mapRemotesForSSR(
const finalRemoteUrl = resolvedUrl.href;
mappedRemotes[mfRemoteName] = `${mfRemoteName}@${finalRemoteUrl}`;
} else if (typeof remote === 'string') {
const mfRemoteName = normalizeRemoteName(remote);
mappedRemotes[mfRemoteName] = `${mfRemoteName}@${determineRemoteUrl(
const mfRemoteName = normalizeProjectName(remote);
mappedRemotes[remote] = `${mfRemoteName}@${determineRemoteUrl(
remote
)}`;
}
}

return mappedRemotes;
}

function normalizeRemoteName(remote: string) {
return remote.replace(/-/g, '_');
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type {
ModuleFederationConfig,
NxModuleFederationConfigOverride,
import {
normalizeProjectName,
type ModuleFederationConfig,
type NxModuleFederationConfigOverride,
} from '../../utils';
import { getModuleFederationConfig } from './utils';

Expand Down Expand Up @@ -43,7 +44,7 @@ export async function withModuleFederationForSSR(
...(config.plugins ?? []),
new (require('@module-federation/enhanced').ModuleFederationPlugin)(
{
name: options.name.replace(/-/g, '_'),
name: normalizeProjectName(this._options.config.name),
filename: 'remoteEntry.js',
exposes: options.exposes,
remotes: mappedRemotes,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type {
ModuleFederationConfig,
NxModuleFederationConfigOverride,
import {
normalizeProjectName,
type ModuleFederationConfig,
type NxModuleFederationConfigOverride,
} from '../../utils';
import { getModuleFederationConfig } from './utils';
import { ModuleFederationPlugin } from '@module-federation/enhanced/webpack';
Expand Down Expand Up @@ -45,7 +46,7 @@ export async function withModuleFederation(
plugins: [
...(config.plugins ?? []),
new ModuleFederationPlugin({
name: options.name.replace(/-/g, '_'),
name: normalizeProjectName(this._options.config.name),
filename: 'remoteEntry.mjs',
exposes: options.exposes,
remotes: mappedRemotes,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { DefinePlugin } from '@rspack/core';
import {
ModuleFederationConfig,
normalizeProjectName,
NxModuleFederationConfigOverride,
} from '../../utils';
import { getModuleFederationConfig } from './utils';
Expand Down Expand Up @@ -36,7 +37,7 @@ export async function withModuleFederationForSSR(
// eslint-disable-next-line @typescript-eslint/no-var-requires
new (require('@module-federation/enhanced/rspack').ModuleFederationPlugin)(
{
name: options.name.replace(/-/g, '_'),
name: normalizeProjectName(options.name),
filename: 'remoteEntry.js',
exposes: options.exposes,
remotes: mappedRemotes,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { Configuration } from '@rspack/core';
import { DefinePlugin } from '@rspack/core';
import {
ModuleFederationConfig,
normalizeProjectName,
NxModuleFederationConfigOverride,
} from '../../utils';
import { getModuleFederationConfig } from './utils';
Expand Down Expand Up @@ -57,7 +58,7 @@ export async function withModuleFederation(

config.plugins.push(
new ModuleFederationPlugin({
name: options.name.replace(/-/g, '_'),
name: normalizeProjectName(options.name),
filename: 'remoteEntry.js',
exposes: options.exposes,
remotes: mappedRemotes,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
ModuleFederationConfig,
normalizeProjectName,
NxModuleFederationConfigOverride,
} from '../../utils';
import { getModuleFederationConfig } from './utils';
Expand Down Expand Up @@ -32,7 +33,7 @@ export async function withModuleFederationForSSR(
config.plugins.push(
new (require('@module-federation/enhanced').ModuleFederationPlugin)(
{
name: options.name.replace(/-/g, '_'),
name: normalizeProjectName(options.name),
filename: 'remoteEntry.js',
exposes: options.exposes,
remotes: mappedRemotes,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
ModuleFederationConfig,
normalizeProjectName,
NxModuleFederationConfigOverride,
} from '../../utils';
import { getModuleFederationConfig } from './utils';
Expand Down Expand Up @@ -43,7 +44,7 @@ export async function withModuleFederation(

config.plugins.push(
new ModuleFederationPlugin({
name: options.name.replace(/-/g, '_'),
name: normalizeProjectName(options.name),
filename: 'remoteEntry.js',
exposes: options.exposes,
remotes: mappedRemotes,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { joinPathFragments, readProjectConfiguration } from '@nx/devkit';
import { addTsConfigPath } from '@nx/js';
import { maybeJs } from '../../../utils/maybe-js';
import { NormalizedSchema } from '../../application/schema';
import { normalizeProjectName } from '@nx/module-federation';

export function setupTspathForRemote(tree: Tree, options: NormalizedSchema) {
const project = readProjectConfiguration(tree, options.projectName);
Expand All @@ -13,7 +14,7 @@ export function setupTspathForRemote(tree: Tree, options: NormalizedSchema) {

addTsConfigPath(
tree,
`${options.projectName.replace(/-/g, '_')}/${exportName}`,
`${normalizeProjectName(options.projectName)}/${exportName}`,
[joinPathFragments(project.root, exportPath)]
);
}