feat(angular): add option for custom path to manifest file (#15053)

Co-authored-by: Leosvel Pérez Espinosa <leosvel.perez.espinosa@gmail.com>
This commit is contained in:
Colum Ferry 2023-02-16 16:12:20 +00:00 committed by GitHub
parent 3eeb4a3e4d
commit f913b905a1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 82 additions and 13 deletions

View File

@ -108,6 +108,10 @@
"type": "array", "type": "array",
"items": { "type": "string" }, "items": { "type": "string" },
"description": "List of remote applications to not automatically serve, either statically or in development mode. This can be useful for multi-repository module federation setups where the host application uses a remote application from an external repository." "description": "List of remote applications to not automatically serve, either statically or in development mode. This can be useful for multi-repository module federation setups where the host application uses a remote application from an external repository."
},
"pathToManifestFile": {
"type": "string",
"description": "Path to a Module Federation manifest file (e.g. `my/path/to/module-federation.manifest.json`) containing the dynamic remote applications relative to the workspace root."
} }
}, },
"additionalProperties": false, "additionalProperties": false,

View File

@ -77,6 +77,10 @@
"verbose": { "verbose": {
"type": "boolean", "type": "boolean",
"description": "Adds more details to output logging." "description": "Adds more details to output logging."
},
"pathToManifestFile": {
"type": "string",
"description": "Path to a Module Federation manifest file (e.g. `my/path/to/module-federation.manifest.json`) containing the dynamic remote applications relative to the workspace root."
} }
}, },
"additionalProperties": false, "additionalProperties": false,

View File

@ -12,6 +12,8 @@ import {
getStaticRemotes, getStaticRemotes,
validateDevRemotes, validateDevRemotes,
} from '../utilities/module-federation'; } from '../utilities/module-federation';
import { existsSync } from 'fs';
import { extname, join } from 'path';
export function executeModuleFederationDevServerBuilder( export function executeModuleFederationDevServerBuilder(
schema: Schema, schema: Schema,
@ -24,6 +26,29 @@ export function executeModuleFederationDevServerBuilder(
const ws = new Workspaces(workspaceRoot); const ws = new Workspaces(workspaceRoot);
const project = workspaceProjects[context.target.project]; const project = workspaceProjects[context.target.project];
let pathToManifestFile = join(
context.workspaceRoot,
project.sourceRoot,
'assets/module-federation.manifest.json'
);
if (options.pathToManifestFile) {
const userPathToManifestFile = join(
context.workspaceRoot,
options.pathToManifestFile
);
if (!existsSync(userPathToManifestFile)) {
throw new Error(
`The provided Module Federation manifest file path does not exist. Please check the file exists at "${userPathToManifestFile}".`
);
} else if (extname(options.pathToManifestFile) !== '.json') {
throw new Error(
`The Module Federation manifest file must be a JSON. Please ensure the file at ${userPathToManifestFile} is a JSON.`
);
}
pathToManifestFile = userPathToManifestFile;
}
validateDevRemotes(options, workspaceProjects); validateDevRemotes(options, workspaceProjects);
const remotesToSkip = new Set(options.skipRemotes ?? []); const remotesToSkip = new Set(options.skipRemotes ?? []);
@ -37,7 +62,8 @@ export function executeModuleFederationDevServerBuilder(
project, project,
context, context,
workspaceProjects, workspaceProjects,
remotesToSkip remotesToSkip,
pathToManifestFile
); );
const remotes = [...staticRemotes, ...dynamicRemotes]; const remotes = [...staticRemotes, ...dynamicRemotes];

View File

@ -19,4 +19,5 @@ export interface Schema {
poll?: number; poll?: number;
devRemotes?: string[]; devRemotes?: string[];
skipRemotes?: string[]; skipRemotes?: string[];
pathToManifestFile?: string;
} }

View File

@ -118,6 +118,10 @@
"type": "string" "type": "string"
}, },
"description": "List of remote applications to not automatically serve, either statically or in development mode. This can be useful for multi-repository module federation setups where the host application uses a remote application from an external repository." "description": "List of remote applications to not automatically serve, either statically or in development mode. This can be useful for multi-repository module federation setups where the host application uses a remote application from an external repository."
},
"pathToManifestFile": {
"type": "string",
"description": "Path to a Module Federation manifest file (e.g. `my/path/to/module-federation.manifest.json`) containing the dynamic remote applications relative to the workspace root."
} }
}, },
"additionalProperties": false, "additionalProperties": false,

View File

@ -12,9 +12,10 @@ import {
} from '../utilities/module-federation'; } from '../utilities/module-federation';
import { switchMap, tap } from 'rxjs/operators'; import { switchMap, tap } from 'rxjs/operators';
import { from } from 'rxjs'; import { from } from 'rxjs';
import { join } from 'path'; import { extname, join } from 'path';
import { execSync, fork } from 'child_process'; import { execSync, fork } from 'child_process';
import { scheduleTarget } from 'nx/src/adapter/ngcli-adapter'; import { scheduleTarget } from 'nx/src/adapter/ngcli-adapter';
import { existsSync } from 'fs';
export function executeModuleFederationDevSSRBuilder( export function executeModuleFederationDevSSRBuilder(
schema: Schema, schema: Schema,
@ -27,6 +28,29 @@ export function executeModuleFederationDevSSRBuilder(
const ws = new Workspaces(workspaceRoot); const ws = new Workspaces(workspaceRoot);
const project = workspaceProjects[context.target.project]; const project = workspaceProjects[context.target.project];
let pathToManifestFile = join(
context.workspaceRoot,
project.sourceRoot,
'assets/module-federation.manifest.json'
);
if (options.pathToManifestFile) {
const userPathToManifestFile = join(
context.workspaceRoot,
options.pathToManifestFile
);
if (!existsSync(userPathToManifestFile)) {
throw new Error(
`The provided Module Federation manifest file path does not exist. Please check the file exists at "${userPathToManifestFile}".`
);
} else if (extname(options.pathToManifestFile) !== '.json') {
throw new Error(
`The Module Federation manifest file must be a JSON. Please ensure the file at ${userPathToManifestFile} is a JSON.`
);
}
pathToManifestFile = userPathToManifestFile;
}
validateDevRemotes(options, workspaceProjects); validateDevRemotes(options, workspaceProjects);
const remotesToSkip = new Set(options.skipRemotes ?? []); const remotesToSkip = new Set(options.skipRemotes ?? []);
@ -40,7 +64,8 @@ export function executeModuleFederationDevSSRBuilder(
project, project,
context, context,
workspaceProjects, workspaceProjects,
remotesToSkip remotesToSkip,
pathToManifestFile
); );
const remotes = [...staticRemotes, ...dynamicRemotes]; const remotes = [...staticRemotes, ...dynamicRemotes];

View File

@ -13,4 +13,5 @@ export interface Schema {
devRemotes?: string[]; devRemotes?: string[];
skipRemotes?: string[]; skipRemotes?: string[];
verbose?: boolean; verbose?: boolean;
pathToManifestFile?: string;
} }

View File

@ -78,6 +78,10 @@
"verbose": { "verbose": {
"type": "boolean", "type": "boolean",
"description": "Adds more details to output logging." "description": "Adds more details to output logging."
},
"pathToManifestFile": {
"type": "string",
"description": "Path to a Module Federation manifest file (e.g. `my/path/to/module-federation.manifest.json`) containing the dynamic remote applications relative to the workspace root."
} }
}, },
"additionalProperties": false, "additionalProperties": false,

View File

@ -7,23 +7,23 @@ export function getDynamicRemotes(
project: ProjectConfiguration, project: ProjectConfiguration,
context: import('@angular-devkit/architect').BuilderContext, context: import('@angular-devkit/architect').BuilderContext,
workspaceProjects: Record<string, ProjectConfiguration>, workspaceProjects: Record<string, ProjectConfiguration>,
remotesToSkip: Set<string> remotesToSkip: Set<string>,
pathToManifestFile = join(
context.workspaceRoot,
project.sourceRoot,
'assets/module-federation.manifest.json'
)
): string[] { ): string[] {
// check for dynamic remotes // check for dynamic remotes
// we should only check for dynamic based on what we generate // we should only check for dynamic based on what we generate
// and fallback to empty array // and fallback to empty array
const standardPathToGeneratedMFManifestJson = join( if (!existsSync(pathToManifestFile)) {
context.workspaceRoot,
project.sourceRoot,
'assets/module-federation.manifest.json'
);
if (!existsSync(standardPathToGeneratedMFManifestJson)) {
return []; return [];
} }
const moduleFederationManifestJson = readFileSync( const moduleFederationManifestJson = readFileSync(
standardPathToGeneratedMFManifestJson, pathToManifestFile,
'utf-8' 'utf-8'
); );
@ -54,8 +54,8 @@ export function getDynamicRemotes(
if (invalidDynamicRemotes.length) { if (invalidDynamicRemotes.length) {
throw new Error( throw new Error(
invalidDynamicRemotes.length === 1 invalidDynamicRemotes.length === 1
? `Invalid dynamic remote configured in "${standardPathToGeneratedMFManifestJson}": ${invalidDynamicRemotes[0]}.` ? `Invalid dynamic remote configured in "${pathToManifestFile}": ${invalidDynamicRemotes[0]}.`
: `Invalid dynamic remotes configured in "${standardPathToGeneratedMFManifestJson}": ${invalidDynamicRemotes.join( : `Invalid dynamic remotes configured in "${pathToManifestFile}": ${invalidDynamicRemotes.join(
', ' ', '
)}.` )}.`
); );