nx/e2e/angular/src/module-federation.rspack.test.ts
Leosvel Pérez Espinosa 752d418f78
feat(angular): support angular cli v20.0.0-rc.3 (#30715)
Add support for the Angular CLI **20.0.0-rc.3** version.
2025-05-26 10:00:47 -04:00

178 lines
5.6 KiB
TypeScript

import { names } from '@nx/devkit';
import {
checkFilesExist,
cleanupProject,
killProcessAndPorts,
newProject,
readFile,
runCLI,
runCommandUntil,
uniq,
updateFile,
updateJson,
} from '@nx/e2e/utils';
import { join } from 'path';
describe('Angular Module Federation', () => {
let proj: string;
let oldVerboseLoggingValue: string;
beforeAll(() => {
proj = newProject({ packages: ['@nx/angular'] });
oldVerboseLoggingValue = process.env.NX_E2E_VERBOSE_LOGGING;
process.env.NX_E2E_VERBOSE_LOGGING = 'true';
});
afterAll(() => {
cleanupProject();
process.env.NX_E2E_VERBOSE_LOGGING = oldVerboseLoggingValue;
});
it('should generate valid host and remote apps', async () => {
const hostApp = uniq('app');
const remoteApp1 = uniq('remote');
const sharedLib = uniq('shared-lib');
const wildcardLib = uniq('wildcard-lib');
const secondaryEntry = uniq('secondary');
const hostPort = 4300;
const remotePort = 4301;
// generate host app
runCLI(
`generate @nx/angular:host ${hostApp} --style=css --bundler=rspack --no-standalone --no-interactive`
);
let rspackConfigFileContents = readFile(join(hostApp, 'rspack.config.ts'));
let updatedConfigFileContents = rspackConfigFileContents.replace(
`maximumError: '1mb'`,
`maximumError: '3mb'`
);
updateFile(join(hostApp, 'rspack.config.ts'), updatedConfigFileContents);
// generate remote app
runCLI(
`generate @nx/angular:remote ${remoteApp1} --host=${hostApp} --bundler=rspack --port=${remotePort} --style=css --no-standalone --no-interactive`
);
rspackConfigFileContents = readFile(join(remoteApp1, 'rspack.config.ts'));
updatedConfigFileContents = rspackConfigFileContents.replace(
`maximumError: '1mb'`,
`maximumError: '3mb'`
);
updateFile(join(remoteApp1, 'rspack.config.ts'), updatedConfigFileContents);
// check files are generated without the layout directory ("apps/")
checkFilesExist(
`${hostApp}/src/app/app-module.ts`,
`${remoteApp1}/src/app/app-module.ts`
);
// check default generated host is built successfully
const buildOutput = runCLI(`build ${hostApp}`, {
env: { NODE_ENV: 'production' },
});
expect(buildOutput).toContain('Successfully ran target build');
// generate a shared lib with a seconary entry point
runCLI(
`generate @nx/angular:library ${sharedLib} --buildable --no-standalone --no-interactive`
);
runCLI(
`generate @nx/angular:library-secondary-entry-point --library=${sharedLib} --name=${secondaryEntry} --no-interactive`
);
// Add a library that will be accessed via a wildcard in tspath mappings
runCLI(
`generate @nx/angular:library ${wildcardLib} --buildable --no-standalone --no-interactive`
);
updateJson('tsconfig.base.json', (json) => {
delete json.compilerOptions.paths[`@${proj}/${wildcardLib}`];
json.compilerOptions.paths[`@${proj}/${wildcardLib}/*`] = [
`${wildcardLib}/src/lib/*`,
];
return json;
});
// update host & remote files to use shared library
updateFile(
`${hostApp}/src/app/app-module.ts`,
`import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { ${
names(wildcardLib).className
}Module } from '@${proj}/${wildcardLib}/${
names(secondaryEntry).fileName
}-module';
import { ${
names(sharedLib).className
}Module } from '@${proj}/${sharedLib}';
import { ${
names(secondaryEntry).className
}Module } from '@${proj}/${sharedLib}/${secondaryEntry}';
import { App } from './app';
import { NxWelcome } from './nx-welcome';
import { RouterModule } from '@angular/router';
@NgModule({
declarations: [App, NxWelcome],
imports: [
BrowserModule,
${names(sharedLib).className}Module,
${names(wildcardLib).className}Module,
RouterModule.forRoot(
[
{
path: '${remoteApp1}',
loadChildren: () =>
import('${remoteApp1}/Module').then(
(m) => m.RemoteEntryModule
),
},
],
{ initialNavigation: 'enabledBlocking' }
),
],
providers: [],
bootstrap: [App],
})
export class AppModule {}
`
);
updateFile(
`${remoteApp1}/src/app/remote-entry/entry-module.ts`,
`import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { ${names(sharedLib).className}Module } from '@${proj}/${sharedLib}';
import { ${
names(secondaryEntry).className
}Module } from '@${proj}/${sharedLib}/${secondaryEntry}';
import { RemoteEntry } from './entry';
import { NxWelcome } from './nx-welcome';
@NgModule({
declarations: [RemoteEntry, NxWelcome],
imports: [
CommonModule,
${names(sharedLib).className}Module,
RouterModule.forChild([
{
path: '',
component: RemoteEntry,
},
]),
],
providers: [],
})
export class RemoteEntryModule {}
`
);
const processSwc = await runCommandUntil(
`serve ${remoteApp1}`,
(output) =>
!output.includes(`Remote '${remoteApp1}' failed to serve correctly`) &&
output.includes(`Build at:`)
);
await killProcessAndPorts(processSwc.pid, remotePort);
}, 20_000_000);
});