Skip to content

Commit

Permalink
feat(angular): add support for TS Module Federation Config #15739
Browse files Browse the repository at this point in the history
  • Loading branch information
Coly010 committed Jun 30, 2023
1 parent 2941ddc commit f539e6b
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 28 deletions.
54 changes: 41 additions & 13 deletions packages/angular/src/builders/utilities/module-federation.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ProjectConfiguration } from 'nx/src/config/workspace-json-project-json';
import { join } from 'path';
import { existsSync, readFileSync } from 'fs';
import { Remotes } from '@nx/devkit';
import { tsNodeRegister } from './webpack';

export function getDynamicRemotes(
project: ProjectConfiguration,
Expand Down Expand Up @@ -64,26 +64,54 @@ export function getDynamicRemotes(
return dynamicRemotes;
}

export function getStaticRemotes(
project: ProjectConfiguration,
context: import('@angular-devkit/architect').BuilderContext,
workspaceProjects: Record<string, ProjectConfiguration>,
remotesToSkip: Set<string>
): string[] {
const mfConfigPath = join(
context.workspaceRoot,
project.root,
function getModuleFederationConfig(
tsconfigPath: string,
workspaceRoot: string,
projectRoot: string
) {
const moduleFederationConfigPathJS = join(
workspaceRoot,
projectRoot,
'module-federation.config.js'
);

let mfeConfig: { remotes: Remotes };
const moduleFederationConfigPathTS = join(
workspaceRoot,
projectRoot,
'module-federation.config.ts'
);

let moduleFederationConfigPath = moduleFederationConfigPathJS;

if (existsSync(moduleFederationConfigPathTS)) {
tsNodeRegister(moduleFederationConfigPathTS, tsconfigPath);
moduleFederationConfigPath = moduleFederationConfigPathTS;
}

try {
mfeConfig = require(mfConfigPath);
const config = require(moduleFederationConfigPath);
return {
mfeConfig: config.default || config,
mfConfigPath: moduleFederationConfigPath,
};
} catch {
throw new Error(
`Could not load ${mfConfigPath}. Was this project generated with "@nx/angular:host"?`
`Could not load ${moduleFederationConfigPath}. Was this project generated with "@nx/angular:host"?`
);
}
}

export function getStaticRemotes(
project: ProjectConfiguration,
context: import('@angular-devkit/architect').BuilderContext,
workspaceProjects: Record<string, ProjectConfiguration>,
remotesToSkip: Set<string>
): string[] {
const { mfeConfig, mfConfigPath } = getModuleFederationConfig(
project.targets.build.options.tsConfig,
context.workspaceRoot,
project.root
);

const remotesConfig =
Array.isArray(mfeConfig.remotes) && mfeConfig.remotes.length > 0
Expand Down
2 changes: 1 addition & 1 deletion packages/angular/src/builders/utilities/webpack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export function resolveIndexHtmlTransformer(
return (indexHtml) => transform(target, indexHtml);
}

function tsNodeRegister(file: string, tsConfig?: string) {
export function tsNodeRegister(file: string, tsConfig?: string) {
if (!file?.endsWith('.ts')) return;
// Register TS compiler lazily
require('ts-node').register({
Expand Down
4 changes: 3 additions & 1 deletion packages/react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@
"@nx/devkit": "file:../devkit",
"@nx/js": "file:../js",
"@nx/linter": "file:../linter",
"@nx/web": "file:../web"
"@nx/web": "file:../web",
"ts-node": "10.9.1",
"tsconfig-paths": "^4.1.2"
},
"publishConfig": {
"access": "public"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import { ExecutorContext, logger, runExecutor } from '@nx/devkit';
import {
ExecutorContext,
logger,
parseTargetString,
readTargetOptions,
runExecutor,
} from '@nx/devkit';
import devServerExecutor from '@nx/webpack/src/executors/dev-server/dev-server.impl';
import { WebDevServerOptions } from '@nx/webpack/src/executors/dev-server/schema';
import { join } from 'path';
Expand All @@ -10,33 +16,93 @@ import * as chalk from 'chalk';
import { waitForPortOpen } from '@nx/web/src/utils/wait-for-port-open';
import { findMatchingProjects } from 'nx/src/utils/find-matching-projects';
import { fork } from 'child_process';
import { existsSync } from 'fs';

type ModuleFederationDevServerOptions = WebDevServerOptions & {
devRemotes?: string | string[];
skipRemotes?: string[];
};

export default async function* moduleFederationDevServer(
options: ModuleFederationDevServerOptions,
context: ExecutorContext
): AsyncIterableIterator<{ success: boolean; baseUrl?: string }> {
const currIter = devServerExecutor(options, context);
const p = context.projectsConfigurations.projects[context.projectName];
function tsNodeRegister(file: string, tsConfig?: string) {
if (!file?.endsWith('.ts')) return;
// Register TS compiler lazily
require('ts-node').register({
project: tsConfig,
compilerOptions: {
module: 'CommonJS',
types: ['node'],
},
});

const moduleFederationConfigPath = join(
context.root,
p.root,
if (!tsConfig) return;

// Register paths in tsConfig
const tsconfigPaths = require('tsconfig-paths');
const { absoluteBaseUrl: baseUrl, paths } =
tsconfigPaths.loadConfig(tsConfig);
if (baseUrl && paths) {
tsconfigPaths.register({ baseUrl, paths });
}
}

function getBuildOptions(buildTarget: string, context: ExecutorContext) {
const target = parseTargetString(buildTarget, context.projectGraph);

const buildOptions = readTargetOptions(target, context);

return {
...buildOptions,
};
}

function getModuleFederationConfig(
tsconfigPath: string,
workspaceRoot: string,
projectRoot: string
) {
const moduleFederationConfigPathJS = join(
workspaceRoot,
projectRoot,
'module-federation.config.js'
);

let moduleFederationConfig: any;
const moduleFederationConfigPathTS = join(
workspaceRoot,
projectRoot,
'module-federation.config.ts'
);

let moduleFederationConfigPath = moduleFederationConfigPathJS;

if (existsSync(moduleFederationConfigPathTS)) {
tsNodeRegister(moduleFederationConfigPathTS, tsconfigPath);
moduleFederationConfigPath = moduleFederationConfigPathTS;
}

try {
moduleFederationConfig = require(moduleFederationConfigPath);
const config = require(moduleFederationConfigPath);
return config.default || config;
} catch {
throw new Error(
`Could not load ${moduleFederationConfigPath}. Was this project generated with "@nx/react:host"?\nSee: https://nx.dev/recipes/module-federation/faster-builds`
);
}
}

export default async function* moduleFederationDevServer(
options: ModuleFederationDevServerOptions,
context: ExecutorContext
): AsyncIterableIterator<{ success: boolean; baseUrl?: string }> {
const nxBin = require.resolve('nx');
const currIter = devServerExecutor(options, context);
const p = context.projectsConfigurations.projects[context.projectName];
const buildOptions = getBuildOptions(options.buildTarget, context);

const moduleFederationConfig = getModuleFederationConfig(
buildOptions.tsConfig,
context.root,
p.root
);

const remotesToSkip = new Set(
findMatchingProjects(options.skipRemotes ?? [], context.projectGraph.nodes)
Expand All @@ -61,7 +127,6 @@ export default async function* moduleFederationDevServer(
)} with ${knownRemotes.length} remotes`
);

const nxBin = require.resolve('nx');
const devRemoteIters: AsyncIterable<{ success: boolean }>[] = [];
let isCollectingStaticRemoteOutput = true;

Expand Down

0 comments on commit f539e6b

Please sign in to comment.