diff --git a/packages/angular/src/generators/federate-module/federate-module.spec.ts b/packages/angular/src/generators/federate-module/federate-module.spec.ts index 7797000d39884..581d4673cf5da 100644 --- a/packages/angular/src/generators/federate-module/federate-module.spec.ts +++ b/packages/angular/src/generators/federate-module/federate-module.spec.ts @@ -12,9 +12,9 @@ import { E2eTestRunner, UnitTestRunner } from '../../utils/test-runners'; describe('federate-module', () => { let schema: Schema = { name: 'my-federated-module', - remote: 'my-remote', - path: 'apps/my-remote/src/my-federated-module.ts', - remoteDirectory: 'apps/my-remote', + remote: 'myremote', + path: 'apps/myremote/src/my-federated-module.ts', + remoteDirectory: 'apps/myremote', }; describe('no remote', () => { @@ -29,32 +29,32 @@ describe('federate-module', () => { const projects = getProjects(tree); - expect(projects.get('my-remote').root).toEqual('apps/my-remote'); + expect(projects.get('myremote').root).toEqual('apps/myremote'); - expect(tree.exists('apps/my-remote/module-federation.config.ts')).toBe( + expect(tree.exists('apps/myremote/module-federation.config.ts')).toBe( true ); const content = tree.read( - 'apps/my-remote/module-federation.config.ts', + 'apps/myremote/module-federation.config.ts', 'utf-8' ); expect(content).toContain( - `'./my-federated-module': 'apps/my-remote/src/my-federated-module.ts'` + `'./my-federated-module': 'apps/myremote/src/my-federated-module.ts'` ); const tsconfig = JSON.parse(tree.read('tsconfig.base.json', 'utf-8')); expect( - tsconfig.compilerOptions.paths['my-remote/my-federated-module'] - ).toEqual(['apps/my-remote/src/my-federated-module.ts']); + tsconfig.compilerOptions.paths['myremote/my-federated-module'] + ).toEqual(['apps/myremote/src/my-federated-module.ts']); }); }); describe('with remote', () => { const tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' }); let remoteSchema: remoteSchma = { - name: 'my-remote', - directory: 'my-remote', + name: 'myremote', + directory: 'myremote', e2eTestRunner: E2eTestRunner.Cypress, skipFormat: true, linter: Linter.EsLint, @@ -78,7 +78,7 @@ describe('federate-module', () => { ); expect(content).not.toContain( - `'./my-federated-module': 'apps/my-remote/src/my-federated-module.ts'` + `'./my-federated-module': 'apps/myremote/src/my-federated-module.ts'` ); await federateModuleGenerator(tree, { @@ -92,7 +92,7 @@ describe('federate-module', () => { 'utf-8' ); expect(content).toContain( - `'./my-federated-module': 'apps/my-remote/src/my-federated-module.ts'` + `'./my-federated-module': 'apps/myremote/src/my-federated-module.ts'` ); const tsconfig = JSON.parse(tree.read('tsconfig.base.json', 'utf-8')); @@ -100,7 +100,7 @@ describe('federate-module', () => { tsconfig.compilerOptions.paths[ `${remoteSchema.name}/my-federated-module` ] - ).toEqual(['apps/my-remote/src/my-federated-module.ts']); + ).toEqual(['apps/myremote/src/my-federated-module.ts']); }); }); }); diff --git a/packages/angular/src/generators/remote/remote.spec.ts b/packages/angular/src/generators/remote/remote.spec.ts index 1c2458d0b0fa4..5a073f79e0f9e 100644 --- a/packages/angular/src/generators/remote/remote.spec.ts +++ b/packages/angular/src/generators/remote/remote.spec.ts @@ -443,4 +443,19 @@ describe('MF Remote App Generator', () => { const packageJson = readJson(tree, 'package.json'); expect(packageJson).toEqual(initialPackageJson); }); + + it('should error when an invalid remote name is passed to the remote generator', async () => { + const tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' }); + + await expect( + generateTestRemoteApplication(tree, { + directory: 'test/my-remote', + }) + ).rejects.toMatchInlineSnapshot(` + [Error: Invalid remote name: my-remote. Remote project names must: + - Start with a letter, dollar sign ($) or underscore (_) + - Followed by any valid character (letters, digits, underscores, or dollar signs) + The regular expression used is ^[a-zA-Z_$][a-zA-Z_$0-9]*$.] + `); + }); }); diff --git a/packages/angular/src/generators/remote/remote.ts b/packages/angular/src/generators/remote/remote.ts index f8c8f4197275c..723f4b4143e0f 100644 --- a/packages/angular/src/generators/remote/remote.ts +++ b/packages/angular/src/generators/remote/remote.ts @@ -3,6 +3,7 @@ import { formatFiles, getProjects, runTasksInSerial, + stripIndents, Tree, } from '@nx/devkit'; import { @@ -39,6 +40,16 @@ export async function remote(tree: Tree, schema: Schema) { directory: options.directory, }); + const REMOTE_NAME_REGEX = '^[a-zA-Z_$][a-zA-Z_$0-9]*$'; + const remoteNameRegex = new RegExp(REMOTE_NAME_REGEX); + if (!remoteNameRegex.test(remoteProjectName)) { + throw new Error( + stripIndents`Invalid remote name: ${remoteProjectName}. Remote project names must: + - Start with a letter, dollar sign ($) or underscore (_) + - Followed by any valid character (letters, digits, underscores, or dollar signs) + The regular expression used is ${REMOTE_NAME_REGEX}.` + ); + } const port = options.port ?? findNextAvailablePort(tree); const appInstallTask = await applicationGenerator(tree, { diff --git a/packages/react/src/generators/federate-module/federate-module.spec.ts b/packages/react/src/generators/federate-module/federate-module.spec.ts index 1f784206cb430..cf42d76f65f9c 100644 --- a/packages/react/src/generators/federate-module/federate-module.spec.ts +++ b/packages/react/src/generators/federate-module/federate-module.spec.ts @@ -12,9 +12,9 @@ describe('federate-module', () => { let tree: Tree; let schema: Schema = { name: 'my-federated-module', - remote: 'my-remote', - remoteDirectory: 'my-remote', - path: 'my-remote/src/my-federated-module.ts', + remote: 'myremote', + remoteDirectory: 'myremote', + path: 'myremote/src/my-federated-module.ts', style: 'css', skipFormat: true, bundler: 'webpack', @@ -33,7 +33,7 @@ describe('federate-module', () => { beforeAll(() => { tree = createTreeWithEmptyWorkspace(); - tree.write('my-remote/src/my-federated-module.ts', ''); // Ensure that the file exists + tree.write('myremote/src/my-federated-module.ts', ''); // Ensure that the file exists }); describe('no remote', () => { it('should generate a remote and e2e', async () => { @@ -41,27 +41,27 @@ describe('federate-module', () => { const projects = getProjects(tree); - expect(projects.get('my-remote').root).toEqual('my-remote'); - expect(projects.get('my-remote-e2e').root).toEqual('my-remote-e2e'); + expect(projects.get('myremote').root).toEqual('myremote'); + expect(projects.get('myremote-e2e').root).toEqual('myremote-e2e'); }); it('should contain an entry for the new path for module federation', async () => { await federateModuleGenerator(tree, schema); - expect(tree.exists('my-remote/module-federation.config.ts')).toBe(true); + expect(tree.exists('myremote/module-federation.config.ts')).toBe(true); const content = tree.read( - 'my-remote/module-federation.config.ts', + 'myremote/module-federation.config.ts', 'utf-8' ); expect(content).toContain( - `'./my-federated-module': 'my-remote/src/my-federated-module.ts'` + `'./my-federated-module': 'myremote/src/my-federated-module.ts'` ); const tsconfig = JSON.parse(tree.read('tsconfig.base.json', 'utf-8')); expect( - tsconfig.compilerOptions.paths['my-remote/my-federated-module'] - ).toEqual(['my-remote/src/my-federated-module.ts']); + tsconfig.compilerOptions.paths['myremote/my-federated-module'] + ).toEqual(['myremote/src/my-federated-module.ts']); }); it('should error when invalid path is provided', async () => { @@ -99,7 +99,7 @@ describe('federate-module', () => { ); expect(content).not.toContain( - `'./my-federated-module': 'my-remote/src/my-federated-module.ts'` + `'./my-federated-module': 'myremote/src/my-federated-module.ts'` ); await federateModuleGenerator(tree, { @@ -112,13 +112,13 @@ describe('federate-module', () => { 'utf-8' ); expect(content).toContain( - `'./my-federated-module': 'my-remote/src/my-federated-module.ts'` + `'./my-federated-module': 'myremote/src/my-federated-module.ts'` ); const tsconfig = JSON.parse(tree.read('tsconfig.base.json', 'utf-8')); expect( tsconfig.compilerOptions.paths[`${schema.remote}/my-federated-module`] - ).toEqual(['my-remote/src/my-federated-module.ts']); + ).toEqual(['myremote/src/my-federated-module.ts']); }); }); }); diff --git a/packages/react/src/generators/remote/__snapshots__/remote.rspack.spec.ts.snap b/packages/react/src/generators/remote/__snapshots__/remote.rspack.spec.ts.snap new file mode 100644 index 0000000000000..31c7933533f6d --- /dev/null +++ b/packages/react/src/generators/remote/__snapshots__/remote.rspack.spec.ts.snap @@ -0,0 +1,179 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`remote generator bundler=rspack should create the remote with the correct config files 1`] = ` +"const { composePlugins, withNx, withReact } = require('@nx/rspack'); +const { withModuleFederation } = require('@nx/rspack/module-federation'); + +const baseConfig = require('./module-federation.config'); + +const config = { + ...baseConfig, +}; + +// Nx plugins for rspack to build config object from Nx options and context. +/** + * DTS Plugin is disabled in Nx Workspaces as Nx already provides Typing support Module Federation + * The DTS Plugin can be enabled by setting dts: true + * Learn more about the DTS Plugin here: https://module-federation.io/configure/dts.html + */ +module.exports = composePlugins(withNx(), withReact(), withModuleFederation(config, { dts: false })); +" +`; + +exports[`remote generator bundler=rspack should create the remote with the correct config files 2`] = `"module.exports = require('./rspack.config');"`; + +exports[`remote generator bundler=rspack should create the remote with the correct config files 3`] = ` +"module.exports = { + name: 'test', + + exposes: { + './Module': './src/remote-entry.ts', + }, +}; +" +`; + +exports[`remote generator bundler=rspack should create the remote with the correct config files when --js=true 1`] = ` +"const { composePlugins, withNx, withReact } = require('@nx/rspack'); +const { withModuleFederation } = require('@nx/rspack/module-federation'); + +const baseConfig = require('./module-federation.config'); + +const config = { + ...baseConfig, +}; + +// Nx plugins for rspack to build config object from Nx options and context. +/** + * DTS Plugin is disabled in Nx Workspaces as Nx already provides Typing support Module Federation + * The DTS Plugin can be enabled by setting dts: true + * Learn more about the DTS Plugin here: https://module-federation.io/configure/dts.html + */ +module.exports = composePlugins(withNx(), withReact(), withModuleFederation(config, { dts: false })); +" +`; + +exports[`remote generator bundler=rspack should create the remote with the correct config files when --js=true 2`] = `"module.exports = require('./rspack.config');"`; + +exports[`remote generator bundler=rspack should create the remote with the correct config files when --js=true 3`] = ` +"module.exports = { + name: 'test', + + exposes: { + './Module': './src/remote-entry.js', + }, +}; +" +`; + +exports[`remote generator bundler=rspack should create the remote with the correct config files when --typescriptConfiguration=true 1`] = ` +"import { composePlugins, withNx, withReact } from '@nx/rspack'; +import { withModuleFederation } from '@nx/rspack/module-federation'; + +import baseConfig from './module-federation.config'; + +const config = { + ...baseConfig, +}; + +// Nx plugins for rspack to build config object from Nx options and context. +/** + * DTS Plugin is disabled in Nx Workspaces as Nx already provides Typing support Module Federation + * The DTS Plugin can be enabled by setting dts: true + * Learn more about the DTS Plugin here: https://module-federation.io/configure/dts.html + */ +export default composePlugins( + withNx(), + withReact(), + withModuleFederation(config, { dts: false }) +); +" +`; + +exports[`remote generator bundler=rspack should create the remote with the correct config files when --typescriptConfiguration=true 2`] = ` +"export default require('./rspack.config'); +" +`; + +exports[`remote generator bundler=rspack should create the remote with the correct config files when --typescriptConfiguration=true 3`] = ` +"import { ModuleFederationConfig } from '@nx/rspack/module-federation'; + +const config: ModuleFederationConfig = { + name: 'test', + + exposes: { + './Module': './src/remote-entry.ts', + }, +}; + +export default config; +" +`; + +exports[`remote generator bundler=rspack should generate correct remote with config files when using --ssr 1`] = ` +"const {composePlugins, withNx, withReact} = require('@nx/rspack'); +const {withModuleFederationForSSR} = require('@nx/rspack/module-federation'); + +const baseConfig = require("./module-federation.server.config"); + +const defaultConfig = { + ...baseConfig, +}; + +// Nx plugins for rspack to build config object from Nx options and context. +/** + * DTS Plugin is disabled in Nx Workspaces as Nx already provides Typing support Module Federation + * The DTS Plugin can be enabled by setting dts: true + * Learn more about the DTS Plugin here: https://module-federation.io/configure/dts.html + */ +module.exports = composePlugins(withNx(), withReact({ssr: true}), withModuleFederationForSSR(defaultConfig, { dts: false })); +" +`; + +exports[`remote generator bundler=rspack should generate correct remote with config files when using --ssr 2`] = ` +"module.exports = { + name: 'test', + exposes: { + './Module': './src/remote-entry.ts', + }, +}; +" +`; + +exports[`remote generator bundler=rspack should generate correct remote with config files when using --ssr and --typescriptConfiguration=true 1`] = ` +"import { composePlugins, withNx, withReact } from '@nx/rspack'; +import { withModuleFederationForSSR } from '@nx/rspack/module-federation'; + +import baseConfig from './module-federation.server.config'; + +const defaultConfig = { + ...baseConfig, +}; + +// Nx plugins for rspack to build config object from Nx options and context. +/** + * DTS Plugin is disabled in Nx Workspaces as Nx already provides Typing support Module Federation + * The DTS Plugin can be enabled by setting dts: true + * Learn more about the DTS Plugin here: https://module-federation.io/configure/dts.html + */ +export default composePlugins( + withNx(), + withReact({ ssr: true }), + withModuleFederationForSSR(defaultConfig, { dts: false }) +); +" +`; + +exports[`remote generator bundler=rspack should generate correct remote with config files when using --ssr and --typescriptConfiguration=true 2`] = ` +"import { ModuleFederationConfig } from '@nx/rspack/module-federation'; + +const config: ModuleFederationConfig = { + name: 'test', + exposes: { + './Module': './src/remote-entry.ts', + }, +}; + +export default config; +" +`; diff --git a/packages/react/src/generators/remote/remote.rspack.spec.ts b/packages/react/src/generators/remote/remote.rspack.spec.ts index 5d439679334ca..f7a7444dd9f03 100644 --- a/packages/react/src/generators/remote/remote.rspack.spec.ts +++ b/packages/react/src/generators/remote/remote.rspack.spec.ts @@ -86,8 +86,7 @@ jest.mock('@nx/devkit', () => { }; }); -// TODO(colum): turn these on when rspack is moved into the main repo -xdescribe('remote generator', () => { +describe('remote generator', () => { // TODO(@jaysoo): Turn this back to adding the plugin let originalEnv: string; @@ -324,5 +323,28 @@ xdescribe('remote generator', () => { }) ).rejects.toThrowError(`Invalid remote name provided: ${name}.`); }); + + it('should throw an error when an invalid remote name is used', async () => { + const tree = createTreeWithEmptyWorkspace(); + await expect( + remote(tree, { + directory: 'test/my-app', + devServerPort: 4209, + e2eTestRunner: 'cypress', + linter: Linter.EsLint, + skipFormat: false, + style: 'css', + unitTestRunner: 'jest', + ssr: true, + typescriptConfiguration: true, + bundler: 'rspack', + }) + ).rejects.toMatchInlineSnapshot(` + [Error: Invalid remote name: my-app. Remote project names must: + - Start with a letter, dollar sign ($) or underscore (_) + - Followed by any valid character (letters, digits, underscores, or dollar signs) + The regular expression used is ^[a-zA-Z_$][a-zA-Z_$0-9]*$.] + `); + }); }); }); diff --git a/packages/react/src/generators/remote/remote.ts b/packages/react/src/generators/remote/remote.ts index de6c4557bf5b0..4d6549715c207 100644 --- a/packages/react/src/generators/remote/remote.ts +++ b/packages/react/src/generators/remote/remote.ts @@ -8,6 +8,7 @@ import { names, readProjectConfiguration, runTasksInSerial, + stripIndents, Tree, updateProjectConfiguration, } from '@nx/devkit'; @@ -25,7 +26,10 @@ import { addRemoteToDynamicHost } from './lib/add-remote-to-dynamic-host'; import { addMfEnvToTargetDefaultInputs } from '../../utils/add-mf-env-to-inputs'; import { maybeJs } from '../../utils/maybe-js'; import { isValidVariable } from '@nx/js'; -import { moduleFederationEnhancedVersion } from '../../utils/versions'; +import { + moduleFederationEnhancedVersion, + nxVersion, +} from '../../utils/versions'; import { ensureProjectName } from '@nx/devkit/src/generators/project-name-and-root-utils'; import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; @@ -119,6 +123,16 @@ export async function remoteGenerator(host: Tree, schema: Schema) { } await ensureProjectName(host, options, 'application'); + const REMOTE_NAME_REGEX = '^[a-zA-Z_$][a-zA-Z_$0-9]*$'; + const remoteNameRegex = new RegExp(REMOTE_NAME_REGEX); + if (!remoteNameRegex.test(options.projectName)) { + throw new Error( + stripIndents`Invalid remote name: ${options.projectName}. Remote project names must: + - Start with a letter, dollar sign ($) or underscore (_) + - Followed by any valid character (letters, digits, underscores, or dollar signs) + The regular expression used is ${REMOTE_NAME_REGEX}.` + ); + } const initAppTask = await applicationGenerator(host, { ...options, name: options.projectName, @@ -211,7 +225,10 @@ export async function remoteGenerator(host: Tree, schema: Schema) { const installTask = addDependenciesToPackageJson( host, {}, - { '@module-federation/enhanced': moduleFederationEnhancedVersion } + { + '@module-federation/enhanced': moduleFederationEnhancedVersion, + '@nx/web': nxVersion, + } ); tasks.push(installTask); diff --git a/packages/rspack/src/utils/module-federation/remotes.ts b/packages/rspack/src/utils/module-federation/remotes.ts index 8d92a6a7fcad6..c4c8432a1d255 100644 --- a/packages/rspack/src/utils/module-federation/remotes.ts +++ b/packages/rspack/src/utils/module-federation/remotes.ts @@ -16,12 +16,19 @@ export function mapRemotes( ): Record { const mappedRemotes = {}; - for (const remote of remotes) { - if (Array.isArray(remote)) { - const remoteName = normalizeRemoteName(remote[0]); - mappedRemotes[remoteName] = handleArrayRemote(remote, remoteEntryExt); - } else if (typeof remote === 'string') { - mappedRemotes[remote] = handleStringRemote(remote, determineRemoteUrl); + for (const nxRemoteProjectName of remotes) { + if (Array.isArray(nxRemoteProjectName)) { + const mfRemoteName = normalizeRemoteName(nxRemoteProjectName[0]); + mappedRemotes[mfRemoteName] = handleArrayRemote( + nxRemoteProjectName, + remoteEntryExt + ); + } else if (typeof nxRemoteProjectName === 'string') { + const mfRemoteName = normalizeRemoteName(nxRemoteProjectName[0]); + mappedRemotes[mfRemoteName] = handleStringRemote( + nxRemoteProjectName, + determineRemoteUrl + ); } } @@ -33,8 +40,8 @@ function handleArrayRemote( remote: [string, string], remoteEntryExt: 'js' | 'mjs' ): string { - let [remoteName, remoteLocation] = remote; - remoteName = normalizeRemoteName(remoteName); + let [nxRemoteProjectName, remoteLocation] = remote; + const mfRemoteName = normalizeRemoteName(nxRemoteProjectName); const remoteLocationExt = extname(remoteLocation); // If remote location already has .js or .mjs extension @@ -46,7 +53,7 @@ function handleArrayRemote( ? remoteLocation.slice(0, -1) : remoteLocation; - const globalPrefix = `${remoteName.replace(/-/g, '_')}@`; + const globalPrefix = `${normalizeRemoteName(mfRemoteName)}@`; // if the remote is defined with anything other than http then we assume it's a promise based remote // In that case we should use what the user provides as the remote location @@ -59,12 +66,12 @@ function handleArrayRemote( // Helper function to deal with remotes that are strings function handleStringRemote( - remote: string, - determineRemoteUrl: (remote: string) => string + nxRemoteProjectName: string, + determineRemoteUrl: (nxRemoteProjectName: string) => string ): string { - const globalPrefix = `${remote.replace(/-/g, '_')}@`; + const globalPrefix = `${normalizeRemoteName(nxRemoteProjectName)}@`; - return `${globalPrefix}${determineRemoteUrl(remote)}`; + return `${globalPrefix}${determineRemoteUrl(nxRemoteProjectName)}`; } /** @@ -84,10 +91,10 @@ export function mapRemotesForSSR( for (const remote of remotes) { if (Array.isArray(remote)) { - let [remoteName, remoteLocation] = remote; - remoteName = normalizeRemoteName(remoteName); + let [nxRemoteProjectName, remoteLocation] = remote; + const mfRemoteName = normalizeRemoteName(nxRemoteProjectName); const remoteLocationExt = extname(remoteLocation); - mappedRemotes[remoteName] = `${remoteName}@${ + mappedRemotes[mfRemoteName] = `${mfRemoteName}@${ ['.js', '.mjs'].includes(remoteLocationExt) ? remoteLocation : `${ @@ -97,14 +104,16 @@ export function mapRemotesForSSR( }/remoteEntry.${remoteEntryExt}` }`; } else if (typeof remote === 'string') { - const remoteName = normalizeRemoteName(remote); - mappedRemotes[remoteName] = `${remoteName}@${determineRemoteUrl(remote)}`; + const mfRemoteName = normalizeRemoteName(remote); + mappedRemotes[mfRemoteName] = `${mfRemoteName}@${determineRemoteUrl( + remote + )}`; } } return mappedRemotes; } -function normalizeRemoteName(remote: string): string { - return remote.replace(/-/g, '_'); +function normalizeRemoteName(nxRemoteProjectName: string): string { + return nxRemoteProjectName.replace(/-/g, '_'); } diff --git a/packages/webpack/src/utils/module-federation/remotes.ts b/packages/webpack/src/utils/module-federation/remotes.ts index c633cc4a05684..8372a9fe054cf 100644 --- a/packages/webpack/src/utils/module-federation/remotes.ts +++ b/packages/webpack/src/utils/module-federation/remotes.ts @@ -17,18 +17,19 @@ export function mapRemotes( ): Record { const mappedRemotes = {}; - for (const remote of remotes) { - if (Array.isArray(remote)) { - const remoteName = normalizeRemoteName(remote[0]); - mappedRemotes[remoteName] = handleArrayRemote( - remote, + for (const nxRemoteProjectName of remotes) { + if (Array.isArray(nxRemoteProjectName)) { + const mfRemoteName = normalizeRemoteName(nxRemoteProjectName[0]); + mappedRemotes[mfRemoteName] = handleArrayRemote( + nxRemoteProjectName, remoteEntryExt, isRemoteGlobal ); - } else if (typeof remote === 'string') { - const remoteName = normalizeRemoteName(remote); - mappedRemotes[remoteName] = handleStringRemote( - remote, + } else if (typeof nxRemoteProjectName === 'string') { + const mfRemoteName = normalizeRemoteName(nxRemoteProjectName); + mappedRemotes[mfRemoteName] = handleStringRemote( + nxRemoteProjectName, + determineRemoteUrl, isRemoteGlobal ); @@ -44,8 +45,8 @@ function handleArrayRemote( remoteEntryExt: 'js' | 'mjs', isRemoteGlobal: boolean ): string { - let [remoteName, remoteLocation] = remote; - remoteName = normalizeRemoteName(remoteName); + let [nxRemoteProjectName, remoteLocation] = remote; + const mfRemoteName = normalizeRemoteName(nxRemoteProjectName); const remoteLocationExt = extname(remoteLocation); // If remote location already has .js or .mjs extension @@ -58,7 +59,7 @@ function handleArrayRemote( : remoteLocation; const globalPrefix = isRemoteGlobal - ? `${remoteName.replace(/-/g, '_')}@` + ? `${normalizeRemoteName(nxRemoteProjectName)}@` : ''; // if the remote is defined with anything other than http then we assume it's a promise based remote @@ -72,13 +73,15 @@ function handleArrayRemote( // Helper function to deal with remotes that are strings function handleStringRemote( - remote: string, - determineRemoteUrl: (remote: string) => string, + nxRemoteProjectName: string, + determineRemoteUrl: (nxRemoteProjectName: string) => string, isRemoteGlobal: boolean ): string { - const globalPrefix = isRemoteGlobal ? `${remote.replace(/-/g, '_')}@` : ''; + const globalPrefix = isRemoteGlobal + ? `${normalizeRemoteName(nxRemoteProjectName)}@` + : ''; - return `${globalPrefix}${determineRemoteUrl(remote)}`; + return `${globalPrefix}${determineRemoteUrl(nxRemoteProjectName)}`; } /** @@ -98,10 +101,10 @@ export function mapRemotesForSSR( for (const remote of remotes) { if (Array.isArray(remote)) { - let [remoteName, remoteLocation] = remote; - remoteName = normalizeRemoteName(remoteName); + let [nxRemoteProjectName, remoteLocation] = remote; + const mfRemoteName = normalizeRemoteName(nxRemoteProjectName); const remoteLocationExt = extname(remoteLocation); - mappedRemotes[remoteName] = `${remoteName}@${ + mappedRemotes[mfRemoteName] = `${mfRemoteName}@${ ['.js', '.mjs', '.json'].includes(remoteLocationExt) ? remoteLocation : `${ @@ -111,8 +114,10 @@ export function mapRemotesForSSR( }/remoteEntry.${remoteEntryExt}` }`; } else if (typeof remote === 'string') { - const remoteName = normalizeRemoteName(remote); - mappedRemotes[remoteName] = `${remoteName}@${determineRemoteUrl(remote)}`; + const mfRemoteName = normalizeRemoteName(remote); + mappedRemotes[mfRemoteName] = `${mfRemoteName}@${determineRemoteUrl( + remote + )}`; } }