Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -100,25 +100,27 @@ export async function startRemoteIterators(
: startStaticRemotesFileServer(staticRemotesConfig, context, options);

isServer
? startSsrRemoteProxies(
? await startSsrRemoteProxies(
staticRemotesConfig,
mappedLocationsOfStaticRemotes,
options.ssl
? {
pathToCert: options.sslCert,
pathToKey: options.sslKey,
}
: undefined
: undefined,
options.host
)
: startRemoteProxies(
: await startRemoteProxies(
staticRemotesConfig,
mappedLocationsOfStaticRemotes,
options.ssl
? {
pathToCert: options.sslCert,
pathToKey: options.sslKey,
}
: undefined
: undefined,
options.host
);

return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,16 @@ export class NxModuleFederationDevServerPlugin implements RspackPluginInstance {
workspaceRoot,
this._options.devServerConfig.staticRemotesPort
);
startRemoteProxies(staticRemotesConfig, mappedLocationOfRemotes, {
pathToCert: this._options.devServerConfig.sslCert,
pathToKey: this._options.devServerConfig.sslCert,
});
await startRemoteProxies(
staticRemotesConfig,
mappedLocationOfRemotes,
{
pathToCert: this._options.devServerConfig.sslCert,
pathToKey: this._options.devServerConfig.sslCert,
},
false,
this._options.devServerConfig.host
);

new DefinePlugin({
'process.env.NX_MF_DEV_REMOTES': process.env.NX_MF_DEV_REMOTES,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,14 +74,15 @@ export class NxModuleFederationSSRDevServerPlugin
workspaceRoot,
this._options.devServerConfig.staticRemotesPort
);
startRemoteProxies(
await startRemoteProxies(
staticRemotesConfig,
mappedLocationOfRemotes,
{
pathToCert: this._options.devServerConfig.sslCert,
pathToKey: this._options.devServerConfig.sslCert,
},
true
true,
this._options.devServerConfig.host
);

new DefinePlugin({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,16 @@ export class NxModuleFederationDevServerPlugin implements RspackPluginInstance {
workspaceRoot,
this._options.devServerConfig.staticRemotesPort
);
startRemoteProxies(staticRemotesConfig, mappedLocationOfRemotes, {
pathToCert: this._options.devServerConfig.sslCert,
pathToKey: this._options.devServerConfig.sslCert,
});
await startRemoteProxies(
staticRemotesConfig,
mappedLocationOfRemotes,
{
pathToCert: this._options.devServerConfig.sslCert,
pathToKey: this._options.devServerConfig.sslCert,
},
false,
this._options.devServerConfig.host
);

new DefinePlugin({
'process.env.NX_MF_DEV_REMOTES': process.env.NX_MF_DEV_REMOTES,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,14 +74,15 @@ export class NxModuleFederationSSRDevServerPlugin
workspaceRoot,
this._options.devServerConfig.staticRemotesPort
);
startRemoteProxies(
await startRemoteProxies(
staticRemotesConfig,
mappedLocationOfRemotes,
{
pathToCert: this._options.devServerConfig.sslCert,
pathToKey: this._options.devServerConfig.sslCert,
},
true
true,
this._options.devServerConfig.host
);

new DefinePlugin({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import { StaticRemoteConfig } from '../../utils';
import { StaticRemoteConfig, isPortInUse } from '../../utils';
import { existsSync, readFileSync } from 'fs';
import { Express } from 'express';

export function startRemoteProxies(
export async function startRemoteProxies(
staticRemotesConfig: Record<string, StaticRemoteConfig>,
mappedLocationsOfRemotes: Record<string, string>,
sslOptions?: {
pathToCert: string;
pathToKey: string;
},
isServer?: boolean
isServer?: boolean,
host: string = '127.0.0.1'
) {
const { createProxyMiddleware } = require('http-proxy-middleware');
const express = require('express');
Expand All @@ -33,8 +34,22 @@ export function startRemoteProxies(

const remotes = Object.keys(staticRemotesConfig);
console.log(`NX Starting static remotes proxies...`);
let startedProxies = 0;
let skippedProxies = 0;

for (const app of remotes) {
const appConfig = staticRemotesConfig[app];

// Check if the port is already in use (another MF dev server may have already started a proxy)
const portInUse = await isPortInUse(appConfig.port, host);
if (portInUse) {
console.log(
`NX Skipping proxy for ${app} on port ${appConfig.port} - port already in use (likely served by another process)`
);
skippedProxies++;
continue;
}

const expressProxy: Express = express();
expressProxy.use(
createProxyMiddleware({
Expand All @@ -57,6 +72,14 @@ export function startRemoteProxies(
.listen(appConfig.port);
process.on('SIGTERM', () => proxyServer.close());
process.on('exit', () => proxyServer.close());
startedProxies++;
Comment thread
Coly010 marked this conversation as resolved.
}

if (skippedProxies > 0) {
console.info(
`NX Static remotes proxies: started ${startedProxies}, skipped ${skippedProxies} (already running)`
);
} else {
console.info(`NX Static remotes proxies started successfully`);
}
console.info(`NX Static remotes proxies started successfully`);
}
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 @@ -6,5 +6,6 @@ export * from './models';
export * from './normalize-project-name';
export * from './get-remotes-for-host';
export * from './parse-static-remotes-config';
export * from './port-utils';
export * from './start-remote-proxies';
export * from './start-ssr-remote-proxies';
17 changes: 17 additions & 0 deletions packages/module-federation/src/utils/port-utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { waitForPortOpen } from '@nx/web/src/utils/wait-for-port-open';

/**
* Check if a port is already in use by attempting to connect to it.
* Uses waitForPortOpen with retries: 0 for an immediate check.
*/
export async function isPortInUse(
port: number,
host: string = '127.0.0.1'
): Promise<boolean> {
try {
await waitForPortOpen(port, { retries: 0, host });
return true; // Port is open/in use
} catch {
return false; // Port is not in use
}
}
33 changes: 29 additions & 4 deletions packages/module-federation/src/utils/start-remote-proxies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ import type { Express } from 'express';
import { logger } from '@nx/devkit';
import { StaticRemotesConfig } from './parse-static-remotes-config';
import { existsSync, readFileSync } from 'fs';
import { isPortInUse } from './port-utils';

export function startRemoteProxies(
export async function startRemoteProxies(
staticRemotesConfig: StaticRemotesConfig,
mappedLocationsOfRemotes: Record<string, string>,
sslOptions?: { pathToCert: string; pathToKey: string }
sslOptions?: { pathToCert: string; pathToKey: string },
host: string = '127.0.0.1'
) {
const { createProxyMiddleware } = require('http-proxy-middleware');
const express = require('express');
Expand All @@ -29,7 +31,22 @@ export function startRemoteProxies(
const https = require('https');

logger.info(`NX Starting static remotes proxies...`);
let startedProxies = 0;
let skippedProxies = 0;

for (const app of staticRemotesConfig.remotes) {
const port = staticRemotesConfig.config[app].port;

// Check if the port is already in use (another MF dev server may have already started a proxy)
const portInUse = await isPortInUse(port, host);
if (portInUse) {
logger.info(
`NX Skipping proxy for ${app} on port ${port} - port already in use (likely served by another process)`
);
skippedProxies++;
continue;
}

const expressProxy: Express = express();
expressProxy.use(
createProxyMiddleware({
Expand All @@ -40,9 +57,17 @@ export function startRemoteProxies(
);
const proxyServer = (sslCert ? https : http)
.createServer({ cert: sslCert, key: sslKey }, expressProxy)
.listen(staticRemotesConfig.config[app].port);
.listen(port);
process.on('SIGTERM', () => proxyServer.close());
process.on('exit', () => proxyServer.close());
startedProxies++;
}

if (skippedProxies > 0) {
logger.info(
`NX Static remotes proxies: started ${startedProxies}, skipped ${skippedProxies} (already running)`
);
} else {
logger.info(`NX Static remotes proxies started successfully`);
}
logger.info(`NX Static remotes proxies started successfully`);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ import type { Express } from 'express';
import { logger } from '@nx/devkit';
import type { StaticRemotesConfig } from './parse-static-remotes-config';
import { existsSync, readFileSync } from 'fs';
import { isPortInUse } from './port-utils';

export function startSsrRemoteProxies(
export async function startSsrRemoteProxies(
staticRemotesConfig: StaticRemotesConfig,
mappedLocationsOfRemotes: Record<string, string>,
sslOptions?: { pathToCert: string; pathToKey: string }
sslOptions?: { pathToCert: string; pathToKey: string },
host: string = '127.0.0.1'
) {
const { createProxyMiddleware } = require('http-proxy-middleware');
const express = require('express');
Expand All @@ -31,7 +33,22 @@ export function startSsrRemoteProxies(
const https = require('https');

logger.info(`NX Starting static remotes proxies...`);
let startedProxies = 0;
let skippedProxies = 0;

for (const app of staticRemotesConfig.remotes) {
const port = staticRemotesConfig.config[app].port;

// Check if the port is already in use (another MF dev server may have already started a proxy)
const portInUse = await isPortInUse(port, host);
if (portInUse) {
logger.info(
`NX Skipping proxy for ${app} on port ${port} - port already in use (likely served by another process)`
);
skippedProxies++;
continue;
}

const expressProxy: Express = express();
/**
* SSR remotes have two output paths: one for the browser and one for the server.
Expand All @@ -57,9 +74,17 @@ export function startSsrRemoteProxies(

const proxyServer = (sslCert ? https : http)
.createServer({ cert: sslCert, key: sslKey }, expressProxy)
.listen(staticRemotesConfig.config[app].port);
.listen(port);
process.on('SIGTERM', () => proxyServer.close());
process.on('exit', () => proxyServer.close());
startedProxies++;
}

if (skippedProxies > 0) {
logger.info(
`NX SSR Static remotes proxies: started ${startedProxies}, skipped ${skippedProxies} (already running)`
);
} else {
logger.info(`Nx SSR Static remotes proxies started successfully`);
}
logger.info(`Nx SSR Static remotes proxies started successfully`);
}
Loading