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 Jul 7, 2023
1 parent 21007d8 commit 187bd5a
Show file tree
Hide file tree
Showing 10 changed files with 125 additions and 97 deletions.
2 changes: 0 additions & 2 deletions packages/angular/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,6 @@
"magic-string": "~0.26.2",
"minimatch": "3.0.5",
"semver": "7.5.3",
"ts-node": "10.9.1",
"tsconfig-paths": "^4.1.2",
"webpack": "^5.80.0",
"webpack-merge": "5.7.3",
"enquirer": "^2.3.6",
Expand Down
55 changes: 42 additions & 13 deletions packages/angular/src/builders/utilities/module-federation.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { ProjectConfiguration } from 'nx/src/config/workspace-json-project-json';
import { join } from 'path';
import { existsSync, readFileSync } from 'fs';
import { logger, Remotes } from '@nx/devkit';
import { logger } from '@nx/devkit';
import { tsNodeRegister } from '@nx/js/src/utils/typescript/tsnode-register';

export function getDynamicRemotes(
project: ProjectConfiguration,
Expand Down Expand Up @@ -71,26 +72,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
23 changes: 1 addition & 22 deletions packages/angular/src/builders/utilities/webpack.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { merge } from 'webpack-merge';
import { tsNodeRegister } from '@nx/js/src/utils/typescript/tsnode-register';

export async function mergeCustomWebpackConfig(
baseWebpackConfig: any,
Expand Down Expand Up @@ -48,25 +49,3 @@ export function resolveIndexHtmlTransformer(

return (indexHtml) => transform(target, indexHtml);
}

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'],
},
});

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 });
}
}
2 changes: 2 additions & 0 deletions packages/js/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@
"detect-port": "^1.5.1",
"fast-glob": "3.2.7",
"fs-extra": "^11.1.0",
"ts-node": "10.9.1",
"tsconfig-paths": "^4.1.2",
"ignore": "^5.0.4",
"js-tokens": "^4.0.0",
"minimatch": "3.0.5",
Expand Down
21 changes: 21 additions & 0 deletions packages/js/src/utils/typescript/tsnode-register.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
export 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'],
},
});

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 });
}
}
2 changes: 0 additions & 2 deletions packages/next/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,6 @@
"http-proxy-middleware": "^2.0.6",
"ignore": "^5.0.4",
"semver": "7.5.3",
"ts-node": "10.9.1",
"tsconfig-paths": "^4.1.2",
"url-loader": "^4.1.1",
"webpack-merge": "^5.8.0",
"@nx/devkit": "file:../devkit",
Expand Down
20 changes: 0 additions & 20 deletions packages/next/src/executors/server/lib/tsnode-register.ts

This file was deleted.

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,72 @@ 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';
import { tsNodeRegister } from '@nx/js/src/utils/typescript/tsnode-register';

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 getBuildOptions(buildTarget: string, context: ExecutorContext) {
const target = parseTargetString(buildTarget, context.projectGraph);

const moduleFederationConfigPath = join(
context.root,
p.root,
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 Down Expand Up @@ -88,7 +133,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
2 changes: 0 additions & 2 deletions packages/webpack/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,6 @@
"stylus-loader": "^7.1.0",
"terser-webpack-plugin": "^5.3.3",
"ts-loader": "^9.3.1",
"ts-node": "10.9.1",
"tsconfig-paths": "^4.1.2",
"tsconfig-paths-webpack-plugin": "4.0.0",
"tslib": "^2.3.0",
"webpack": "^5.80.0",
Expand Down
25 changes: 2 additions & 23 deletions packages/webpack/src/utils/webpack/custom-webpack.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,4 @@
export function tsNodeRegister(file: string = '', tsConfig?: string) {
if (!file?.endsWith('.ts')) return;

// Avoid double-registering which can lead to issues type-checking already transformed files.
if (isRegistered()) return;

// Register TS compiler lazily
require('ts-node').register({
project: tsConfig,
compilerOptions: {
module: 'CommonJS',
types: ['node'],
},
});

// Register paths in tsConfig
const tsconfigPaths = require('tsconfig-paths');
const { absoluteBaseUrl: baseUrl, paths } =
tsconfigPaths.loadConfig(tsConfig);
if (baseUrl && paths) {
tsconfigPaths.register({ baseUrl, paths });
}
}
import { tsNodeRegister } from '@nx/js/src/utils/typescript/tsnode-register';

export function resolveCustomWebpackConfig(path: string, tsConfig: string) {
tsNodeRegister(path, tsConfig);
Expand All @@ -33,6 +11,7 @@ export function resolveCustomWebpackConfig(path: string, tsConfig: string) {
// `{ default: { ... } }`
return customWebpackConfig.default || customWebpackConfig;
}

export function isRegistered() {
return (
require.extensions['.ts'] != undefined ||
Expand Down

0 comments on commit 187bd5a

Please sign in to comment.