Project Init

This commit is contained in:
Muluhabt
2026-05-29 15:23:46 +03:00
commit 2fbc557aac
67387 changed files with 6063341 additions and 0 deletions

View File

@@ -0,0 +1,5 @@
import { ExecutorContext } from '@nx/devkit';
import { type StaticRemotesConfig } from '../../utils';
import { type BuildStaticRemotesOptions } from './models';
export declare function buildStaticRemotes(staticRemotesConfig: StaticRemotesConfig, nxBin: any, context: ExecutorContext, options: BuildStaticRemotesOptions, buildTarget?: 'build' | 'server'): Promise<Record<string, string>>;
//# sourceMappingURL=build-static-remotes.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"build-static-remotes.d.ts","sourceRoot":"","sources":["../../../../../../packages/module-federation/src/executors/utils/build-static-remotes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAU,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,KAAK,yBAAyB,EAAE,MAAM,UAAU,CAAC;AAM1D,wBAAsB,kBAAkB,CACtC,mBAAmB,EAAE,mBAAmB,EACxC,KAAK,KAAA,EACL,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,yBAAyB,EAClC,WAAW,GAAE,OAAO,GAAG,QAAkB,mCAsF1C"}

View File

@@ -0,0 +1,70 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.buildStaticRemotes = buildStaticRemotes;
const devkit_1 = require("@nx/devkit");
const node_child_process_1 = require("node:child_process");
const path_1 = require("path");
const cache_directory_1 = require("nx/src/utils/cache-directory");
const fs_1 = require("fs");
async function buildStaticRemotes(staticRemotesConfig, nxBin, context, options, buildTarget = 'build') {
if (!staticRemotesConfig.remotes.length) {
return;
}
devkit_1.logger.info(`NX Building ${staticRemotesConfig.remotes.length} static remotes...`);
const mappedLocationOfRemotes = {};
for (const app of staticRemotesConfig.remotes) {
mappedLocationOfRemotes[app] = `http${options.ssl ? 's' : ''}://${options.host}:${options.staticRemotesPort}/${staticRemotesConfig.config[app].urlSegment}`;
}
await new Promise((res, rej) => {
const staticProcess = (0, node_child_process_1.fork)(nxBin, [
'run-many',
`--target=${buildTarget}`,
`--projects=${staticRemotesConfig.remotes.join(',')}`,
...(context.configurationName
? [`--configuration=${context.configurationName}`]
: []),
...(options.parallel ? [`--parallel=${options.parallel}`] : []),
], {
cwd: context.root,
stdio: ['ignore', 'pipe', 'pipe', 'ipc'],
env: {
...process.env,
// Ensure that webpack serve env var is not passed to static remotes
WEBPACK_SERVE: 'false',
},
});
// File to debug build failures e.g. 2024-01-01T00_00_0_0Z-build.log'
const remoteBuildLogFile = (0, path_1.join)(cache_directory_1.workspaceDataDirectory, `${new Date().toISOString().replace(/[:\.]/g, '_')}-build.log`);
const stdoutStream = (0, fs_1.createWriteStream)(remoteBuildLogFile);
staticProcess.stdout.on('data', (data) => {
const ANSII_CODE_REGEX = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g;
const stdoutString = data.toString().replace(ANSII_CODE_REGEX, '');
stdoutStream.write(stdoutString);
// in addition to writing into the stdout stream, also show error directly in console
// so the error is easily discoverable. 'ERROR in' is the key word to search in webpack output.
if (stdoutString.includes('ERROR in')) {
devkit_1.logger.log(stdoutString);
}
if (stdoutString.includes(`Successfully ran target ${buildTarget}`)) {
staticProcess.stdout.removeAllListeners('data');
devkit_1.logger.info(`NX Built ${staticRemotesConfig.remotes.length} static remotes`);
res();
}
});
staticProcess.stderr.on('data', (data) => devkit_1.logger.info(data.toString()));
staticProcess.once('exit', (code) => {
stdoutStream.end();
staticProcess.stdout.removeAllListeners('data');
staticProcess.stderr.removeAllListeners('data');
if (code !== 0) {
rej(`Remote failed to start. A complete log can be found in: ${remoteBuildLogFile}`);
}
else {
res();
}
});
process.on('SIGTERM', () => staticProcess.kill('SIGTERM'));
process.on('exit', () => staticProcess.kill('SIGTERM'));
});
return mappedLocationOfRemotes;
}

View File

@@ -0,0 +1,5 @@
export * from './start-static-remotes-file-server';
export * from './build-static-remotes';
export * from './start-remote-iterators';
export { DevRemoteDefinition } from './models';
//# sourceMappingURL=index.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../packages/module-federation/src/executors/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,oCAAoC,CAAC;AACnD,cAAc,wBAAwB,CAAC;AACvC,cAAc,0BAA0B,CAAC;AACzC,OAAO,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC"}

View File

@@ -0,0 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
tslib_1.__exportStar(require("./start-static-remotes-file-server"), exports);
tslib_1.__exportStar(require("./build-static-remotes"), exports);
tslib_1.__exportStar(require("./start-remote-iterators"), exports);

View File

@@ -0,0 +1,31 @@
import type { ProjectConfiguration, ExecutorContext } from '@nx/devkit';
export type DevRemoteDefinition = string | {
remoteName: string;
configuration: string;
};
export type StartRemoteFn = (remotes: string[], workspaceProjects: Record<string, ProjectConfiguration>, options: {
devRemotes: DevRemoteDefinition[];
verbose: boolean;
}, context: ExecutorContext, target: 'serve' | 'serve-static') => Promise<AsyncIterable<{
success: boolean;
}>[]>;
export interface StaticRemotesOptions {
staticRemotesPort?: number;
host?: string;
ssl?: boolean;
sslCert?: string;
sslKey?: string;
}
export interface BuildStaticRemotesOptions extends StaticRemotesOptions {
parallel?: number;
}
export interface StartRemoteIteratorsOptions extends BuildStaticRemotesOptions {
devRemotes: DevRemoteDefinition[];
skipRemotes?: string[];
buildTarget?: string;
liveReload?: boolean;
open?: boolean;
ssl?: boolean;
verbose: boolean;
}
//# sourceMappingURL=models.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../../../../../../packages/module-federation/src/executors/utils/models.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAExE,MAAM,MAAM,mBAAmB,GAC3B,MAAM,GACN;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,CAAC;AAElD,MAAM,MAAM,aAAa,GAAG,CAC1B,OAAO,EAAE,MAAM,EAAE,EACjB,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,EACvD,OAAO,EAAE;IACP,UAAU,EAAE,mBAAmB,EAAE,CAAC;IAClC,OAAO,EAAE,OAAO,CAAC;CAClB,EACD,OAAO,EAAE,eAAe,EACxB,MAAM,EAAE,OAAO,GAAG,cAAc,KAC7B,OAAO,CAAC,aAAa,CAAC;IAAE,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC,EAAE,CAAC,CAAC;AAEpD,MAAM,WAAW,oBAAoB;IACnC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,yBAA0B,SAAQ,oBAAoB;IACrE,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,2BAA4B,SAAQ,yBAAyB;IAC5E,UAAU,EAAE,mBAAmB,EAAE,CAAC;IAClC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;CAClB"}

View File

@@ -0,0 +1,2 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });

View File

@@ -0,0 +1,26 @@
import { StartRemoteFn, type StartRemoteIteratorsOptions } from './models';
import { type ExecutorContext } from '@nx/devkit';
export declare function startRemoteIterators(options: StartRemoteIteratorsOptions, context: ExecutorContext, startRemoteFn: StartRemoteFn, pathToManifestFile: string | undefined, pluginName?: 'react' | 'angular', isServer?: boolean): Promise<{
remotes: {
staticRemotes: string[];
devRemotes: any[];
dynamicRemotes: any[];
remotePorts: number[];
staticRemotePort: number;
};
devRemoteIters: AsyncIterable<{
success: boolean;
}>[];
staticRemotesIter: AsyncGenerator<{
success: boolean;
baseUrl: string;
}, {
success: boolean;
}, unknown> | AsyncGenerator<{
success: boolean;
baseUrl: string;
} | {
success: boolean;
}, void, unknown>;
}>;
//# sourceMappingURL=start-remote-iterators.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"start-remote-iterators.d.ts","sourceRoot":"","sources":["../../../../../../packages/module-federation/src/executors/utils/start-remote-iterators.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,KAAK,2BAA2B,EAAE,MAAM,UAAU,CAAC;AAgB3E,OAAO,EACL,KAAK,eAAe,EAErB,MAAM,YAAY,CAAC;AAEpB,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,2BAA2B,EACpC,OAAO,EAAE,eAAe,EACxB,aAAa,EAAE,aAAa,EAC5B,kBAAkB,EAAE,MAAM,GAAG,SAAS,EACtC,UAAU,GAAE,OAAO,GAAG,SAAmB,EACzC,QAAQ,UAAQ;;;;;;;;;;;;;;;;;;;;;;GAuGjB"}

View File

@@ -0,0 +1,52 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.startRemoteIterators = startRemoteIterators;
const utils_1 = require("../../utils");
const build_static_remotes_1 = require("./build-static-remotes");
const start_static_remotes_file_server_1 = require("./start-static-remotes-file-server");
const devkit_1 = require("@nx/devkit");
async function startRemoteIterators(options, context, startRemoteFn, pathToManifestFile, pluginName = 'react', isServer = false) {
const nxBin = require.resolve('nx/bin/nx');
const { projects: workspaceProjects } = (0, devkit_1.readProjectsConfigurationFromProjectGraph)(context.projectGraph);
const project = workspaceProjects[context.projectName];
const buildTargetName = (0, utils_1.getBuildTargetNameFromMFDevServer)(project, context.projectGraph);
const moduleFederationConfig = (0, utils_1.getModuleFederationConfig)(project.targets?.[buildTargetName]?.options?.tsConfig, context.root, project.root, pluginName);
const remoteNames = options.devRemotes.map((r) => typeof r === 'string' ? r : r.remoteName);
const remotes = (0, utils_1.getRemotes)(remoteNames, options.skipRemotes, moduleFederationConfig, {
projectName: project.name,
projectGraph: context.projectGraph,
root: context.root,
}, pathToManifestFile);
options.staticRemotesPort ??= remotes.staticRemotePort;
// Set NX_MF_DEV_REMOTES for the Nx Runtime Library Control Plugin
process.env.NX_MF_DEV_REMOTES = JSON.stringify([
...(remotes.devRemotes.map((r) => typeof r === 'string' ? r : r.remoteName) ?? []).map((r) => (0, utils_1.normalizeProjectName)(r)),
(0, utils_1.normalizeProjectName)(project.name),
]);
const staticRemotesConfig = isServer
? (0, utils_1.parseStaticSsrRemotesConfig)([...remotes.staticRemotes, ...remotes.dynamicRemotes], context)
: (0, utils_1.parseStaticRemotesConfig)([...remotes.staticRemotes, ...remotes.dynamicRemotes], context);
const mappedLocationsOfStaticRemotes = await (0, build_static_remotes_1.buildStaticRemotes)(staticRemotesConfig, nxBin, context, options, isServer ? 'server' : 'build');
const devRemoteIters = await startRemoteFn(remotes.devRemotes, workspaceProjects, options, context, 'serve');
const staticRemotesIter = isServer
? (0, start_static_remotes_file_server_1.startSsrStaticRemotesFileServer)(staticRemotesConfig, context, options)
: (0, start_static_remotes_file_server_1.startStaticRemotesFileServer)(staticRemotesConfig, context, options);
isServer
? await (0, utils_1.startSsrRemoteProxies)(staticRemotesConfig, mappedLocationsOfStaticRemotes, options.ssl
? {
pathToCert: options.sslCert,
pathToKey: options.sslKey,
}
: undefined, options.host)
: await (0, utils_1.startRemoteProxies)(staticRemotesConfig, mappedLocationsOfStaticRemotes, options.ssl
? {
pathToCert: options.sslCert,
pathToKey: options.sslKey,
}
: undefined, options.host);
return {
remotes,
devRemoteIters,
staticRemotesIter,
};
}

View File

@@ -0,0 +1,16 @@
import { type ExecutorContext } from '@nx/devkit';
import { type StaticRemotesOptions } from './models';
import type { StaticRemotesConfig } from '../../utils';
export declare function startStaticRemotesFileServer(staticRemotesConfig: StaticRemotesConfig, context: ExecutorContext, options: StaticRemotesOptions, forceMoveToCommonLocation?: boolean): AsyncGenerator<{
success: boolean;
baseUrl: string;
}, {
success: boolean;
}, unknown>;
export declare function startSsrStaticRemotesFileServer(staticRemotesConfig: StaticRemotesConfig, context: ExecutorContext, options: StaticRemotesOptions): AsyncGenerator<{
success: boolean;
baseUrl: string;
} | {
success: boolean;
}, void, unknown>;
//# sourceMappingURL=start-static-remotes-file-server.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"start-static-remotes-file-server.d.ts","sourceRoot":"","sources":["../../../../../../packages/module-federation/src/executors/utils/start-static-remotes-file-server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,eAAe,EAAiB,MAAM,YAAY,CAAC;AACjE,OAAO,EAAE,KAAK,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAIrD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAEvD,wBAAgB,4BAA4B,CAC1C,mBAAmB,EAAE,mBAAmB,EACxC,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,oBAAoB,EAC7B,yBAAyB,UAAQ;;;;;YAuDlC;AAED,wBAAuB,+BAA+B,CACpD,mBAAmB,EAAE,mBAAmB,EACxC,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,oBAAoB;;;;;kBAa9B"}

View File

@@ -0,0 +1,62 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.startStaticRemotesFileServer = startStaticRemotesFileServer;
exports.startSsrStaticRemotesFileServer = startSsrStaticRemotesFileServer;
const tslib_1 = require("tslib");
const devkit_1 = require("@nx/devkit");
const file_server_impl_1 = tslib_1.__importDefault(require("@nx/web/src/executors/file-server/file-server.impl"));
const path_1 = require("path");
const fs_1 = require("fs");
function startStaticRemotesFileServer(staticRemotesConfig, context, options, forceMoveToCommonLocation = false) {
if (!staticRemotesConfig.remotes ||
staticRemotesConfig.remotes.length === 0) {
return;
}
let shouldMoveToCommonLocation = forceMoveToCommonLocation || false;
let commonOutputDirectory;
if (!forceMoveToCommonLocation) {
for (const app of staticRemotesConfig.remotes) {
const remoteBasePath = staticRemotesConfig.config[app].basePath;
if (!commonOutputDirectory) {
commonOutputDirectory = remoteBasePath;
}
else if (commonOutputDirectory !== remoteBasePath) {
shouldMoveToCommonLocation = true;
break;
}
}
}
if (shouldMoveToCommonLocation) {
commonOutputDirectory = (0, path_1.join)(devkit_1.workspaceRoot, 'tmp/static-remotes');
for (const app of staticRemotesConfig.remotes) {
const remoteConfig = staticRemotesConfig.config[app];
(0, fs_1.cpSync)(remoteConfig.outputPath, (0, path_1.join)(commonOutputDirectory, remoteConfig.urlSegment), {
force: true,
recursive: true,
});
}
}
const staticRemotesIter = (0, file_server_impl_1.default)({
cors: true,
watch: false,
staticFilePath: commonOutputDirectory,
parallel: false,
spa: false,
withDeps: false,
host: options.host,
port: options.staticRemotesPort,
ssl: options.ssl,
sslCert: options.sslCert,
sslKey: options.sslKey,
cacheSeconds: -1,
}, context);
return staticRemotesIter;
}
async function* startSsrStaticRemotesFileServer(staticRemotesConfig, context, options) {
const staticRemotesIter = startStaticRemotesFileServer(staticRemotesConfig, context, options, true);
if (!staticRemotesIter) {
yield { success: true };
return;
}
yield* staticRemotesIter;
}

View File

@@ -0,0 +1,15 @@
export interface NxModuleFederationDevServerConfig {
host?: string;
staticRemotesPort?: number;
pathToManifestFile?: string;
ssl?: boolean;
sslCert?: string;
sslKey?: string;
parallel?: number;
devRemoteFindOptions?: DevRemoteFindOptions;
}
export interface DevRemoteFindOptions {
retries?: number;
retryDelay?: number;
}
//# sourceMappingURL=index.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../packages/module-federation/src/plugins/models/index.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,iCAAiC;IAChD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oBAAoB,CAAC,EAAE,oBAAoB,CAAC;CAC7C;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB"}

View File

@@ -0,0 +1,2 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });

View File

@@ -0,0 +1,14 @@
import { Compiler, RspackPluginInstance } from '@rspack/core';
import { ModuleFederationConfig } from '../../../utils/models';
import { NxModuleFederationDevServerConfig } from '../../models';
export declare class NxModuleFederationDevServerPlugin implements RspackPluginInstance {
private _options;
private nxBin;
constructor(_options: {
config: ModuleFederationConfig;
devServerConfig?: NxModuleFederationDevServerConfig;
});
apply(compiler: Compiler): void;
private setup;
}
//# sourceMappingURL=nx-module-federation-dev-server-plugin.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"nx-module-federation-dev-server-plugin.d.ts","sourceRoot":"","sources":["../../../../../../../packages/module-federation/src/plugins/nx-module-federation-plugin/angular/nx-module-federation-dev-server-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,QAAQ,EAER,oBAAoB,EACrB,MAAM,cAAc,CAAC;AAQtB,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAY/D,OAAO,EAAE,iCAAiC,EAAE,MAAM,cAAc,CAAC;AAIjE,qBAAa,iCAAkC,YAAW,oBAAoB;IAI1E,OAAO,CAAC,QAAQ;IAHlB,OAAO,CAAC,KAAK,CAAgC;gBAGnC,QAAQ,EAAE;QAChB,MAAM,EAAE,sBAAsB,CAAC;QAC/B,eAAe,CAAC,EAAE,iCAAiC,CAAC;KACrD;IAOH,KAAK,CAAC,QAAQ,EAAE,QAAQ;YAoDV,KAAK;CAyDpB"}

View File

@@ -0,0 +1,76 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.NxModuleFederationDevServerPlugin = void 0;
const tslib_1 = require("tslib");
const core_1 = require("@rspack/core");
const pc = tslib_1.__importStar(require("picocolors"));
const devkit_1 = require("@nx/devkit");
const path_1 = require("path");
const fs_1 = require("fs");
const utils_1 = require("../../utils");
const PLUGIN_NAME = 'NxModuleFederationDevServerPlugin';
class NxModuleFederationDevServerPlugin {
constructor(_options) {
this._options = _options;
this.nxBin = require.resolve('nx/bin/nx');
this._options.devServerConfig ??= {
host: 'localhost',
};
}
apply(compiler) {
const isDevServer = process.env['WEBPACK_SERVE'];
if (!isDevServer) {
return;
}
let initialized = false;
compiler.hooks.beforeCompile.tapAsync(PLUGIN_NAME, async (params, callback) => {
if (!initialized) {
initialized = true;
const staticRemotesConfig = await this.setup();
devkit_1.logger.info(`NX Starting module federation dev-server for ${pc.bold(this._options.config.name)} with ${Object.keys(staticRemotesConfig).length} remotes`);
const mappedLocationOfRemotes = await (0, utils_1.buildStaticRemotes)(staticRemotesConfig, this._options.devServerConfig, this.nxBin);
(0, utils_1.startStaticRemotesFileServer)(staticRemotesConfig, devkit_1.workspaceRoot, this._options.devServerConfig.staticRemotesPort);
await (0, utils_1.startRemoteProxies)(staticRemotesConfig, mappedLocationOfRemotes, {
pathToCert: this._options.devServerConfig.sslCert,
pathToKey: this._options.devServerConfig.sslKey,
}, false, this._options.devServerConfig.host);
new core_1.DefinePlugin({
'process.env.NX_MF_DEV_REMOTES': process.env.NX_MF_DEV_REMOTES,
}).apply(compiler);
}
callback();
});
}
async setup() {
const projectGraph = (0, devkit_1.readCachedProjectGraph)();
const { projects: workspaceProjects } = (0, devkit_1.readProjectsConfigurationFromProjectGraph)(projectGraph);
const project = workspaceProjects[this._options.config.name];
if (!this._options.devServerConfig.pathToManifestFile) {
this._options.devServerConfig.pathToManifestFile =
(0, utils_1.getDynamicMfManifestFile)(project, devkit_1.workspaceRoot);
}
else {
const userPathToManifestFile = this._options.devServerConfig.pathToManifestFile.startsWith(devkit_1.workspaceRoot)
? this._options.devServerConfig.pathToManifestFile
: (0, path_1.join)(devkit_1.workspaceRoot, this._options.devServerConfig.pathToManifestFile);
if (!(0, fs_1.existsSync)(userPathToManifestFile)) {
throw new Error(`The provided Module Federation manifest file path does not exist. Please check the file exists at "${userPathToManifestFile}".`);
}
else if ((0, path_1.extname)(this._options.devServerConfig.pathToManifestFile) !== '.json') {
throw new Error(`The Module Federation manifest file must be a JSON. Please ensure the file at ${userPathToManifestFile} is a JSON.`);
}
this._options.devServerConfig.pathToManifestFile = userPathToManifestFile;
}
const { remotes, staticRemotePort } = (0, utils_1.getRemotes)(this._options.config, projectGraph, this._options.devServerConfig.pathToManifestFile);
this._options.devServerConfig.staticRemotesPort ??= staticRemotePort;
const remotesConfig = (0, utils_1.parseRemotesConfig)(remotes, devkit_1.workspaceRoot, projectGraph);
const staticRemotesConfig = await (0, utils_1.getStaticRemotes)(remotesConfig.config ?? {}, this._options.devServerConfig?.devRemoteFindOptions, this._options.devServerConfig?.host);
const devRemotes = remotes.filter((r) => !staticRemotesConfig[r]);
process.env.NX_MF_DEV_REMOTES = JSON.stringify([
...(devRemotes.length > 0 ? devRemotes : []),
project.name,
]);
return staticRemotesConfig ?? {};
}
}
exports.NxModuleFederationDevServerPlugin = NxModuleFederationDevServerPlugin;

View File

@@ -0,0 +1,12 @@
import { Compiler, RspackPluginInstance } from '@rspack/core';
import { ModuleFederationConfig, NxModuleFederationConfigOverride } from '../../../utils/models';
export declare class NxModuleFederationPlugin implements RspackPluginInstance {
private _options;
private configOverride?;
constructor(_options: {
config: ModuleFederationConfig;
isServer?: boolean;
}, configOverride?: NxModuleFederationConfigOverride);
apply(compiler: Compiler): void;
}
//# sourceMappingURL=nx-module-federation-plugin.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"nx-module-federation-plugin.d.ts","sourceRoot":"","sources":["../../../../../../../packages/module-federation/src/plugins/nx-module-federation-plugin/angular/nx-module-federation-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAC9D,OAAO,EACL,sBAAsB,EACtB,gCAAgC,EACjC,MAAM,uBAAuB,CAAC;AAK/B,qBAAa,wBAAyB,YAAW,oBAAoB;IAEjE,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,cAAc,CAAC;gBAJf,QAAQ,EAAE;QAChB,MAAM,EAAE,sBAAsB,CAAC;QAC/B,QAAQ,CAAC,EAAE,OAAO,CAAC;KACpB,EACO,cAAc,CAAC,EAAE,gCAAgC;IAG3D,KAAK,CAAC,QAAQ,EAAE,QAAQ;CA0FzB"}

View File

@@ -0,0 +1,90 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.NxModuleFederationPlugin = void 0;
const utils_1 = require("../../../with-module-federation/angular/utils");
const utils_2 = require("../../../utils");
const devkit_1 = require("@nx/devkit");
class NxModuleFederationPlugin {
constructor(_options, configOverride) {
this._options = _options;
this.configOverride = configOverride;
}
apply(compiler) {
if (global.NX_GRAPH_CREATION) {
return;
}
// This is required to ensure Module Federation will build the project correctly
compiler.options.optimization ??= {};
compiler.options.optimization.runtimeChunk =
process.env['WEBPACK_SERVE'] && !this._options.config.exposes
? (compiler.options.optimization?.runtimeChunk ?? undefined)
: false;
if (compiler.options.optimization.splitChunks) {
compiler.options.optimization.splitChunks.cacheGroups ??= {};
compiler.options.optimization.splitChunks.cacheGroups.default = false;
compiler.options.optimization.splitChunks.cacheGroups.common = false;
}
compiler.options.output.publicPath = !compiler.options.output.publicPath
? 'auto'
: compiler.options.output.publicPath;
compiler.options.output.uniqueName = this._options.config.name;
// Ensure workspace root is in resolve.modules so that expose paths
// like "apps/remote/src/..." resolve correctly without baseUrl.
compiler.options.resolve ??= {};
compiler.options.resolve.modules = [
...(compiler.options.resolve.modules ?? ['node_modules']),
devkit_1.workspaceRoot,
];
if (this._options.isServer) {
compiler.options.target = 'async-node';
compiler.options.output.library ??= {
type: 'commonjs-module',
};
compiler.options.output.library.type = 'commonjs-module';
}
else {
// Ensure ESM output is enabled when using library type 'module'.
// Without these, remoteEntry.js emits `export` statements but the
// runtime loads it as a classic script, causing "Unexpected token 'export'".
compiler.options.experiments ??= {};
compiler.options.experiments.outputModule = true;
compiler.options.output.module = true;
}
const config = (0, utils_1.getModuleFederationConfigSync)(this._options.config, {
isServer: this._options.isServer,
}, true);
const sharedLibraries = config.sharedLibraries;
const sharedDependencies = config.sharedDependencies;
const mappedRemotes = config.mappedRemotes;
const runtimePlugins = [];
if (this.configOverride?.runtimePlugins) {
runtimePlugins.push(...(this.configOverride.runtimePlugins ?? []));
}
if (this._options.isServer) {
runtimePlugins.push(require.resolve('@module-federation/node/runtimePlugin'));
}
new (require('@module-federation/enhanced/rspack').ModuleFederationPlugin)({
name: (0, utils_2.normalizeProjectName)(this._options.config.name),
filename: 'remoteEntry.js',
exposes: this._options.config.exposes,
remotes: mappedRemotes,
shared: {
...(sharedDependencies ?? {}),
},
...(this._options.isServer
? {
library: {
type: 'commonjs-module',
},
remoteType: 'script',
}
: { library: { type: 'module' } }),
...(this.configOverride ? this.configOverride : {}),
runtimePlugins,
}).apply(compiler);
if (sharedLibraries) {
sharedLibraries.getReplacementPlugin().apply(compiler);
}
}
}
exports.NxModuleFederationPlugin = NxModuleFederationPlugin;

View File

@@ -0,0 +1,16 @@
import { Compiler, RspackPluginInstance } from '@rspack/core';
import { ModuleFederationConfig } from '../../../utils/models';
import { NxModuleFederationDevServerConfig } from '../../models';
export declare class NxModuleFederationSSRDevServerPlugin implements RspackPluginInstance {
private _options;
private devServerProcess;
private nxBin;
constructor(_options: {
config: ModuleFederationConfig;
devServerConfig?: NxModuleFederationDevServerConfig;
});
apply(compiler: Compiler): void;
private startServer;
private setup;
}
//# sourceMappingURL=nx-module-federation-ssr-dev-server-plugin.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"nx-module-federation-ssr-dev-server-plugin.d.ts","sourceRoot":"","sources":["../../../../../../../packages/module-federation/src/plugins/nx-module-federation-plugin/angular/nx-module-federation-ssr-dev-server-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,QAAQ,EAER,oBAAoB,EACrB,MAAM,cAAc,CAAC;AAQtB,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAY/D,OAAO,EAAE,iCAAiC,EAAE,MAAM,cAAc,CAAC;AAKjE,qBAAa,oCACX,YAAW,oBAAoB;IAM7B,OAAO,CAAC,QAAQ;IAJlB,OAAO,CAAC,gBAAgB,CAA2B;IACnD,OAAO,CAAC,KAAK,CAAgC;gBAGnC,QAAQ,EAAE;QAChB,MAAM,EAAE,sBAAsB,CAAC;QAC/B,eAAe,CAAC,EAAE,iCAAiC,CAAC;KACrD;IAOH,KAAK,CAAC,QAAQ,EAAE,QAAQ;YAsDV,WAAW;YAuCX,KAAK;CAmDpB"}

View File

@@ -0,0 +1,108 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.NxModuleFederationSSRDevServerPlugin = void 0;
const tslib_1 = require("tslib");
const core_1 = require("@rspack/core");
const pc = tslib_1.__importStar(require("picocolors"));
const devkit_1 = require("@nx/devkit");
const path_1 = require("path");
const fs_1 = require("fs");
const utils_1 = require("../../utils");
const node_child_process_1 = require("node:child_process");
const PLUGIN_NAME = 'NxModuleFederationSSRDevServerPlugin';
class NxModuleFederationSSRDevServerPlugin {
constructor(_options) {
this._options = _options;
this.nxBin = require.resolve('nx/bin/nx');
this._options.devServerConfig ??= {
host: 'localhost',
};
}
apply(compiler) {
const isDevServer = process.env['WEBPACK_SERVE'];
if (!isDevServer) {
return;
}
compiler.hooks.watchRun.tapAsync(PLUGIN_NAME, async (compiler, callback) => {
compiler.hooks.beforeCompile.tapAsync(PLUGIN_NAME, async (params, callback) => {
const staticRemotesConfig = await this.setup(compiler);
devkit_1.logger.info(`NX Starting module federation dev-server for ${pc.bold(this._options.config.name)} with ${Object.keys(staticRemotesConfig).length} remotes`);
const mappedLocationOfRemotes = await (0, utils_1.buildStaticRemotes)(staticRemotesConfig, this._options.devServerConfig, this.nxBin);
(0, utils_1.startStaticRemotesFileServer)(staticRemotesConfig, devkit_1.workspaceRoot, this._options.devServerConfig.staticRemotesPort);
await (0, utils_1.startRemoteProxies)(staticRemotesConfig, mappedLocationOfRemotes, {
pathToCert: this._options.devServerConfig.sslCert,
pathToKey: this._options.devServerConfig.sslKey,
}, true, this._options.devServerConfig.host);
new core_1.DefinePlugin({
'process.env.NX_MF_DEV_REMOTES': process.env.NX_MF_DEV_REMOTES,
}).apply(compiler);
await this.startServer(compiler);
callback();
});
callback();
});
}
async startServer(compiler) {
compiler.hooks.done.tapAsync(PLUGIN_NAME, async (_, callback) => {
const serverPath = (0, path_1.join)(compiler.options.output.path, compiler.options.output.filename ?? 'server.js');
if (this.devServerProcess) {
await new Promise((res) => {
this.devServerProcess.on('exit', () => {
res();
});
this.devServerProcess.kill('SIGKILL');
this.devServerProcess = undefined;
});
}
if (!(0, fs_1.existsSync)(serverPath)) {
for (let retries = 0; retries < 10; retries++) {
await new Promise((res) => setTimeout(res, 200));
if ((0, fs_1.existsSync)(serverPath)) {
break;
}
}
if (!(0, fs_1.existsSync)(serverPath)) {
throw new Error(`Could not find server bundle at ${serverPath}.`);
}
}
this.devServerProcess = (0, node_child_process_1.fork)(serverPath);
process.on('exit', () => {
this.devServerProcess?.kill('SIGKILL');
});
process.on('SIGINT', () => {
this.devServerProcess?.kill('SIGKILL');
});
callback();
});
}
async setup(compiler) {
const projectGraph = (0, devkit_1.readCachedProjectGraph)();
const { projects: workspaceProjects } = (0, devkit_1.readProjectsConfigurationFromProjectGraph)(projectGraph);
const project = workspaceProjects[this._options.config.name];
if (!this._options.devServerConfig.pathToManifestFile) {
this._options.devServerConfig.pathToManifestFile =
(0, utils_1.getDynamicMfManifestFile)(project, devkit_1.workspaceRoot);
}
else {
const userPathToManifestFile = (0, path_1.join)(devkit_1.workspaceRoot, this._options.devServerConfig.pathToManifestFile);
if (!(0, fs_1.existsSync)(userPathToManifestFile)) {
throw new Error(`The provided Module Federation manifest file path does not exist. Please check the file exists at "${userPathToManifestFile}".`);
}
else if ((0, path_1.extname)(this._options.devServerConfig.pathToManifestFile) !== '.json') {
throw new Error(`The Module Federation manifest file must be a JSON. Please ensure the file at ${userPathToManifestFile} is a JSON.`);
}
this._options.devServerConfig.pathToManifestFile = userPathToManifestFile;
}
const { remotes, staticRemotePort } = (0, utils_1.getRemotes)(this._options.config, projectGraph, this._options.devServerConfig.pathToManifestFile);
this._options.devServerConfig.staticRemotesPort ??= staticRemotePort;
const remotesConfig = (0, utils_1.parseRemotesConfig)(remotes, devkit_1.workspaceRoot, projectGraph, true);
const staticRemotesConfig = await (0, utils_1.getStaticRemotes)(remotesConfig.config ?? {});
const devRemotes = remotes.filter((r) => !staticRemotesConfig[r]);
process.env.NX_MF_DEV_REMOTES = JSON.stringify([
...(devRemotes.length > 0 ? devRemotes : []),
project.name,
]);
return staticRemotesConfig ?? {};
}
}
exports.NxModuleFederationSSRDevServerPlugin = NxModuleFederationSSRDevServerPlugin;

View File

@@ -0,0 +1,14 @@
import { Compiler, RspackPluginInstance } from '@rspack/core';
import { ModuleFederationConfig } from '../../../utils/models';
import { NxModuleFederationDevServerConfig } from '../../models';
export declare class NxModuleFederationDevServerPlugin implements RspackPluginInstance {
private _options;
private nxBin;
constructor(_options: {
config: ModuleFederationConfig;
devServerConfig?: NxModuleFederationDevServerConfig;
});
apply(compiler: Compiler): void;
private setup;
}
//# sourceMappingURL=nx-module-federation-dev-server-plugin.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"nx-module-federation-dev-server-plugin.d.ts","sourceRoot":"","sources":["../../../../../../../packages/module-federation/src/plugins/nx-module-federation-plugin/rspack/nx-module-federation-dev-server-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,QAAQ,EAER,oBAAoB,EACrB,MAAM,cAAc,CAAC;AAQtB,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAY/D,OAAO,EAAE,iCAAiC,EAAE,MAAM,cAAc,CAAC;AAIjE,qBAAa,iCAAkC,YAAW,oBAAoB;IAI1E,OAAO,CAAC,QAAQ;IAHlB,OAAO,CAAC,KAAK,CAAgC;gBAGnC,QAAQ,EAAE;QAChB,MAAM,EAAE,sBAAsB,CAAC;QAC/B,eAAe,CAAC,EAAE,iCAAiC,CAAC;KACrD;IAOH,KAAK,CAAC,QAAQ,EAAE,QAAQ;YAoDV,KAAK;CAyDpB"}

View File

@@ -0,0 +1,76 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.NxModuleFederationDevServerPlugin = void 0;
const tslib_1 = require("tslib");
const core_1 = require("@rspack/core");
const pc = tslib_1.__importStar(require("picocolors"));
const devkit_1 = require("@nx/devkit");
const path_1 = require("path");
const fs_1 = require("fs");
const utils_1 = require("../../utils");
const PLUGIN_NAME = 'NxModuleFederationDevServerPlugin';
class NxModuleFederationDevServerPlugin {
constructor(_options) {
this._options = _options;
this.nxBin = require.resolve('nx/bin/nx');
this._options.devServerConfig ??= {
host: 'localhost',
};
}
apply(compiler) {
const isDevServer = process.env['WEBPACK_SERVE'];
if (!isDevServer) {
return;
}
let initialized = false;
compiler.hooks.beforeCompile.tapAsync(PLUGIN_NAME, async (params, callback) => {
if (!initialized) {
initialized = true;
const staticRemotesConfig = await this.setup();
devkit_1.logger.info(`NX Starting module federation dev-server for ${pc.bold(this._options.config.name)} with ${Object.keys(staticRemotesConfig).length} remotes`);
const mappedLocationOfRemotes = await (0, utils_1.buildStaticRemotes)(staticRemotesConfig, this._options.devServerConfig, this.nxBin);
(0, utils_1.startStaticRemotesFileServer)(staticRemotesConfig, devkit_1.workspaceRoot, this._options.devServerConfig.staticRemotesPort);
await (0, utils_1.startRemoteProxies)(staticRemotesConfig, mappedLocationOfRemotes, {
pathToCert: this._options.devServerConfig.sslCert,
pathToKey: this._options.devServerConfig.sslKey,
}, false, this._options.devServerConfig.host);
new core_1.DefinePlugin({
'process.env.NX_MF_DEV_REMOTES': process.env.NX_MF_DEV_REMOTES,
}).apply(compiler);
}
callback();
});
}
async setup() {
const projectGraph = (0, devkit_1.readCachedProjectGraph)();
const { projects: workspaceProjects } = (0, devkit_1.readProjectsConfigurationFromProjectGraph)(projectGraph);
const project = workspaceProjects[this._options.config.name];
if (!this._options.devServerConfig.pathToManifestFile) {
this._options.devServerConfig.pathToManifestFile =
(0, utils_1.getDynamicMfManifestFile)(project, devkit_1.workspaceRoot);
}
else {
const userPathToManifestFile = this._options.devServerConfig.pathToManifestFile.startsWith(devkit_1.workspaceRoot)
? this._options.devServerConfig.pathToManifestFile
: (0, path_1.join)(devkit_1.workspaceRoot, this._options.devServerConfig.pathToManifestFile);
if (!(0, fs_1.existsSync)(userPathToManifestFile)) {
throw new Error(`The provided Module Federation manifest file path does not exist. Please check the file exists at "${userPathToManifestFile}".`);
}
else if ((0, path_1.extname)(this._options.devServerConfig.pathToManifestFile) !== '.json') {
throw new Error(`The Module Federation manifest file must be a JSON. Please ensure the file at ${userPathToManifestFile} is a JSON.`);
}
this._options.devServerConfig.pathToManifestFile = userPathToManifestFile;
}
const { remotes, staticRemotePort } = (0, utils_1.getRemotes)(this._options.config, projectGraph, this._options.devServerConfig.pathToManifestFile);
this._options.devServerConfig.staticRemotesPort ??= staticRemotePort;
const remotesConfig = (0, utils_1.parseRemotesConfig)(remotes, devkit_1.workspaceRoot, projectGraph);
const staticRemotesConfig = await (0, utils_1.getStaticRemotes)(remotesConfig.config ?? {}, this._options.devServerConfig?.devRemoteFindOptions, this._options.devServerConfig?.host);
const devRemotes = remotes.filter((r) => !staticRemotesConfig[r]);
process.env.NX_MF_DEV_REMOTES = JSON.stringify([
...(devRemotes.length > 0 ? devRemotes : []),
project.name,
]);
return staticRemotesConfig ?? {};
}
}
exports.NxModuleFederationDevServerPlugin = NxModuleFederationDevServerPlugin;

View File

@@ -0,0 +1,12 @@
import { Compiler, RspackPluginInstance } from '@rspack/core';
import { ModuleFederationConfig, NxModuleFederationConfigOverride } from '../../../utils/models';
export declare class NxModuleFederationPlugin implements RspackPluginInstance {
private _options;
private configOverride?;
constructor(_options: {
config: ModuleFederationConfig;
isServer?: boolean;
}, configOverride?: NxModuleFederationConfigOverride);
apply(compiler: Compiler): void;
}
//# sourceMappingURL=nx-module-federation-plugin.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"nx-module-federation-plugin.d.ts","sourceRoot":"","sources":["../../../../../../../packages/module-federation/src/plugins/nx-module-federation-plugin/rspack/nx-module-federation-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAC9D,OAAO,EACL,sBAAsB,EACtB,gCAAgC,EACjC,MAAM,uBAAuB,CAAC;AAK/B,qBAAa,wBAAyB,YAAW,oBAAoB;IAEjE,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,cAAc,CAAC;gBAJf,QAAQ,EAAE;QAChB,MAAM,EAAE,sBAAsB,CAAC;QAC/B,QAAQ,CAAC,EAAE,OAAO,CAAC;KACpB,EACO,cAAc,CAAC,EAAE,gCAAgC;IAG3D,KAAK,CAAC,QAAQ,EAAE,QAAQ;CA0EzB"}

View File

@@ -0,0 +1,80 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.NxModuleFederationPlugin = void 0;
const utils_1 = require("../../../with-module-federation/rspack/utils");
const utils_2 = require("../../../utils");
const devkit_1 = require("@nx/devkit");
class NxModuleFederationPlugin {
constructor(_options, configOverride) {
this._options = _options;
this.configOverride = configOverride;
}
apply(compiler) {
if (global.NX_GRAPH_CREATION) {
return;
}
// This is required to ensure Module Federation will build the project correctly
compiler.options.optimization ??= {};
compiler.options.optimization.runtimeChunk = false;
if (compiler.options.optimization.splitChunks) {
compiler.options.optimization.splitChunks.cacheGroups ??= {};
compiler.options.optimization.splitChunks.cacheGroups.default = false;
compiler.options.optimization.splitChunks.cacheGroups.common = false;
}
compiler.options.output.uniqueName = this._options.config.name;
// Ensure workspace root is in resolve.modules so that expose paths
// like "apps/remote/src/..." resolve correctly without baseUrl.
compiler.options.resolve ??= {};
compiler.options.resolve.modules = [
...(compiler.options.resolve.modules ?? ['node_modules']),
devkit_1.workspaceRoot,
];
if (compiler.options.output.scriptType === 'module') {
compiler.options.output.scriptType = undefined;
compiler.options.output.module = undefined;
}
if (this._options.isServer) {
compiler.options.target = 'async-node';
compiler.options.output.library ??= {
type: 'commonjs-module',
};
compiler.options.output.library.type = 'commonjs-module';
}
const config = (0, utils_1.getModuleFederationConfig)(this._options.config, {
isServer: this._options.isServer,
});
const sharedLibraries = config.sharedLibraries;
const sharedDependencies = config.sharedDependencies;
const mappedRemotes = config.mappedRemotes;
const runtimePlugins = [];
if (this.configOverride?.runtimePlugins) {
runtimePlugins.push(...(this.configOverride.runtimePlugins ?? []));
}
if (this._options.isServer) {
runtimePlugins.push(require.resolve('@module-federation/node/runtimePlugin'));
}
new (require('@module-federation/enhanced/rspack').ModuleFederationPlugin)({
name: (0, utils_2.normalizeProjectName)(this._options.config.name),
filename: 'remoteEntry.js',
exposes: this._options.config.exposes,
remotes: mappedRemotes,
shared: {
...(sharedDependencies ?? {}),
},
...(this._options.isServer
? {
library: {
type: 'commonjs-module',
},
remoteType: 'script',
}
: {}),
...(this.configOverride ? this.configOverride : {}),
runtimePlugins,
}).apply(compiler);
if (sharedLibraries) {
sharedLibraries.getReplacementPlugin().apply(compiler);
}
}
}
exports.NxModuleFederationPlugin = NxModuleFederationPlugin;

View File

@@ -0,0 +1,16 @@
import { Compiler, RspackPluginInstance } from '@rspack/core';
import { ModuleFederationConfig } from '../../../utils/models';
import { NxModuleFederationDevServerConfig } from '../../models';
export declare class NxModuleFederationSSRDevServerPlugin implements RspackPluginInstance {
private _options;
private devServerProcess;
private nxBin;
constructor(_options: {
config: ModuleFederationConfig;
devServerConfig?: NxModuleFederationDevServerConfig;
});
apply(compiler: Compiler): void;
private startServer;
private setup;
}
//# sourceMappingURL=nx-module-federation-ssr-dev-server-plugin.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"nx-module-federation-ssr-dev-server-plugin.d.ts","sourceRoot":"","sources":["../../../../../../../packages/module-federation/src/plugins/nx-module-federation-plugin/rspack/nx-module-federation-ssr-dev-server-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,QAAQ,EAER,oBAAoB,EACrB,MAAM,cAAc,CAAC;AAQtB,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAY/D,OAAO,EAAE,iCAAiC,EAAE,MAAM,cAAc,CAAC;AAKjE,qBAAa,oCACX,YAAW,oBAAoB;IAM7B,OAAO,CAAC,QAAQ;IAJlB,OAAO,CAAC,gBAAgB,CAA2B;IACnD,OAAO,CAAC,KAAK,CAAgC;gBAGnC,QAAQ,EAAE;QAChB,MAAM,EAAE,sBAAsB,CAAC;QAC/B,eAAe,CAAC,EAAE,iCAAiC,CAAC;KACrD;IAOH,KAAK,CAAC,QAAQ,EAAE,QAAQ;YAsDV,WAAW;YAuCX,KAAK;CAmDpB"}

View File

@@ -0,0 +1,108 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.NxModuleFederationSSRDevServerPlugin = void 0;
const tslib_1 = require("tslib");
const core_1 = require("@rspack/core");
const pc = tslib_1.__importStar(require("picocolors"));
const devkit_1 = require("@nx/devkit");
const path_1 = require("path");
const fs_1 = require("fs");
const utils_1 = require("../../utils");
const node_child_process_1 = require("node:child_process");
const PLUGIN_NAME = 'NxModuleFederationSSRDevServerPlugin';
class NxModuleFederationSSRDevServerPlugin {
constructor(_options) {
this._options = _options;
this.nxBin = require.resolve('nx/bin/nx');
this._options.devServerConfig ??= {
host: 'localhost',
};
}
apply(compiler) {
const isDevServer = process.env['WEBPACK_SERVE'];
if (!isDevServer) {
return;
}
compiler.hooks.watchRun.tapAsync(PLUGIN_NAME, async (compiler, callback) => {
compiler.hooks.beforeCompile.tapAsync(PLUGIN_NAME, async (params, callback) => {
const staticRemotesConfig = await this.setup(compiler);
devkit_1.logger.info(`NX Starting module federation dev-server for ${pc.bold(this._options.config.name)} with ${Object.keys(staticRemotesConfig).length} remotes`);
const mappedLocationOfRemotes = await (0, utils_1.buildStaticRemotes)(staticRemotesConfig, this._options.devServerConfig, this.nxBin);
(0, utils_1.startStaticRemotesFileServer)(staticRemotesConfig, devkit_1.workspaceRoot, this._options.devServerConfig.staticRemotesPort);
await (0, utils_1.startRemoteProxies)(staticRemotesConfig, mappedLocationOfRemotes, {
pathToCert: this._options.devServerConfig.sslCert,
pathToKey: this._options.devServerConfig.sslKey,
}, true, this._options.devServerConfig.host);
new core_1.DefinePlugin({
'process.env.NX_MF_DEV_REMOTES': process.env.NX_MF_DEV_REMOTES,
}).apply(compiler);
await this.startServer(compiler);
callback();
});
callback();
});
}
async startServer(compiler) {
compiler.hooks.done.tapAsync(PLUGIN_NAME, async (_, callback) => {
const serverPath = (0, path_1.join)(compiler.options.output.path, compiler.options.output.filename ?? 'server.js');
if (this.devServerProcess) {
await new Promise((res) => {
this.devServerProcess.on('exit', () => {
res();
});
this.devServerProcess.kill('SIGKILL');
this.devServerProcess = undefined;
});
}
if (!(0, fs_1.existsSync)(serverPath)) {
for (let retries = 0; retries < 10; retries++) {
await new Promise((res) => setTimeout(res, 200));
if ((0, fs_1.existsSync)(serverPath)) {
break;
}
}
if (!(0, fs_1.existsSync)(serverPath)) {
throw new Error(`Could not find server bundle at ${serverPath}.`);
}
}
this.devServerProcess = (0, node_child_process_1.fork)(serverPath);
process.on('exit', () => {
this.devServerProcess?.kill('SIGKILL');
});
process.on('SIGINT', () => {
this.devServerProcess?.kill('SIGKILL');
});
callback();
});
}
async setup(compiler) {
const projectGraph = (0, devkit_1.readCachedProjectGraph)();
const { projects: workspaceProjects } = (0, devkit_1.readProjectsConfigurationFromProjectGraph)(projectGraph);
const project = workspaceProjects[this._options.config.name];
if (!this._options.devServerConfig.pathToManifestFile) {
this._options.devServerConfig.pathToManifestFile =
(0, utils_1.getDynamicMfManifestFile)(project, devkit_1.workspaceRoot);
}
else {
const userPathToManifestFile = (0, path_1.join)(devkit_1.workspaceRoot, this._options.devServerConfig.pathToManifestFile);
if (!(0, fs_1.existsSync)(userPathToManifestFile)) {
throw new Error(`The provided Module Federation manifest file path does not exist. Please check the file exists at "${userPathToManifestFile}".`);
}
else if ((0, path_1.extname)(this._options.devServerConfig.pathToManifestFile) !== '.json') {
throw new Error(`The Module Federation manifest file must be a JSON. Please ensure the file at ${userPathToManifestFile} is a JSON.`);
}
this._options.devServerConfig.pathToManifestFile = userPathToManifestFile;
}
const { remotes, staticRemotePort } = (0, utils_1.getRemotes)(this._options.config, projectGraph, this._options.devServerConfig.pathToManifestFile);
this._options.devServerConfig.staticRemotesPort ??= staticRemotePort;
const remotesConfig = (0, utils_1.parseRemotesConfig)(remotes, devkit_1.workspaceRoot, projectGraph, true);
const staticRemotesConfig = await (0, utils_1.getStaticRemotes)(remotesConfig.config ?? {});
const devRemotes = remotes.filter((r) => !staticRemotesConfig[r]);
process.env.NX_MF_DEV_REMOTES = JSON.stringify([
...(devRemotes.length > 0 ? devRemotes : []),
project.name,
]);
return staticRemotesConfig ?? {};
}
}
exports.NxModuleFederationSSRDevServerPlugin = NxModuleFederationSSRDevServerPlugin;

View File

@@ -0,0 +1,4 @@
import { StaticRemoteConfig } from '../../utils';
import { NxModuleFederationDevServerConfig } from '../models';
export declare function buildStaticRemotes(staticRemotesConfig: Record<string, StaticRemoteConfig>, options: NxModuleFederationDevServerConfig, nxBin: string): Promise<Record<string, string>>;
//# sourceMappingURL=build-static-remotes.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"build-static-remotes.d.ts","sourceRoot":"","sources":["../../../../../../packages/module-federation/src/plugins/utils/build-static-remotes.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,iCAAiC,EAAE,MAAM,WAAW,CAAC;AAE9D,wBAAsB,kBAAkB,CACtC,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,EACvD,OAAO,EAAE,iCAAiC,EAC1C,KAAK,EAAE,MAAM,mCA2Ed"}

View File

@@ -0,0 +1,67 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.buildStaticRemotes = buildStaticRemotes;
const node_child_process_1 = require("node:child_process");
const path_1 = require("path");
const node_fs_1 = require("node:fs");
const cache_directory_1 = require("nx/src/utils/cache-directory");
const devkit_1 = require("@nx/devkit");
async function buildStaticRemotes(staticRemotesConfig, options, nxBin) {
const remotes = Object.keys(staticRemotesConfig);
if (!remotes.length) {
return;
}
const mappedLocationOfRemotes = {};
for (const app of remotes) {
mappedLocationOfRemotes[app] = `http${options.ssl ? 's' : ''}://${options.host ?? 'localhost'}:${options.staticRemotesPort}/${staticRemotesConfig[app].urlSegment}`;
}
await new Promise((res, rej) => {
console.log(`NX Building ${remotes.length} static remotes...`);
const staticProcess = (0, node_child_process_1.fork)(nxBin, [
'run-many',
`--target=build`,
`--projects=${remotes.join(',')}`,
...(options.parallel ? [`--parallel=${options.parallel}`] : []),
], {
cwd: devkit_1.workspaceRoot,
stdio: ['ignore', 'pipe', 'pipe', 'ipc'],
env: {
...process.env,
WEBPACK_SERVE: 'false',
},
});
// File to debug build failures e.g. 2024-01-01T00_00_0_0Z-build.log'
const remoteBuildLogFile = (0, path_1.join)(cache_directory_1.workspaceDataDirectory, `${new Date().toISOString().replace(/[:\.]/g, '_')}-build.log`);
const stdoutStream = (0, node_fs_1.createWriteStream)(remoteBuildLogFile);
staticProcess.stdout?.on('data', (data) => {
const ANSII_CODE_REGEX = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g;
const stdoutString = data.toString().replace(ANSII_CODE_REGEX, '');
stdoutStream.write(stdoutString);
// in addition to writing into the stdout stream, also show error directly in console
// so the error is easily discoverable. 'ERROR in' is the key word to search in webpack output.
if (stdoutString.includes('ERROR in')) {
console.log(stdoutString);
}
if (stdoutString.includes('Successfully ran target build')) {
staticProcess.stdout?.removeAllListeners('data');
console.info(`NX Built ${remotes.length} static remotes`);
res();
}
});
staticProcess.stderr?.on('data', (data) => console.log(data.toString()));
staticProcess.once('exit', (code) => {
stdoutStream.end();
staticProcess.stdout?.removeAllListeners('data');
staticProcess.stderr?.removeAllListeners('data');
if (code !== 0) {
rej(`Remote failed to start. A complete log can be found in: ${remoteBuildLogFile}`);
}
else {
res();
}
});
process.on('SIGTERM', () => staticProcess.kill('SIGTERM'));
process.on('exit', () => staticProcess.kill('SIGTERM'));
});
return mappedLocationOfRemotes;
}

View File

@@ -0,0 +1,3 @@
import { type ProjectConfiguration } from '@nx/devkit';
export declare function getDynamicMfManifestFile(project: ProjectConfiguration, workspaceRoot: string): string | undefined;
//# sourceMappingURL=get-dynamic-manifest-file.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"get-dynamic-manifest-file.d.ts","sourceRoot":"","sources":["../../../../../../packages/module-federation/src/plugins/utils/get-dynamic-manifest-file.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAKvD,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,oBAAoB,EAC7B,aAAa,EAAE,MAAM,GACpB,MAAM,GAAG,SAAS,CAepB"}

View File

@@ -0,0 +1,18 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getDynamicMfManifestFile = getDynamicMfManifestFile;
const ts_solution_setup_1 = require("@nx/js/src/utils/typescript/ts-solution-setup");
const fs_1 = require("fs");
const path_1 = require("path");
function getDynamicMfManifestFile(project, workspaceRoot) {
// {sourceRoot}/assets/module-federation.manifest.json was the generated
// path for the manifest file in the past. We now generate the manifest
// file at {root}/public/module-federation.manifest.json. This check
// ensures that we can still support the old path for backwards
// compatibility since old projects may still have the manifest file
// at the old path.
return [
(0, path_1.join)(workspaceRoot, project.root, 'public/module-federation.manifest.json'),
(0, path_1.join)(workspaceRoot, (0, ts_solution_setup_1.getProjectSourceRoot)(project), 'assets/module-federation.manifest.json'),
].find((path) => (0, fs_1.existsSync)(path));
}

View File

@@ -0,0 +1,8 @@
import { ProjectGraph } from '@nx/devkit';
import { ModuleFederationConfig } from '../../utils';
export declare function getRemotes(config: ModuleFederationConfig, projectGraph: ProjectGraph, pathToManifestFile?: string): {
remotes: string[];
remotePorts: any[];
staticRemotePort: number;
};
//# sourceMappingURL=get-remotes.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"get-remotes.d.ts","sourceRoot":"","sources":["../../../../../../packages/module-federation/src/plugins/utils/get-remotes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,YAAY,EAAiB,MAAM,YAAY,CAAC;AACjE,OAAO,EAA6B,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAIhF,wBAAgB,UAAU,CACxB,MAAM,EAAE,sBAAsB,EAC9B,YAAY,EAAE,YAAY,EAC1B,kBAAkB,CAAC,EAAE,MAAM;;;;EAoC5B"}

View File

@@ -0,0 +1,68 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getRemotes = getRemotes;
const devkit_1 = require("@nx/devkit");
const utils_1 = require("../../utils");
const fs_1 = require("fs");
const path_1 = require("path");
function getRemotes(config, projectGraph, pathToManifestFile) {
const collectedRemotes = new Set();
const { remotes, dynamicRemotes } = extractRemoteProjectsFromConfig(config, pathToManifestFile);
remotes.forEach((r) => collectRemoteProjects(r, collectedRemotes, projectGraph));
// With dynamic remotes, the manifest file may contain the names with `_` due to MF limitations on naming
// The project graph might contain these names with `-` rather than `_`. Check for both.
// This can occur after migration of existing remotes past Nx 19.8
let normalizedDynamicRemotes = dynamicRemotes.map((r) => {
if (projectGraph.nodes[r.replace(/_/g, '-')]) {
return r.replace(/_/g, '-');
}
return r;
});
const knownDynamicRemotes = normalizedDynamicRemotes.filter((r) => projectGraph.nodes[r]);
knownDynamicRemotes.forEach((r) => collectRemoteProjects(r, collectedRemotes, projectGraph));
const remotePorts = [...collectedRemotes, ...knownDynamicRemotes].map((r) => projectGraph.nodes[r].data.targets['serve'].options.port);
const staticRemotePort = Math.max(...[...remotePorts]) + 1;
return {
remotes: Array.from(collectedRemotes),
remotePorts,
staticRemotePort,
};
}
function extractRemoteProjectsFromConfig(config, pathToManifestFile) {
const remotes = [];
const dynamicRemotes = [];
if (pathToManifestFile && (0, fs_1.existsSync)(pathToManifestFile)) {
const moduleFederationManifestJson = (0, fs_1.readFileSync)(pathToManifestFile, 'utf-8');
if (moduleFederationManifestJson) {
/**
*
* This should have shape of
* {
* "remoteName": "remoteLocation",
* }
* But users might have their own, enforce only that the key is the remote name
*/
const parsedManifest = JSON.parse(moduleFederationManifestJson);
if (Object.keys(parsedManifest).every((key) => typeof key === 'string')) {
dynamicRemotes.push(...Object.keys(parsedManifest));
}
}
}
const staticRemotes = config.remotes?.map((r) => (Array.isArray(r) ? r[0] : r)) ?? [];
remotes.push(...staticRemotes);
return { remotes, dynamicRemotes };
}
function collectRemoteProjects(remote, collected, projectGraph) {
const remoteProject = projectGraph.nodes[remote]?.data;
if (!projectGraph.nodes[remote] || collected.has(remote)) {
return;
}
collected.add(remote);
const remoteProjectRoot = remoteProject.root;
let remoteProjectTsConfig = ['tsconfig.app.json', 'tsconfig.json']
.map((p) => (0, path_1.join)(devkit_1.workspaceRoot, remoteProjectRoot, p))
.find((p) => (0, fs_1.existsSync)(p));
const remoteProjectConfig = (0, utils_1.getModuleFederationConfig)(remoteProjectTsConfig, devkit_1.workspaceRoot, remoteProjectRoot);
const { remotes: remoteProjectRemotes } = extractRemoteProjectsFromConfig(remoteProjectConfig);
remoteProjectRemotes.forEach((r) => collectRemoteProjects(r, collected, projectGraph));
}

View File

@@ -0,0 +1,4 @@
import { StaticRemoteConfig } from '../../utils';
import { DevRemoteFindOptions } from '../models';
export declare function getStaticRemotes(remotesConfig: Record<string, StaticRemoteConfig>, devRemoteFindOptions?: DevRemoteFindOptions, host?: string): Promise<Record<string, StaticRemoteConfig>>;
//# sourceMappingURL=get-static-remotes.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"get-static-remotes.d.ts","sourceRoot":"","sources":["../../../../../../packages/module-federation/src/plugins/utils/get-static-remotes.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAEjD,wBAAsB,gBAAgB,CACpC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,EACjD,oBAAoB,CAAC,EAAE,oBAAoB,EAC3C,IAAI,GAAE,MAAoB,+CA8B3B"}

View File

@@ -0,0 +1,27 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getStaticRemotes = getStaticRemotes;
const wait_for_port_open_1 = require("@nx/web/src/utils/wait-for-port-open");
async function getStaticRemotes(remotesConfig, devRemoteFindOptions, host = '127.0.0.1') {
const remotes = Object.keys(remotesConfig);
const findStaticRemotesPromises = [];
for (const remote of remotes) {
findStaticRemotesPromises.push(new Promise((resolve, reject) => {
(0, wait_for_port_open_1.waitForPortOpen)(remotesConfig[remote].port, {
retries: devRemoteFindOptions?.retries ?? 3,
retryDelay: devRemoteFindOptions?.retryDelay ?? 1000,
host,
}).then((res) => {
resolve(undefined);
}, (rej) => {
resolve(remote);
});
}));
}
const staticRemoteNames = (await Promise.all(findStaticRemotesPromises)).filter(Boolean);
let staticRemotesConfig = {};
for (const remote of staticRemoteNames) {
staticRemotesConfig[remote] = remotesConfig[remote];
}
return staticRemotesConfig;
}

View File

@@ -0,0 +1,8 @@
export * from './build-static-remotes';
export * from './get-dynamic-manifest-file';
export * from './get-remotes';
export * from './get-static-remotes';
export * from './parse-remotes-config';
export * from './start-remote-proxies';
export * from './start-static-remotes-file-server';
//# sourceMappingURL=index.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../packages/module-federation/src/plugins/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,eAAe,CAAC;AAC9B,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,oCAAoC,CAAC"}

View File

@@ -0,0 +1,10 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
tslib_1.__exportStar(require("./build-static-remotes"), exports);
tslib_1.__exportStar(require("./get-dynamic-manifest-file"), exports);
tslib_1.__exportStar(require("./get-remotes"), exports);
tslib_1.__exportStar(require("./get-static-remotes"), exports);
tslib_1.__exportStar(require("./parse-remotes-config"), exports);
tslib_1.__exportStar(require("./start-remote-proxies"), exports);
tslib_1.__exportStar(require("./start-static-remotes-file-server"), exports);

View File

@@ -0,0 +1,7 @@
import { ProjectGraph } from '@nx/devkit';
import { StaticRemoteConfig } from '../../utils';
export declare function parseRemotesConfig(remotes: string[] | undefined, workspaceRoot: string, projectGraph: ProjectGraph, isServer?: boolean): {
remotes: string[];
config: Record<string, StaticRemoteConfig>;
};
//# sourceMappingURL=parse-remotes-config.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"parse-remotes-config.d.ts","sourceRoot":"","sources":["../../../../../../packages/module-federation/src/plugins/utils/parse-remotes-config.ts"],"names":[],"mappings":"AAEA,OAAO,EAAqB,YAAY,EAAE,MAAM,YAAY,CAAC;AAC7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEjD,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,EAAE,GAAG,SAAS,EAC7B,aAAa,EAAE,MAAM,EACrB,YAAY,EAAE,YAAY,EAC1B,QAAQ,CAAC,EAAE,OAAO;;;EAmCnB"}

View File

@@ -0,0 +1,35 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseRemotesConfig = parseRemotesConfig;
const path_1 = require("path");
const devkit_internals_1 = require("nx/src/devkit-internals");
const devkit_1 = require("@nx/devkit");
function parseRemotesConfig(remotes, workspaceRoot, projectGraph, isServer) {
if (!remotes?.length) {
return { remotes: [], config: undefined };
}
const config = {};
for (const app of remotes) {
const projectRoot = projectGraph.nodes[app].data.root;
let outputPath = (0, devkit_internals_1.interpolate)(projectGraph.nodes[app].data.targets?.['build']?.options?.outputPath ??
projectGraph.nodes[app].data.targets?.['build']?.outputs?.[0] ??
`${workspaceRoot ? `${workspaceRoot}/` : ''}${projectGraph.nodes[app].data.root}/dist`, {
projectName: projectGraph.nodes[app].data.name,
projectRoot,
workspaceRoot,
});
if (!outputPath.startsWith(workspaceRoot)) {
outputPath = (0, devkit_1.joinPathFragments)(workspaceRoot, outputPath);
}
const basePath = (0, path_1.dirname)(outputPath);
const urlSegment = app;
const port = projectGraph.nodes[app].data.targets?.['serve']?.options.port;
config[app] = {
basePath,
outputPath: isServer ? (0, path_1.dirname)(outputPath) : outputPath,
urlSegment,
port,
};
}
return { remotes, config };
}

View File

@@ -0,0 +1,6 @@
import { StaticRemoteConfig } from '../../utils';
export declare function startRemoteProxies(staticRemotesConfig: Record<string, StaticRemoteConfig>, mappedLocationsOfRemotes: Record<string, string>, sslOptions?: {
pathToCert: string;
pathToKey: string;
}, isServer?: boolean, host?: string): Promise<void>;
//# sourceMappingURL=start-remote-proxies.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"start-remote-proxies.d.ts","sourceRoot":"","sources":["../../../../../../packages/module-federation/src/plugins/utils/start-remote-proxies.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAe,MAAM,aAAa,CAAC;AAI9D,wBAAsB,kBAAkB,CACtC,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,EACvD,wBAAwB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAChD,UAAU,CAAC,EAAE;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB,EACD,QAAQ,CAAC,EAAE,OAAO,EAClB,IAAI,GAAE,MAAoB,iBAwE3B"}

View File

@@ -0,0 +1,65 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.startRemoteProxies = startRemoteProxies;
const utils_1 = require("../../utils");
const fs_1 = require("fs");
async function startRemoteProxies(staticRemotesConfig, mappedLocationsOfRemotes, sslOptions, isServer, host = '127.0.0.1') {
const { createProxyMiddleware } = require('http-proxy-middleware');
const express = require('express');
let sslCert;
let sslKey;
if (sslOptions && sslOptions.pathToCert && sslOptions.pathToKey) {
if ((0, fs_1.existsSync)(sslOptions.pathToCert) && (0, fs_1.existsSync)(sslOptions.pathToKey)) {
sslCert = (0, fs_1.readFileSync)(sslOptions.pathToCert);
sslKey = (0, fs_1.readFileSync)(sslOptions.pathToKey);
}
else {
console.warn(`Encountered SSL options in project.json, however, the certificate files do not exist in the filesystem. Using http.`);
console.warn(`Attempted to find '${sslOptions.pathToCert}' and '${sslOptions.pathToKey}'.`);
}
}
const http = require('http');
const https = require('https');
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 (0, utils_1.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();
expressProxy.use(createProxyMiddleware({
target: mappedLocationsOfRemotes[app],
changeOrigin: true,
secure: sslCert ? false : undefined,
pathRewrite: isServer
? (path) => {
if (path.includes('/server')) {
return path;
}
else {
return `browser/${path}`;
}
}
: undefined,
}));
const proxyServer = (sslCert ? https : http)
.createServer({ cert: sslCert, key: sslKey }, expressProxy)
.listen(appConfig.port);
process.on('SIGTERM', () => proxyServer.close());
process.on('exit', () => proxyServer.close());
startedProxies++;
}
if (skippedProxies > 0) {
console.info(`NX Static remotes proxies: started ${startedProxies}, skipped ${skippedProxies} (already running)`);
}
else {
console.info(`NX Static remotes proxies started successfully`);
}
}

View File

@@ -0,0 +1,3 @@
import { StaticRemoteConfig } from '../../utils';
export declare function startStaticRemotesFileServer(staticRemotesConfig: Record<string, StaticRemoteConfig>, root: string, staticRemotesPort: number): void;
//# sourceMappingURL=start-static-remotes-file-server.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"start-static-remotes-file-server.d.ts","sourceRoot":"","sources":["../../../../../../packages/module-federation/src/plugins/utils/start-static-remotes-file-server.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAIjD,wBAAgB,4BAA4B,CAC1C,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,EACvD,IAAI,EAAE,MAAM,EACZ,iBAAiB,EAAE,MAAM,QAoD1B"}

View File

@@ -0,0 +1,43 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.startStaticRemotesFileServer = startStaticRemotesFileServer;
const path_1 = require("path");
const fs_1 = require("fs");
const node_child_process_1 = require("node:child_process");
const devkit_1 = require("@nx/devkit");
const devkit_internals_1 = require("nx/src/devkit-internals");
function startStaticRemotesFileServer(staticRemotesConfig, root, staticRemotesPort) {
const remotes = Object.keys(staticRemotesConfig);
if (!remotes || remotes.length === 0) {
return;
}
let shouldMoveToCommonLocation = false;
const commonOutputDirectory = (0, path_1.join)(devkit_1.workspaceRoot, 'tmp/static-remotes');
for (const app of remotes) {
const remoteConfig = staticRemotesConfig[app];
if (remoteConfig) {
(0, fs_1.cpSync)(remoteConfig.outputPath, (0, path_1.join)(commonOutputDirectory, remoteConfig.urlSegment), {
force: true,
recursive: true,
});
}
}
const { path: pathToHttpServerPkgJson, packageJson } = (0, devkit_internals_1.readModulePackageJson)('http-server', module.paths);
const pathToHttpServerBin = packageJson.bin['http-server'];
const pathToHttpServer = (0, path_1.resolve)(pathToHttpServerPkgJson.replace('package.json', ''), pathToHttpServerBin);
const httpServerProcess = (0, node_child_process_1.fork)(pathToHttpServer, [
commonOutputDirectory,
`-p=${staticRemotesPort}`,
`-a=localhost`,
`--cors`,
], {
stdio: 'pipe',
cwd: root,
env: {
FORCE_COLOR: 'true',
...process.env,
},
});
process.on('SIGTERM', () => httpServerProcess.kill('SIGTERM'));
process.on('exit', () => httpServerProcess.kill('SIGTERM'));
}

View File

@@ -0,0 +1,7 @@
import type { ProjectGraph } from '@nx/devkit';
import type { WorkspaceLibrary } from './models';
export declare function getDependentPackagesForProject(projectGraph: ProjectGraph, name: string): {
workspaceLibraries: WorkspaceLibrary[];
npmPackages: string[];
};
//# sourceMappingURL=dependencies.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"dependencies.d.ts","sourceRoot":"","sources":["../../../../../packages/module-federation/src/utils/dependencies.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAM/C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAGjD,wBAAgB,8BAA8B,CAC5C,YAAY,EAAE,YAAY,EAC1B,IAAI,EAAE,MAAM,GACX;IACD,kBAAkB,EAAE,gBAAgB,EAAE,CAAC;IACvC,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB,CAUA"}

View File

@@ -0,0 +1,64 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getDependentPackagesForProject = getDependentPackagesForProject;
const devkit_1 = require("@nx/devkit");
const ts_solution_setup_1 = require("@nx/js/src/utils/typescript/ts-solution-setup");
const typescript_1 = require("./typescript");
function getDependentPackagesForProject(projectGraph, name) {
const { npmPackages, workspaceLibraries } = collectDependencies(projectGraph, name);
return {
workspaceLibraries: [...workspaceLibraries.values()],
npmPackages: [...npmPackages],
};
}
function collectDependencies(projectGraph, name, dependencies = {
workspaceLibraries: new Map(),
npmPackages: new Set(),
}, seen = new Set()) {
if (seen.has(name)) {
return dependencies;
}
seen.add(name);
(projectGraph.dependencies[name] ?? []).forEach((dependency) => {
if (dependency.target.startsWith('npm:')) {
dependencies.npmPackages.add(dependency.target.replace('npm:', ''));
}
else if (!dependency.target.includes(':')) {
// Only process as workspace library if it's not an external node.
// External nodes have prefixes like 'npm:', 'cargo:', etc.
if (projectGraph.nodes[dependency.target]) {
dependencies.workspaceLibraries.set(dependency.target, {
name: dependency.target,
root: projectGraph.nodes[dependency.target].data.root,
importKey: getLibraryImportPath(dependency.target, projectGraph),
});
collectDependencies(projectGraph, dependency.target, dependencies, seen);
}
}
// Skip other external node types (cargo:, etc.)
});
return dependencies;
}
function getLibraryImportPath(library, projectGraph) {
let buildLibsFromSource = true;
if (process.env.NX_BUILD_LIBS_FROM_SOURCE) {
buildLibsFromSource = process.env.NX_BUILD_LIBS_FROM_SOURCE === 'true';
}
const libraryNode = projectGraph.nodes[library];
let sourceRoots = [(0, ts_solution_setup_1.getProjectSourceRoot)(libraryNode.data)];
if (!buildLibsFromSource && process.env.NX_BUILD_TARGET) {
const buildTarget = (0, devkit_1.parseTargetString)(process.env.NX_BUILD_TARGET, projectGraph);
sourceRoots = (0, devkit_1.getOutputsForTargetAndConfiguration)(buildTarget, {}, libraryNode);
}
const tsConfigPathMappings = (0, typescript_1.readTsPathMappings)();
for (const [key, value] of Object.entries(tsConfigPathMappings)) {
for (const src of sourceRoots) {
if (value.find((path) => path.startsWith(src))) {
return key;
}
}
}
// Return library name if not found in TS path mappings
// This supports TS Solution + PM Workspaces where libs use package.json instead
return library;
}

View File

@@ -0,0 +1,3 @@
import type { ProjectGraph } from '@nx/devkit';
export declare function isReactProject(projectName: string, projectGraph: ProjectGraph): boolean;
//# sourceMappingURL=framework-detection.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"framework-detection.d.ts","sourceRoot":"","sources":["../../../../../packages/module-federation/src/utils/framework-detection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAG/C,wBAAgB,cAAc,CAC5B,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,YAAY,GACzB,OAAO,CAsBT"}

View File

@@ -0,0 +1,20 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isReactProject = isReactProject;
const dependencies_1 = require("./dependencies");
function isReactProject(projectName, projectGraph) {
const project = projectGraph.nodes[projectName];
if (!project)
return false;
// Check if the project has React dependencies
const { npmPackages } = (0, dependencies_1.getDependentPackagesForProject)(projectGraph, projectName);
// Check for React-related packages
const reactPackages = [
'react',
'react-dom',
'@types/react',
'@types/react-dom',
];
const hasReactDependencies = reactPackages.some((pkg) => npmPackages.includes(pkg));
return hasReactDependencies;
}

View File

@@ -0,0 +1,18 @@
import { type ProjectConfiguration, type ProjectGraph } from '@nx/devkit';
import { ModuleFederationConfig } from './models';
interface ModuleFederationExecutorContext {
projectName: string;
projectGraph: ProjectGraph;
root: string;
}
export declare function getBuildTargetNameFromMFDevServer(projectConfig: ProjectConfiguration, projectGraph: ProjectGraph): string;
export declare function getRemotes(devRemotes: string[], skipRemotes: string[], config: ModuleFederationConfig, context: ModuleFederationExecutorContext, pathToManifestFile?: string): {
staticRemotes: string[];
devRemotes: any[];
dynamicRemotes: any[];
remotePorts: number[];
staticRemotePort: number;
};
export declare function getModuleFederationConfig(tsconfigPath: string | undefined, workspaceRoot: string, projectRoot: string, pluginName?: 'react' | 'angular'): any;
export {};
//# sourceMappingURL=get-remotes-for-host.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"get-remotes-for-host.d.ts","sourceRoot":"","sources":["../../../../../packages/module-federation/src/utils/get-remotes-for-host.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,oBAAoB,EACzB,KAAK,YAAY,EAElB,MAAM,YAAY,CAAC;AAMpB,OAAO,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AAElD,UAAU,+BAA+B;IACvC,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,YAAY,CAAC;IAC3B,IAAI,EAAE,MAAM,CAAC;CACd;AAsCD,wBAAgB,iCAAiC,CAC/C,aAAa,EAAE,oBAAoB,EACnC,YAAY,EAAE,YAAY,UA0B3B;AAoCD,wBAAgB,UAAU,CACxB,UAAU,EAAE,MAAM,EAAE,EACpB,WAAW,EAAE,MAAM,EAAE,EACrB,MAAM,EAAE,sBAAsB,EAC9B,OAAO,EAAE,+BAA+B,EACxC,kBAAkB,CAAC,EAAE,MAAM;;;;;;EA0F5B;AAED,wBAAgB,yBAAyB,CACvC,YAAY,EAAE,MAAM,GAAG,SAAS,EAChC,aAAa,EAAE,MAAM,EACrB,WAAW,EAAE,MAAM,EACnB,UAAU,GAAE,OAAO,GAAG,SAAmB,OAkD1C"}

View File

@@ -0,0 +1,155 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getBuildTargetNameFromMFDevServer = getBuildTargetNameFromMFDevServer;
exports.getRemotes = getRemotes;
exports.getModuleFederationConfig = getModuleFederationConfig;
const tslib_1 = require("tslib");
const devkit_1 = require("@nx/devkit");
const internal_1 = require("@nx/js/src/internal");
const find_matching_projects_1 = require("nx/src/utils/find-matching-projects");
const pc = tslib_1.__importStar(require("picocolors"));
const path_1 = require("path");
const fs_1 = require("fs");
function extractRemoteProjectsFromConfig(config, pathToManifestFile) {
const remotes = [];
const dynamicRemotes = [];
if (pathToManifestFile && (0, fs_1.existsSync)(pathToManifestFile)) {
const moduleFederationManifestJson = (0, fs_1.readFileSync)(pathToManifestFile, 'utf-8');
if (moduleFederationManifestJson) {
/**
*
* This should have shape of
* {
* "remoteName": "remoteLocation",
* }
* But users might have their own, enforce only that the key is the remote name
*/
const parsedManifest = JSON.parse(moduleFederationManifestJson);
// Get keys once instead of calling Object.keys twice
const manifestKeys = Object.keys(parsedManifest);
if (manifestKeys.every((key) => typeof key === 'string')) {
dynamicRemotes.push(...manifestKeys);
}
}
}
const staticRemotes = config.remotes?.map((r) => (Array.isArray(r) ? r[0] : r)) ?? [];
remotes.push(...staticRemotes);
return { remotes, dynamicRemotes };
}
// Find the target that uses the module-federation-dev-server executor
function getBuildTargetNameFromMFDevServer(projectConfig, projectGraph) {
if (projectConfig.targets) {
for (const [targetKey, targetConfig] of Object.entries(projectConfig.targets)) {
const executor = targetConfig.executor || '';
// Extract the portion after the `:` in the executor name
const executorParts = executor.split(':');
const executorName = executorParts.length > 1 ? executorParts[1] : executor;
if (executorName === 'module-federation-dev-server') {
// Extract the buildTarget from the options
if (targetConfig.options?.buildTarget) {
const parsedTarget = (0, devkit_1.parseTargetString)(targetConfig.options.buildTarget, projectGraph);
return parsedTarget.target;
}
}
}
}
return 'build';
}
function collectRemoteProjects(remote, collected, context) {
const remoteProject = context.projectGraph.nodes[remote]?.data;
if (!context.projectGraph.nodes[remote] || collected.has(remote)) {
return;
}
collected.add(remote);
const remoteProjectRoot = remoteProject.root;
const buildTargetName = getBuildTargetNameFromMFDevServer(remoteProject, context.projectGraph);
let remoteProjectTsConfig = remoteProject.targets?.[buildTargetName]?.options?.tsConfig;
const remoteProjectConfig = getModuleFederationConfig(remoteProjectTsConfig, context.root, remoteProjectRoot);
const { remotes: remoteProjectRemotes } = extractRemoteProjectsFromConfig(remoteProjectConfig);
remoteProjectRemotes.forEach((r) => collectRemoteProjects(r, collected, context));
}
function getRemotes(devRemotes, skipRemotes, config, context, pathToManifestFile) {
const collectedRemotes = new Set();
const { remotes, dynamicRemotes } = extractRemoteProjectsFromConfig(config, pathToManifestFile);
remotes.forEach((r) => collectRemoteProjects(r, collectedRemotes, context));
const remotesToSkip = new Set((0, find_matching_projects_1.findMatchingProjects)(skipRemotes, context.projectGraph.nodes) ?? []);
if (remotesToSkip.size > 0) {
devkit_1.logger.info(`Remotes not served automatically: ${[...remotesToSkip.values()].join(', ')}`);
}
const knownRemotes = Array.from(collectedRemotes).filter((r) => !remotesToSkip.has(r));
// With dynamic remotes, the manifest file may contain the names with `_` due to MF limitations on naming
// The project graph might contain these names with `-` rather than `_`. Check for both.
// This can occur after migration of existing remotes past Nx 19.8
const normalizedDynamicRemotes = dynamicRemotes.map((r) => {
// Compute replacement once instead of twice
const normalizedName = r.replace(/_/g, '-');
return context.projectGraph.nodes[normalizedName] ? normalizedName : r;
});
const knownDynamicRemotes = normalizedDynamicRemotes.filter((r) => !remotesToSkip.has(r) && context.projectGraph.nodes[r]);
devkit_1.logger.info(`NX Starting module federation dev-server for ${pc.bold(context.projectName)} with ${[...knownRemotes, ...knownDynamicRemotes].length} remotes`);
// Normalize devRemotes to array and call findMatchingProjects once
const devServeApps = new Set(!devRemotes
? []
: (0, find_matching_projects_1.findMatchingProjects)(Array.isArray(devRemotes) ? devRemotes : [devRemotes], context.projectGraph.nodes));
const staticRemotes = knownRemotes.filter((r) => !devServeApps.has(r));
const devServeRemotes = [...knownRemotes, ...knownDynamicRemotes].filter((r) => devServeApps.has(r));
const staticDynamicRemotes = knownDynamicRemotes.filter((r) => !devServeApps.has(r));
// Helper to get port from remote project
const getRemotePort = (r) => context.projectGraph.nodes[r].data.targets['serve'].options.port;
// Collect ports for dev-served remotes (used in return value)
const remotePorts = [...devServeRemotes, ...staticDynamicRemotes].map(getRemotePort);
// Calculate max port in a single pass instead of creating intermediate arrays
let maxPort = -Infinity;
for (const port of remotePorts) {
if (port > maxPort)
maxPort = port;
}
for (const r of staticRemotes) {
const port = getRemotePort(r);
if (port > maxPort)
maxPort = port;
}
const staticRemotePort = staticRemotes.length === 0 && remotePorts.length === 0
? undefined
: maxPort + (remotesToSkip.size + 1);
return {
staticRemotes,
devRemotes: devServeRemotes,
dynamicRemotes: staticDynamicRemotes,
remotePorts,
staticRemotePort,
};
}
function getModuleFederationConfig(tsconfigPath, workspaceRoot, projectRoot, pluginName = 'react') {
const moduleFederationConfigPathJS = (0, path_1.join)(workspaceRoot, projectRoot, 'module-federation.config.js');
const moduleFederationConfigPathTS = (0, path_1.join)(workspaceRoot, projectRoot, 'module-federation.config.ts');
let moduleFederationConfigPath = moduleFederationConfigPathJS;
tsconfigPath =
tsconfigPath ??
[
(0, path_1.join)(projectRoot, 'tsconfig.app.json'),
(0, path_1.join)(projectRoot, 'tsconfig.json'),
(0, path_1.join)(workspaceRoot, 'tsconfig.json'),
(0, path_1.join)(workspaceRoot, 'tsconfig.base.json'),
].find((p) => (0, fs_1.existsSync)(p));
if (!tsconfigPath) {
throw new Error(`Could not find a tsconfig for remote project located at ${projectRoot}. Please add a tsconfig.app.json or tsconfig.json to the project.`);
}
// create a no-op so this can be called with issue
const fullTSconfigPath = tsconfigPath.startsWith(workspaceRoot)
? tsconfigPath
: (0, path_1.join)(workspaceRoot, tsconfigPath);
let cleanupTranspiler = () => { };
if ((0, fs_1.existsSync)(moduleFederationConfigPathTS)) {
cleanupTranspiler = (0, internal_1.registerTsProject)(fullTSconfigPath);
moduleFederationConfigPath = moduleFederationConfigPathTS;
}
try {
const config = require(moduleFederationConfigPath);
cleanupTranspiler();
return config.default || config;
}
catch {
throw new Error(`Could not load ${moduleFederationConfigPath}. Was this project generated with "@nx/${pluginName}:host"?\nSee: https://nx.dev/concepts/more-concepts/faster-builds-with-module-federation`);
}
}

View File

@@ -0,0 +1,12 @@
export * from './share';
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 './port-utils';
export * from './start-remote-proxies';
export * from './start-ssr-remote-proxies';
//# sourceMappingURL=index.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../packages/module-federation/src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AACzB,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AACvC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,cAAc,CAAC;AAC7B,cAAc,wBAAwB,CAAC;AACvC,cAAc,4BAA4B,CAAC"}

14
node_modules/@nx/module-federation/src/utils/index.js generated vendored Normal file
View File

@@ -0,0 +1,14 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
tslib_1.__exportStar(require("./share"), exports);
tslib_1.__exportStar(require("./dependencies"), exports);
tslib_1.__exportStar(require("./package-json"), exports);
tslib_1.__exportStar(require("./remotes"), exports);
tslib_1.__exportStar(require("./models"), exports);
tslib_1.__exportStar(require("./normalize-project-name"), exports);
tslib_1.__exportStar(require("./get-remotes-for-host"), exports);
tslib_1.__exportStar(require("./parse-static-remotes-config"), exports);
tslib_1.__exportStar(require("./port-utils"), exports);
tslib_1.__exportStar(require("./start-remote-proxies"), exports);
tslib_1.__exportStar(require("./start-ssr-remote-proxies"), exports);

View File

@@ -0,0 +1,48 @@
import type { moduleFederationPlugin } from '@module-federation/sdk';
import { NormalModuleReplacementPlugin as RspackNormalModuleReplacementPlugin } from '@rspack/core';
export type ModuleFederationLibrary = {
type: string;
name: string;
};
export type WorkspaceLibrary = {
name: string;
root: string;
importKey: string | undefined;
};
export type SharedWorkspaceLibraryConfig = {
getAliases: () => Record<string, string>;
getLibraries: (projectRoot: string, eager?: boolean) => Record<string, SharedLibraryConfig>;
getReplacementPlugin: () => InstanceType<typeof RspackNormalModuleReplacementPlugin> | import('webpack').NormalModuleReplacementPlugin;
};
export type Remotes = Array<string | [remoteName: string, remoteUrl: string]>;
export interface SharedLibraryConfig {
singleton?: boolean;
strictVersion?: boolean;
requiredVersion?: false | string;
eager?: boolean;
}
export type SharedFunction = (libraryName: string, sharedConfig: SharedLibraryConfig) => undefined | false | SharedLibraryConfig;
export type AdditionalSharedConfig = Array<string | [libraryName: string, sharedConfig: SharedLibraryConfig] | {
libraryName: string;
sharedConfig: SharedLibraryConfig;
}>;
export interface ModuleFederationConfig {
name: string;
remotes?: Remotes;
library?: ModuleFederationLibrary;
exposes?: Record<string, string>;
shared?: SharedFunction;
additionalShared?: AdditionalSharedConfig;
/**
* `nxRuntimeLibraryControlPlugin` is a runtime module federation plugin to ensure
* that shared libraries are resolved from a remote with live reload capabilities.
* If you run into any issues with loading shared libraries, try disabling this option.
*/
disableNxRuntimeLibraryControlPlugin?: boolean;
}
export type NxModuleFederationConfigOverride = Omit<moduleFederationPlugin.ModuleFederationPluginOptions, 'exposes' | 'remotes' | 'name' | 'shared' | 'filename'>;
export type WorkspaceLibrarySecondaryEntryPoint = {
name: string;
path: string;
};
//# sourceMappingURL=index.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../packages/module-federation/src/utils/models/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AACrE,OAAO,EAAE,6BAA6B,IAAI,mCAAmC,EAAE,MAAM,cAAc,CAAC;AAEpG,MAAM,MAAM,uBAAuB,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAErE,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;CAC/B,CAAC;AAEF,MAAM,MAAM,4BAA4B,GAAG;IACzC,UAAU,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC,YAAY,EAAE,CACZ,WAAW,EAAE,MAAM,EACnB,KAAK,CAAC,EAAE,OAAO,KACZ,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;IACzC,oBAAoB,EAAE,MAClB,YAAY,CAAC,OAAO,mCAAmC,CAAC,GACxD,OAAO,SAAS,EAAE,6BAA6B,CAAC;CACrD,CAAC;AAEF,MAAM,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC;AAE9E,MAAM,WAAW,mBAAmB;IAClC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,eAAe,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;IACjC,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,MAAM,cAAc,GAAG,CAC3B,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,mBAAmB,KAC9B,SAAS,GAAG,KAAK,GAAG,mBAAmB,CAAC;AAE7C,MAAM,MAAM,sBAAsB,GAAG,KAAK,CACtC,MAAM,GACN,CAAC,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,mBAAmB,CAAC,GACxD;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,mBAAmB,CAAA;CAAE,CAC7D,CAAC;AAEF,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,uBAAuB,CAAC;IAClC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,gBAAgB,CAAC,EAAE,sBAAsB,CAAC;IAC1C;;;;OAIG;IACH,oCAAoC,CAAC,EAAE,OAAO,CAAC;CAChD;AAED,MAAM,MAAM,gCAAgC,GAAG,IAAI,CACjD,sBAAsB,CAAC,6BAA6B,EACpD,SAAS,GAAG,SAAS,GAAG,MAAM,GAAG,QAAQ,GAAG,UAAU,CACvD,CAAC;AAEF,MAAM,MAAM,mCAAmC,GAAG;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd,CAAC"}

View File

@@ -0,0 +1,2 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });

View File

@@ -0,0 +1,58 @@
import { ProjectGraph } from '@nx/devkit';
import { ModuleFederationConfig, SharedLibraryConfig, shareWorkspaceLibraries } from './index';
/**
* Configuration options for module federation config generation.
*/
export interface ModuleFederationConfigOptions {
/** Whether this is for server-side rendering */
isServer?: boolean;
/** Custom function to determine remote URLs */
determineRemoteUrl?: (remote: string) => string;
}
/**
* Framework-specific configuration for module federation.
*/
export interface FrameworkConfig {
/** Bundler type affects shared library config */
bundler: 'webpack' | 'rspack';
/** Remote entry file extension */
remoteEntryExt: 'js' | 'mjs';
/** Whether to pass true as 4th param to mapRemotes */
mapRemotesExpose?: boolean;
/** Function to apply eager packages for this framework */
applyEagerPackages?: (sharedConfig: Record<string, SharedLibraryConfig>, projectGraph: ProjectGraph, projectName: string) => void;
/** Default npm packages to always share */
defaultPackagesToShare?: string[];
/** npm packages to exclude from sharing */
packagesToAvoid?: string[];
}
/**
* Result of getModuleFederationConfig
*/
export interface ModuleFederationConfigResult {
sharedLibraries: ReturnType<typeof shareWorkspaceLibraries>;
sharedDependencies: Record<string, SharedLibraryConfig>;
mappedRemotes: Record<string, string>;
}
/**
* Creates a default remote URL resolver function.
* This is extracted to avoid code duplication across bundler utils.
*/
declare function createDefaultRemoteUrlResolver(isServer?: boolean, remoteEntryExt?: 'js' | 'mjs'): (remote: string) => string;
/**
* Async version - tries cached graph first, falls back to creating new one.
* Used by webpack and angular async configs.
*/
export declare function getModuleFederationConfigAsync(mfConfig: ModuleFederationConfig, options: ModuleFederationConfigOptions, frameworkConfig: FrameworkConfig): Promise<ModuleFederationConfigResult>;
/**
* Sync version - only uses cached graph.
* Used by rspack and angular sync configs.
*/
export declare function getModuleFederationConfigSync(mfConfig: ModuleFederationConfig, options: ModuleFederationConfigOptions, frameworkConfig: FrameworkConfig): ModuleFederationConfigResult;
/**
* Clears the static remotes env cache.
* Useful for testing or when the env variable changes.
*/
export declare function clearStaticRemotesEnvCache(): void;
export { createDefaultRemoteUrlResolver };
//# sourceMappingURL=module-federation-config.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"module-federation-config.d.ts","sourceRoot":"","sources":["../../../../../packages/module-federation/src/utils/module-federation-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,YAAY,EAEb,MAAM,YAAY,CAAC;AACpB,OAAO,EAML,sBAAsB,EACtB,mBAAmB,EAEnB,uBAAuB,EACxB,MAAM,SAAS,CAAC;AAEjB;;GAEG;AACH,MAAM,WAAW,6BAA6B;IAC5C,gDAAgD;IAChD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,+CAA+C;IAC/C,kBAAkB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,CAAC;CACjD;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,iDAAiD;IACjD,OAAO,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC9B,kCAAkC;IAClC,cAAc,EAAE,IAAI,GAAG,KAAK,CAAC;IAC7B,sDAAsD;IACtD,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,0DAA0D;IAC1D,kBAAkB,CAAC,EAAE,CACnB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,EACjD,YAAY,EAAE,YAAY,EAC1B,WAAW,EAAE,MAAM,KAChB,IAAI,CAAC;IACV,2CAA2C;IAC3C,sBAAsB,CAAC,EAAE,MAAM,EAAE,CAAC;IAClC,2CAA2C;IAC3C,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,4BAA4B;IAC3C,eAAe,EAAE,UAAU,CAAC,OAAO,uBAAuB,CAAC,CAAC;IAC5D,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;IACxD,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACvC;AAmID;;;GAGG;AACH,iBAAS,8BAA8B,CACrC,QAAQ,GAAE,OAAe,EACzB,cAAc,GAAE,IAAI,GAAG,KAAY,GAClC,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,CAwC5B;AAED;;;GAGG;AACH,wBAAsB,8BAA8B,CAClD,QAAQ,EAAE,sBAAsB,EAChC,OAAO,EAAE,6BAAkC,EAC3C,eAAe,EAAE,eAAe,GAC/B,OAAO,CAAC,4BAA4B,CAAC,CAcvC;AAED;;;GAGG;AACH,wBAAgB,6BAA6B,CAC3C,QAAQ,EAAE,sBAAsB,EAChC,OAAO,EAAE,6BAAkC,EAC3C,eAAe,EAAE,eAAe,GAC/B,4BAA4B,CAQ9B;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,IAAI,IAAI,CAGjD;AAGD,OAAO,EAAE,8BAA8B,EAAE,CAAC"}

View File

@@ -0,0 +1,143 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getModuleFederationConfigAsync = getModuleFederationConfigAsync;
exports.getModuleFederationConfigSync = getModuleFederationConfigSync;
exports.clearStaticRemotesEnvCache = clearStaticRemotesEnvCache;
exports.createDefaultRemoteUrlResolver = createDefaultRemoteUrlResolver;
const devkit_1 = require("@nx/devkit");
const index_1 = require("./index");
/**
* Core implementation for generating module federation configuration.
* This is used by webpack, rspack, and angular utils.
*
* @param mfConfig - Module federation configuration
* @param options - Configuration options
* @param frameworkConfig - Framework-specific configuration
* @param projectGraph - The Nx project graph
*/
function buildModuleFederationConfig(mfConfig, options, frameworkConfig, projectGraph) {
const { bundler, remoteEntryExt, mapRemotesExpose, applyEagerPackages, defaultPackagesToShare = [], packagesToAvoid = [], } = frameworkConfig;
const project = projectGraph.nodes[mfConfig.name]?.data;
if (!project) {
throw Error(`Cannot find project "${mfConfig.name}". Check that the name is correct in module-federation.config.js`);
}
const dependencies = (0, index_1.getDependentPackagesForProject)(projectGraph, mfConfig.name);
// Filter dependencies if shared function provided
if (mfConfig.shared) {
dependencies.workspaceLibraries = dependencies.workspaceLibraries.filter((lib) => mfConfig.shared(lib.importKey, {}) !== false);
dependencies.npmPackages = dependencies.npmPackages.filter((pkg) => mfConfig.shared(pkg, {}) !== false);
}
const sharedLibraries = (0, index_1.shareWorkspaceLibraries)(dependencies.workspaceLibraries, undefined, bundler);
// Build npm packages list with framework-specific defaults
let npmPackagesList = dependencies.npmPackages;
if (defaultPackagesToShare.length > 0 || packagesToAvoid.length > 0) {
npmPackagesList = Array.from(new Set([
...defaultPackagesToShare,
...dependencies.npmPackages.filter((pkg) => !packagesToAvoid.includes(pkg)),
]));
}
const npmPackages = (0, index_1.sharePackages)(npmPackagesList);
// Remove packages to avoid from final config
for (const pkgName of packagesToAvoid) {
if (pkgName in npmPackages) {
delete npmPackages[pkgName];
}
}
const sharedDependencies = {
...sharedLibraries.getLibraries(project.root),
...npmPackages,
};
// Apply framework-specific eager packages
if (applyEagerPackages) {
applyEagerPackages(sharedDependencies, projectGraph, mfConfig.name);
}
(0, index_1.applySharedFunction)(sharedDependencies, mfConfig.shared);
(0, index_1.applyAdditionalShared)(sharedDependencies, mfConfig.additionalShared, projectGraph);
// Map remotes
const mapRemotesFunction = options.isServer ? index_1.mapRemotesForSSR : index_1.mapRemotes;
let mappedRemotes = {};
if (mfConfig.remotes && mfConfig.remotes.length > 0) {
const determineRemoteUrlFn = options.determineRemoteUrl ||
createDefaultRemoteUrlResolver(options.isServer, remoteEntryExt);
mappedRemotes = mapRemotesFunction(mfConfig.remotes, remoteEntryExt, determineRemoteUrlFn, mapRemotesExpose);
}
return { sharedLibraries, sharedDependencies, mappedRemotes };
}
// Cache for parsed static remotes env variable
let cachedStaticRemotesEnv = undefined;
let cachedStaticRemotesMap = undefined;
/**
* Gets static remotes from env with caching.
* Invalidates cache if env variable changes.
*/
function getStaticRemotesFromEnv() {
const currentEnv = process.env.NX_MF_DEV_SERVER_STATIC_REMOTES;
if (currentEnv !== cachedStaticRemotesEnv) {
cachedStaticRemotesEnv = currentEnv;
cachedStaticRemotesMap = currentEnv ? JSON.parse(currentEnv) : undefined;
}
return cachedStaticRemotesMap;
}
/**
* Creates a default remote URL resolver function.
* This is extracted to avoid code duplication across bundler utils.
*/
function createDefaultRemoteUrlResolver(isServer = false, remoteEntryExt = 'js') {
const { readCachedProjectConfiguration, } = require('nx/src/project-graph/project-graph');
const target = 'serve';
const remoteEntry = isServer
? 'server/remoteEntry.js'
: `remoteEntry.${remoteEntryExt}`;
return function (remote) {
const mappedStaticRemotesFromEnv = getStaticRemotesFromEnv();
if (mappedStaticRemotesFromEnv && mappedStaticRemotesFromEnv[remote]) {
return `${mappedStaticRemotesFromEnv[remote]}/${remoteEntry}`;
}
let remoteConfiguration = null;
try {
remoteConfiguration = readCachedProjectConfiguration(remote);
}
catch (e) {
throw new Error(`Cannot find remote "${remote}". Check that the remote name is correct in your module federation config file.\n`);
}
const serveTarget = remoteConfiguration?.targets?.[target];
if (!serveTarget) {
throw new Error(`Cannot automatically determine URL of remote (${remote}). Looked for property "host" in the project's "serve" target.\n` +
`You can also use the tuple syntax in your config to configure your remotes. e.g. \`remotes: [['remote1', 'http://localhost:4201']]\``);
}
const host = serveTarget.options?.host ??
`http${serveTarget.options.ssl ? 's' : ''}://localhost`;
const port = serveTarget.options?.port ?? 4201;
return `${host.endsWith('/') ? host.slice(0, -1) : host}:${port}/${remoteEntry}`;
};
}
/**
* Async version - tries cached graph first, falls back to creating new one.
* Used by webpack and angular async configs.
*/
async function getModuleFederationConfigAsync(mfConfig, options = {}, frameworkConfig) {
let projectGraph;
try {
projectGraph = (0, devkit_1.readCachedProjectGraph)();
}
catch (e) {
projectGraph = await (0, devkit_1.createProjectGraphAsync)();
}
return buildModuleFederationConfig(mfConfig, options, frameworkConfig, projectGraph);
}
/**
* Sync version - only uses cached graph.
* Used by rspack and angular sync configs.
*/
function getModuleFederationConfigSync(mfConfig, options = {}, frameworkConfig) {
const projectGraph = (0, devkit_1.readCachedProjectGraph)();
return buildModuleFederationConfig(mfConfig, options, frameworkConfig, projectGraph);
}
/**
* Clears the static remotes env cache.
* Useful for testing or when the env variable changes.
*/
function clearStaticRemotesEnvCache() {
cachedStaticRemotesEnv = undefined;
cachedStaticRemotesMap = undefined;
}

View File

@@ -0,0 +1,2 @@
export declare function normalizeProjectName(name: string): string;
//# sourceMappingURL=normalize-project-name.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"normalize-project-name.d.ts","sourceRoot":"","sources":["../../../../../packages/module-federation/src/utils/normalize-project-name.ts"],"names":[],"mappings":"AACA,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,UAKhD"}

View File

@@ -0,0 +1,10 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.normalizeProjectName = normalizeProjectName;
// normalize to allow only JavaScript var valid names
function normalizeProjectName(name) {
// 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, '_');
}

View File

@@ -0,0 +1,3 @@
import type { PackageJson } from 'nx/src/utils/package-json';
export declare function readRootPackageJson(): PackageJson;
//# sourceMappingURL=package-json.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"package-json.d.ts","sourceRoot":"","sources":["../../../../../packages/module-federation/src/utils/package-json.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAE7D,wBAAgB,mBAAmB,IAAI,WAAW,CASjD"}

View File

@@ -0,0 +1,12 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.readRootPackageJson = readRootPackageJson;
const devkit_1 = require("@nx/devkit");
const fs_1 = require("fs");
function readRootPackageJson() {
const pkgJsonPath = (0, devkit_1.joinPathFragments)(devkit_1.workspaceRoot, 'package.json');
if (!(0, fs_1.existsSync)(pkgJsonPath)) {
throw new Error('NX MF: Could not find root package.json to determine dependency versions.');
}
return (0, devkit_1.readJsonFile)(pkgJsonPath);
}

View File

@@ -0,0 +1,14 @@
import { ExecutorContext } from '@nx/devkit';
export type StaticRemoteConfig = {
basePath: string;
outputPath: string;
urlSegment: string;
port: number;
};
export type StaticRemotesConfig = {
remotes: string[];
config: Record<string, StaticRemoteConfig> | undefined;
};
export declare function parseStaticRemotesConfig(staticRemotes: string[] | undefined, context: ExecutorContext): StaticRemotesConfig;
export declare function parseStaticSsrRemotesConfig(staticRemotes: string[] | undefined, context: ExecutorContext): StaticRemotesConfig;
//# sourceMappingURL=parse-static-remotes-config.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"parse-static-remotes-config.d.ts","sourceRoot":"","sources":["../../../../../packages/module-federation/src/utils/parse-static-remotes-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAqB,MAAM,YAAY,CAAC;AAIhE,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AACF,MAAM,MAAM,mBAAmB,GAAG;IAChC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,GAAG,SAAS,CAAC;CACxD,CAAC;AAEF,wBAAgB,wBAAwB,CACtC,aAAa,EAAE,MAAM,EAAE,GAAG,SAAS,EACnC,OAAO,EAAE,eAAe,GACvB,mBAAmB,CAgCrB;AAED,wBAAgB,2BAA2B,CACzC,aAAa,EAAE,MAAM,EAAE,GAAG,SAAS,EACnC,OAAO,EAAE,eAAe,GACvB,mBAAmB,CAgCrB"}

View File

@@ -0,0 +1,62 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseStaticRemotesConfig = parseStaticRemotesConfig;
exports.parseStaticSsrRemotesConfig = parseStaticSsrRemotesConfig;
const devkit_1 = require("@nx/devkit");
const path_1 = require("path");
const utils_1 = require("nx/src/tasks-runner/utils");
function parseStaticRemotesConfig(staticRemotes, context) {
if (!staticRemotes?.length) {
return { remotes: [], config: undefined };
}
const config = {};
for (const app of staticRemotes) {
const projectGraph = context.projectGraph;
const projectRoot = projectGraph.nodes[app].data.root;
let outputPath = (0, utils_1.interpolate)(projectGraph.nodes[app].data.targets?.['build']?.options?.outputPath ??
projectGraph.nodes[app].data.targets?.['build']?.outputs?.[0] ??
`${context.root}/${projectGraph.nodes[app].data.root}/dist`, {
projectName: projectGraph.nodes[app].data.name,
projectRoot,
workspaceRoot: context.root,
});
if (outputPath.startsWith(projectRoot)) {
outputPath = (0, devkit_1.joinPathFragments)(context.root, outputPath);
}
const basePath = ['', '/', '.'].some((p) => (0, path_1.dirname)(outputPath) === p)
? outputPath
: (0, path_1.dirname)(outputPath); // dist || dist/checkout -> dist
const urlSegment = app;
const port = context.projectGraph.nodes[app].data.targets['serve'].options.port;
config[app] = { basePath, outputPath, urlSegment, port };
}
return { remotes: staticRemotes, config };
}
function parseStaticSsrRemotesConfig(staticRemotes, context) {
if (!staticRemotes?.length) {
return { remotes: [], config: undefined };
}
const config = {};
for (const app of staticRemotes) {
const projectGraph = context.projectGraph;
const projectRoot = projectGraph.nodes[app].data.root;
let outputPath = (0, utils_1.interpolate)(projectGraph.nodes[app].data.targets?.['build']?.options?.outputPath ??
projectGraph.nodes[app].data.targets?.['build']?.outputs?.[0] ??
`${context.root}/${projectGraph.nodes[app].data.root}/dist`, {
projectName: projectGraph.nodes[app].data.name,
projectRoot,
workspaceRoot: context.root,
});
if (outputPath.startsWith(projectRoot)) {
outputPath = (0, devkit_1.joinPathFragments)(context.root, outputPath);
}
outputPath = (0, path_1.dirname)(outputPath);
const basePath = ['', '/', '.'].some((p) => (0, path_1.dirname)(outputPath) === p)
? outputPath
: (0, path_1.dirname)(outputPath); // dist || dist/checkout -> dist
const urlSegment = app;
const port = context.projectGraph.nodes[app].data.targets['serve'].options.port;
config[app] = { basePath, outputPath, urlSegment, port };
}
return { remotes: staticRemotes, config };
}

View File

@@ -0,0 +1,4 @@
import type { ModuleFederationRuntimePlugin } from '@module-federation/enhanced/runtime';
declare const nxRuntimeLibraryControlPlugin: () => ModuleFederationRuntimePlugin;
export default nxRuntimeLibraryControlPlugin;
//# sourceMappingURL=runtime-library-control.plugin.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"runtime-library-control.plugin.d.ts","sourceRoot":"","sources":["../../../../../../packages/module-federation/src/utils/plugins/runtime-library-control.plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,qCAAqC,CAAC;AAgBzF,QAAA,MAAM,6BAA6B,EAAE,MAAM,6BAoDxC,CAAC;AAEJ,eAAe,6BAA6B,CAAC"}

View File

@@ -0,0 +1,54 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const runtimeStore = {
sharedPackagesFromDev: {},
};
if (process.env.NX_MF_DEV_REMOTES) {
// process.env.NX_MF_DEV_REMOTES is replaced by an array value via DefinePlugin, even though the original value is a stringified array.
runtimeStore.devRemotes = process.env
.NX_MF_DEV_REMOTES;
}
const nxRuntimeLibraryControlPlugin = function () {
return {
name: 'nx-runtime-library-control-plugin',
beforeInit(args) {
runtimeStore.name = args.options.name;
return args;
},
resolveShare: (args) => {
const { shareScopeMap, scope, pkgName, version, GlobalFederation } = args;
const originalResolver = args.resolver;
args.resolver = function () {
if (!runtimeStore.sharedPackagesFromDev[pkgName]) {
if (!GlobalFederation.__INSTANCES__) {
return originalResolver();
}
else if (!runtimeStore.devRemotes) {
return originalResolver();
}
const devRemoteInstanceToUse = GlobalFederation.__INSTANCES__.find((instance) => instance.options.shared[pkgName] &&
runtimeStore.devRemotes.find((dr) => instance.name === dr));
if (!devRemoteInstanceToUse) {
return originalResolver();
}
runtimeStore.sharedPackagesFromDev[pkgName] =
devRemoteInstanceToUse.name;
}
const remoteInstanceName = runtimeStore.sharedPackagesFromDev[pkgName];
const remoteInstance = GlobalFederation.__INSTANCES__.find((instance) => instance.name === remoteInstanceName);
try {
const remotePkgInfo = remoteInstance.options.shared[pkgName].find((shared) => shared.from === remoteInstanceName);
remotePkgInfo.useIn.push(runtimeStore.name);
remotePkgInfo.useIn = Array.from(new Set(remotePkgInfo.useIn));
shareScopeMap[scope][pkgName][version] = remotePkgInfo;
return { shared: remotePkgInfo, useTreesShaking: false };
}
catch {
return originalResolver();
}
};
return args;
},
};
};
exports.default = nxRuntimeLibraryControlPlugin;

View File

@@ -0,0 +1,6 @@
/**
* Check if a port is already in use by attempting to connect to it.
* Uses waitForPortOpen with retries: 0 for an immediate check.
*/
export declare function isPortInUse(port: number, host?: string): Promise<boolean>;
//# sourceMappingURL=port-utils.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"port-utils.d.ts","sourceRoot":"","sources":["../../../../../packages/module-federation/src/utils/port-utils.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE,MAAoB,GACzB,OAAO,CAAC,OAAO,CAAC,CAOlB"}

View File

@@ -0,0 +1,17 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isPortInUse = isPortInUse;
const wait_for_port_open_1 = require("@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.
*/
async function isPortInUse(port, host = 'localhost') {
try {
await (0, wait_for_port_open_1.waitForPortOpen)(port, { retries: 0, host });
return true; // Port is open/in use
}
catch {
return false; // Port is not in use
}
}

View File

@@ -0,0 +1,8 @@
import { AdditionalSharedConfig, ModuleFederationConfig, ModuleFederationLibrary, NxModuleFederationConfigOverride, Remotes, SharedFunction, SharedLibraryConfig, SharedWorkspaceLibraryConfig, WorkspaceLibrary, WorkspaceLibrarySecondaryEntryPoint } from './models';
import { applyAdditionalShared, applySharedFunction, getNpmPackageSharedConfig, sharePackages, shareWorkspaceLibraries } from './share';
import { normalizeProjectName } from './normalize-project-name';
import { mapRemotes, mapRemotesForSSR } from './remotes';
import { getDependentPackagesForProject } from './dependencies';
import { readRootPackageJson } from './package-json';
export { ModuleFederationConfig, NxModuleFederationConfigOverride, SharedLibraryConfig, SharedWorkspaceLibraryConfig, AdditionalSharedConfig, WorkspaceLibrary, SharedFunction, WorkspaceLibrarySecondaryEntryPoint, Remotes, ModuleFederationLibrary, applySharedFunction, applyAdditionalShared, getNpmPackageSharedConfig, shareWorkspaceLibraries, sharePackages, mapRemotes, mapRemotesForSSR, normalizeProjectName, getDependentPackagesForProject, readRootPackageJson, };
//# sourceMappingURL=public-api.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"public-api.d.ts","sourceRoot":"","sources":["../../../../../packages/module-federation/src/utils/public-api.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EACtB,sBAAsB,EACtB,uBAAuB,EACvB,gCAAgC,EAChC,OAAO,EACP,cAAc,EACd,mBAAmB,EACnB,4BAA4B,EAC5B,gBAAgB,EAChB,mCAAmC,EACpC,MAAM,UAAU,CAAC;AAElB,OAAO,EACL,qBAAqB,EACrB,mBAAmB,EACnB,yBAAyB,EACzB,aAAa,EACb,uBAAuB,EACxB,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAEhE,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAEzD,OAAO,EAAE,8BAA8B,EAAE,MAAM,gBAAgB,CAAC;AAEhE,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAErD,OAAO,EACL,sBAAsB,EACtB,gCAAgC,EAChC,mBAAmB,EACnB,4BAA4B,EAC5B,sBAAsB,EACtB,gBAAgB,EAChB,cAAc,EACd,mCAAmC,EACnC,OAAO,EACP,uBAAuB,EACvB,mBAAmB,EACnB,qBAAqB,EACrB,yBAAyB,EACzB,uBAAuB,EACvB,aAAa,EACb,UAAU,EACV,gBAAgB,EAChB,oBAAoB,EACpB,8BAA8B,EAC9B,mBAAmB,GACpB,CAAC"}

View File

@@ -0,0 +1,18 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.readRootPackageJson = exports.getDependentPackagesForProject = exports.normalizeProjectName = exports.mapRemotesForSSR = exports.mapRemotes = exports.sharePackages = exports.shareWorkspaceLibraries = exports.getNpmPackageSharedConfig = exports.applyAdditionalShared = exports.applySharedFunction = void 0;
const share_1 = require("./share");
Object.defineProperty(exports, "applyAdditionalShared", { enumerable: true, get: function () { return share_1.applyAdditionalShared; } });
Object.defineProperty(exports, "applySharedFunction", { enumerable: true, get: function () { return share_1.applySharedFunction; } });
Object.defineProperty(exports, "getNpmPackageSharedConfig", { enumerable: true, get: function () { return share_1.getNpmPackageSharedConfig; } });
Object.defineProperty(exports, "sharePackages", { enumerable: true, get: function () { return share_1.sharePackages; } });
Object.defineProperty(exports, "shareWorkspaceLibraries", { enumerable: true, get: function () { return share_1.shareWorkspaceLibraries; } });
const normalize_project_name_1 = require("./normalize-project-name");
Object.defineProperty(exports, "normalizeProjectName", { enumerable: true, get: function () { return normalize_project_name_1.normalizeProjectName; } });
const remotes_1 = require("./remotes");
Object.defineProperty(exports, "mapRemotes", { enumerable: true, get: function () { return remotes_1.mapRemotes; } });
Object.defineProperty(exports, "mapRemotesForSSR", { enumerable: true, get: function () { return remotes_1.mapRemotesForSSR; } });
const dependencies_1 = require("./dependencies");
Object.defineProperty(exports, "getDependentPackagesForProject", { enumerable: true, get: function () { return dependencies_1.getDependentPackagesForProject; } });
const package_json_1 = require("./package-json");
Object.defineProperty(exports, "readRootPackageJson", { enumerable: true, get: function () { return package_json_1.readRootPackageJson; } });

View File

@@ -0,0 +1,20 @@
import { Remotes } from './models';
/**
* Map remote names to a format that can be understood and used by Module
* Federation.
*
* @param remotes - The remotes to map
* @param remoteEntryExt - The file extension of the remoteEntry file
* @param determineRemoteUrl - The function used to lookup the URL of the served remote
*/
export declare function mapRemotes(remotes: Remotes, remoteEntryExt: 'js' | 'mjs', determineRemoteUrl: (remote: string) => string, isRemoteGlobal?: boolean): Record<string, string>;
/**
* Map remote names to a format that can be understood and used by Module
* Federation.
*
* @param remotes - The remotes to map
* @param remoteEntryExt - The file extension of the remoteEntry file
* @param determineRemoteUrl - The function used to lookup the URL of the served remote
*/
export declare function mapRemotesForSSR(remotes: Remotes, remoteEntryExt: 'js' | 'mjs', determineRemoteUrl: (remote: string) => string): Record<string, string>;
//# sourceMappingURL=remotes.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"remotes.d.ts","sourceRoot":"","sources":["../../../../../packages/module-federation/src/utils/remotes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAInC;;;;;;;GAOG;AACH,wBAAgB,UAAU,CACxB,OAAO,EAAE,OAAO,EAChB,cAAc,EAAE,IAAI,GAAG,KAAK,EAC5B,kBAAkB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,EAC9C,cAAc,UAAQ,GACrB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAqBxB;AAkCD;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,OAAO,EAChB,cAAc,EAAE,IAAI,GAAG,KAAK,EAC5B,kBAAkB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,GAC7C,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CA0BxB"}

View File

@@ -0,0 +1,75 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.mapRemotes = mapRemotes;
exports.mapRemotesForSSR = mapRemotesForSSR;
const url_helpers_1 = require("./url-helpers");
const normalize_project_name_1 = require("./normalize-project-name");
/**
* Map remote names to a format that can be understood and used by Module
* Federation.
*
* @param remotes - The remotes to map
* @param remoteEntryExt - The file extension of the remoteEntry file
* @param determineRemoteUrl - The function used to lookup the URL of the served remote
*/
function mapRemotes(remotes, remoteEntryExt, determineRemoteUrl, isRemoteGlobal = false) {
const mappedRemotes = {};
for (const nxRemoteProjectName of remotes) {
if (Array.isArray(nxRemoteProjectName)) {
const mfRemoteName = nxRemoteProjectName[0];
mappedRemotes[mfRemoteName] = handleArrayRemote(nxRemoteProjectName, remoteEntryExt, isRemoteGlobal);
}
else if (typeof nxRemoteProjectName === 'string') {
mappedRemotes[nxRemoteProjectName] = handleStringRemote(nxRemoteProjectName, determineRemoteUrl, isRemoteGlobal);
}
}
return mappedRemotes;
}
// Helper function to deal with remotes that are arrays
function handleArrayRemote(remote, remoteEntryExt, isRemoteGlobal) {
const [nxRemoteProjectName, remoteLocation] = remote;
const mfRemoteName = (0, normalize_project_name_1.normalizeProjectName)(nxRemoteProjectName);
const finalRemoteUrl = (0, url_helpers_1.processRemoteLocation)(remoteLocation, remoteEntryExt);
// Promise-based remotes should not use the global prefix format
if (remoteLocation.startsWith('promise new Promise')) {
return finalRemoteUrl;
}
return isRemoteGlobal ? `${mfRemoteName}@${finalRemoteUrl}` : finalRemoteUrl;
}
// Helper function to deal with remotes that are strings
function handleStringRemote(nxRemoteProjectName, determineRemoteUrl, isRemoteGlobal) {
const globalPrefix = isRemoteGlobal
? `${(0, normalize_project_name_1.normalizeProjectName)(nxRemoteProjectName)}@`
: '';
return `${globalPrefix}${determineRemoteUrl(nxRemoteProjectName)}`;
}
/**
* Map remote names to a format that can be understood and used by Module
* Federation.
*
* @param remotes - The remotes to map
* @param remoteEntryExt - The file extension of the remoteEntry file
* @param determineRemoteUrl - The function used to lookup the URL of the served remote
*/
function mapRemotesForSSR(remotes, remoteEntryExt, determineRemoteUrl) {
const mappedRemotes = {};
for (const remote of remotes) {
if (Array.isArray(remote)) {
let [nxRemoteProjectName, remoteLocation] = remote;
const mfRemoteName = (0, normalize_project_name_1.normalizeProjectName)(nxRemoteProjectName);
const finalRemoteUrl = (0, url_helpers_1.processRemoteLocation)(remoteLocation, remoteEntryExt);
// Promise-based remotes should not use the global prefix format
if (remoteLocation.startsWith('promise new Promise')) {
mappedRemotes[mfRemoteName] = finalRemoteUrl;
}
else {
mappedRemotes[mfRemoteName] = `${mfRemoteName}@${finalRemoteUrl}`;
}
}
else if (typeof remote === 'string') {
const mfRemoteName = (0, normalize_project_name_1.normalizeProjectName)(remote);
mappedRemotes[remote] = `${mfRemoteName}@${determineRemoteUrl(remote)}`;
}
}
return mappedRemotes;
}

View File

@@ -0,0 +1,13 @@
import type { WorkspaceLibrary } from './models';
import { WorkspaceLibrarySecondaryEntryPoint } from './models';
export declare function collectWorkspaceLibrarySecondaryEntryPoints(library: WorkspaceLibrary, tsconfigPathAliases: Record<string, string[]>): WorkspaceLibrarySecondaryEntryPoint[];
export declare function getNonNodeModulesSubDirs(directory: string): string[];
export declare function recursivelyCollectSecondaryEntryPointsFromDirectory(pkgName: string, pkgVersion: string, pkgRoot: string, mainEntryPointExports: any | undefined, directories: string[], collectedPackages: {
name: string;
version: string;
}[]): void;
export declare function collectPackageSecondaryEntryPoints(pkgName: string, pkgVersion: string, collectedPackages: {
name: string;
version: string;
}[]): void;
//# sourceMappingURL=secondary-entry-points.d.ts.map

Some files were not shown because too many files have changed in this diff Show More