feat(module-federation): use nx run-many to build static remotes in parallel (#19987)

This commit is contained in:
Colum Ferry 2023-11-06 16:25:33 +00:00 committed by GitHub
parent 33ca59673a
commit 1338a7c133
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 176 additions and 74 deletions

View File

@ -122,6 +122,10 @@
"description": "Whether the host that is running this executor is the first in the project tree to do so.", "description": "Whether the host that is running this executor is the first in the project tree to do so.",
"default": true, "default": true,
"x-priority": "internal" "x-priority": "internal"
},
"parallel": {
"type": "number",
"description": "Max number of parallel processes for building static remotes"
} }
}, },
"additionalProperties": false, "additionalProperties": false,

View File

@ -100,6 +100,10 @@
"description": "Whether the host that is running this executor is the first in the project tree to do so.", "description": "Whether the host that is running this executor is the first in the project tree to do so.",
"default": true, "default": true,
"x-priority": "internal" "x-priority": "internal"
},
"parallel": {
"type": "number",
"description": "Max number of parallel processes for building static remotes"
} }
}, },
"presets": [] "presets": []

View File

@ -121,6 +121,48 @@ export function executeModuleFederationDevServerBuilder(
pathToManifestFile pathToManifestFile
); );
const staticRemoteBuildPromise = new Promise<void>((res) => {
logger.info(
`NX Building ${remotes.staticRemotes.length} static remotes...`
);
const staticProcess = fork(
nxBin,
[
'run-many',
`--target=build`,
`--projects=${remotes.staticRemotes.join(',')}`,
...(context.target.configuration
? [`--configuration=${context.target.configuration}`]
: []),
...(options.parallel ? [`--parallel=${options.parallel}`] : []),
],
{
cwd: context.workspaceRoot,
stdio: ['ignore', 'pipe', 'pipe', 'ipc'],
}
);
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, '');
if (stdoutString.includes('Successfully ran target build')) {
staticProcess.stdout.removeAllListeners('data');
logger.info(`NX Built ${remotes.staticRemotes.length} static remotes`);
res();
}
});
staticProcess.stderr.on('data', (data) => logger.info(data.toString()));
staticProcess.on('exit', (code) => {
if (code !== 0) {
throw new Error(`Remotes failed to build. See above for errors.`);
}
});
process.on('SIGTERM', () => staticProcess.kill('SIGTERM'));
process.on('exit', () => staticProcess.kill('SIGTERM'));
});
return from(staticRemoteBuildPromise).pipe(
concatMap(() => {
let isCollectingStaticRemoteOutput = true; let isCollectingStaticRemoteOutput = true;
for (const app of remotes.staticRemotes) { for (const app of remotes.staticRemotes) {
@ -136,7 +178,9 @@ export function executeModuleFederationDevServerBuilder(
[ [
'run', 'run',
`${app}:serve-static${ `${app}:serve-static${
context.target.configuration ? `:${context.target.configuration}` : '' context.target.configuration
? `:${context.target.configuration}`
: ''
}`, }`,
...(isUsingModuleFederationDevServerExecutor ...(isUsingModuleFederationDevServerExecutor
? [`--isInitialHost=false`] ? [`--isInitialHost=false`]
@ -221,6 +265,8 @@ export function executeModuleFederationDevServerBuilder(
return devRemotes$.length > 0 return devRemotes$.length > 0
? combineLatest([...devRemotes$]).pipe(concatMap(() => currExecutor)) ? combineLatest([...devRemotes$]).pipe(concatMap(() => currExecutor))
: currExecutor; : currExecutor;
})
);
} }
export default require('@angular-devkit/architect').createBuilder( export default require('@angular-devkit/architect').createBuilder(

View File

@ -22,4 +22,5 @@ export interface Schema {
pathToManifestFile?: string; pathToManifestFile?: string;
static?: boolean; static?: boolean;
isInitialHost?: boolean; isInitialHost?: boolean;
parallel?: number;
} }

View File

@ -132,6 +132,10 @@
"description": "Whether the host that is running this executor is the first in the project tree to do so.", "description": "Whether the host that is running this executor is the first in the project tree to do so.",
"default": true, "default": true,
"x-priority": "internal" "x-priority": "internal"
},
"parallel": {
"type": "number",
"description": "Max number of parallel processes for building static remotes"
} }
}, },
"additionalProperties": false, "additionalProperties": false,

View File

@ -24,6 +24,7 @@ type ModuleFederationDevServerOptions = WebDevServerOptions & {
skipRemotes?: string[]; skipRemotes?: string[];
static?: boolean; static?: boolean;
isInitialHost?: boolean; isInitialHost?: boolean;
parallel?: number;
}; };
function getBuildOptions(buildTarget: string, context: ExecutorContext) { function getBuildOptions(buildTarget: string, context: ExecutorContext) {
@ -80,6 +81,44 @@ export default async function* moduleFederationDevServer(
} }
); );
logger.info(`NX Building ${remotes.staticRemotes.length} static remotes...`);
await new Promise<void>((res) => {
const staticProcess = fork(
nxBin,
[
'run-many',
`--target=build`,
`--projects=${remotes.staticRemotes.join(',')}`,
...(context.configurationName
? [`--configuration=${context.configurationName}`]
: []),
...(options.parallel ? [`--parallel=${options.parallel}`] : []),
],
{
cwd: context.root,
stdio: ['ignore', 'pipe', 'pipe', 'ipc'],
}
);
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, '');
if (stdoutString.includes('Successfully ran target build')) {
staticProcess.stdout.removeAllListeners('data');
logger.info(`NX Built ${remotes.staticRemotes.length} static remotes`);
res();
}
});
staticProcess.stderr.on('data', (data) => logger.info(data.toString()));
staticProcess.on('exit', (code) => {
if (code !== 0) {
throw new Error(`Remote failed to start. See above for errors.`);
}
});
process.on('SIGTERM', () => staticProcess.kill('SIGTERM'));
process.on('exit', () => staticProcess.kill('SIGTERM'));
});
let isCollectingStaticRemoteOutput = true; let isCollectingStaticRemoteOutput = true;
const devRemoteIters: AsyncIterable<{ success: boolean }>[] = []; const devRemoteIters: AsyncIterable<{ success: boolean }>[] = [];

View File

@ -101,6 +101,10 @@
"description": "Whether the host that is running this executor is the first in the project tree to do so.", "description": "Whether the host that is running this executor is the first in the project tree to do so.",
"default": true, "default": true,
"x-priority": "internal" "x-priority": "internal"
},
"parallel": {
"type": "number",
"description": "Max number of parallel processes for building static remotes"
} }
} }
} }