feat(angular): replace mfe references with mf (#10957)
This commit is contained in:
parent
778f13fdaf
commit
37072bc5d6
@ -196,13 +196,13 @@
|
|||||||
"description": "Split the project configuration into `<projectRoot>/project.json` rather than including it inside `workspace.json`.",
|
"description": "Split the project configuration into `<projectRoot>/project.json` rather than including it inside `workspace.json`.",
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
"mfe": {
|
"mf": {
|
||||||
"description": "Generate a Module Federation configuration for the application",
|
"description": "Generate a Module Federation configuration for the application",
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false,
|
"default": false,
|
||||||
"x-deprecated": "Use the `host` or `remote` generators instead. Support for generating Module Federation applications using the application generator will be removed in an upcoming version."
|
"x-deprecated": "Use the `host` or `remote` generators instead. Support for generating Module Federation applications using the application generator will be removed in an upcoming version."
|
||||||
},
|
},
|
||||||
"mfeType": {
|
"mfType": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["host", "remote"],
|
"enum": ["host", "remote"],
|
||||||
"description": "Type of application to generate the Module Federation configuration for.",
|
"description": "Type of application to generate the Module Federation configuration for.",
|
||||||
@ -1732,11 +1732,11 @@
|
|||||||
"path": "/packages/angular/src/generators/scam-pipe/schema.json"
|
"path": "/packages/angular/src/generators/scam-pipe/schema.json"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "setup-mfe",
|
"name": "setup-mf",
|
||||||
"factory": "./src/generators/setup-mfe/setup-mfe",
|
"factory": "./src/generators/setup-mf/setup-mf",
|
||||||
"schema": {
|
"schema": {
|
||||||
"$schema": "http://json-schema.org/schema",
|
"$schema": "http://json-schema.org/schema",
|
||||||
"$id": "GeneratorAngularMFESetup",
|
"$id": "GeneratorAngularMFSetup",
|
||||||
"cli": "nx",
|
"cli": "nx",
|
||||||
"title": "Generate Module Federation Setup for Angular App",
|
"title": "Generate Module Federation Setup for Angular App",
|
||||||
"description": "Create Module Federation configuration files for given Angular Application.",
|
"description": "Create Module Federation configuration files for given Angular Application.",
|
||||||
@ -1748,7 +1748,7 @@
|
|||||||
"$default": { "$source": "argv", "index": 0 },
|
"$default": { "$source": "argv", "index": 0 },
|
||||||
"x-prompt": "What app would you like to generate a Module Federation configuration for?"
|
"x-prompt": "What app would you like to generate a Module Federation configuration for?"
|
||||||
},
|
},
|
||||||
"mfeType": {
|
"mfType": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["host", "remote"],
|
"enum": ["host", "remote"],
|
||||||
"description": "Type of application to generate the Module Federation configuration for.",
|
"description": "Type of application to generate the Module Federation configuration for.",
|
||||||
@ -1794,15 +1794,15 @@
|
|||||||
"description": "The prefix to use for any generated component."
|
"description": "The prefix to use for any generated component."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": ["appName", "mfeType"],
|
"required": ["appName", "mfType"],
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"presets": []
|
"presets": []
|
||||||
},
|
},
|
||||||
"description": "Generate a Module Federation configuration for a given Angular application.",
|
"description": "Generate a Module Federation configuration for a given Angular application.",
|
||||||
"implementation": "/packages/angular/src/generators/setup-mfe/setup-mfe.ts",
|
"implementation": "/packages/angular/src/generators/setup-mf/setup-mf.ts",
|
||||||
"aliases": [],
|
"aliases": [],
|
||||||
"hidden": false,
|
"hidden": false,
|
||||||
"path": "/packages/angular/src/generators/setup-mfe/schema.json"
|
"path": "/packages/angular/src/generators/setup-mf/schema.json"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "setup-tailwind",
|
"name": "setup-tailwind",
|
||||||
|
|||||||
@ -39,7 +39,7 @@
|
|||||||
"scam",
|
"scam",
|
||||||
"scam-directive",
|
"scam-directive",
|
||||||
"scam-pipe",
|
"scam-pipe",
|
||||||
"setup-mfe",
|
"setup-mf",
|
||||||
"setup-tailwind",
|
"setup-tailwind",
|
||||||
"stories",
|
"stories",
|
||||||
"storybook-configuration",
|
"storybook-configuration",
|
||||||
|
|||||||
@ -34,12 +34,12 @@ To start with, we need to create a new Nx Workspace. We can do this easily with:
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Npm
|
# Npm
|
||||||
npx create-nx-workspace ng-mfe
|
npx create-nx-workspace ng-mf
|
||||||
```
|
```
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Yarn
|
# Yarn
|
||||||
yarn create nx-workspace ng-mfe --packageManager=yarn
|
yarn create nx-workspace ng-mf --packageManager=yarn
|
||||||
```
|
```
|
||||||
|
|
||||||
You'll be prompted for a preset. We recommend selecting `empty` as it will allow you finer control over your workspace configuration.
|
You'll be prompted for a preset. We recommend selecting `empty` as it will allow you finer control over your workspace configuration.
|
||||||
@ -232,7 +232,7 @@ Next we want to set up our `entry.component.ts` file so that it renders a login
|
|||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { UserService } from '@ng-mfe/shared/data-access-user';
|
import { UserService } from '@ng-mfe/shared/data-access-user';
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ng-mfe-login-entry',
|
selector: 'ng-mf-login-entry',
|
||||||
template: `
|
template: `
|
||||||
<div class="login-app">
|
<div class="login-app">
|
||||||
<form class="login-form" (ngSubmit)="login()">
|
<form class="login-form" (ngSubmit)="login()">
|
||||||
@ -330,7 +330,7 @@ import { Router } from '@angular/router';
|
|||||||
import { distinctUntilChanged } from 'rxjs/operators';
|
import { distinctUntilChanged } from 'rxjs/operators';
|
||||||
import { UserService } from '@ng-mfe/shared/data-access-user';
|
import { UserService } from '@ng-mfe/shared/data-access-user';
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ng-mfe-root',
|
selector: 'ng-mf-root',
|
||||||
template: `
|
template: `
|
||||||
<div class="dashboard-nav">Admin Dashboard</div>
|
<div class="dashboard-nav">Admin Dashboard</div>
|
||||||
<div *ngIf="isLoggedIn$ | async; else signIn">
|
<div *ngIf="isLoggedIn$ | async; else signIn">
|
||||||
@ -399,7 +399,7 @@ We’ll start by creating this file. Add a `module-federation.manifest.json` fil
|
|||||||
Next, open `main.ts` under the `src/`folder and replace it with the following:
|
Next, open `main.ts` under the `src/`folder and replace it with the following:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { setRemoteDefinitions } from '@nrwl/angular/mfe';
|
import { setRemoteDefinitions } from '@nrwl/angular/mf';
|
||||||
|
|
||||||
fetch('/assets/module-federation.manifest.json')
|
fetch('/assets/module-federation.manifest.json')
|
||||||
.then((res) => res.json())
|
.then((res) => res.json())
|
||||||
@ -453,7 +453,7 @@ Replace it with the following:
|
|||||||
You will also need to add the following import to the top of the file:
|
You will also need to add the following import to the top of the file:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { loadRemoteModule } from '@nrwl/angular/mfe';
|
import { loadRemoteModule } from '@nrwl/angular/mf';
|
||||||
```
|
```
|
||||||
|
|
||||||
The `loadRemoteModule` helper method simply hides some logic that will check if the Remote application has been loaded, and if not, load it, and then requests the correct exposed module from it.
|
The `loadRemoteModule` helper method simply hides some logic that will check if the Remote application has been loaded, and if not, load it, and then requests the correct exposed module from it.
|
||||||
|
|||||||
@ -1,18 +1,18 @@
|
|||||||
import {
|
import {
|
||||||
checkFilesExist,
|
checkFilesExist,
|
||||||
|
cleanupProject,
|
||||||
getSize,
|
getSize,
|
||||||
killPorts,
|
killPorts,
|
||||||
newProject,
|
newProject,
|
||||||
cleanupProject,
|
promisifiedTreeKill,
|
||||||
|
readFile,
|
||||||
runCLI,
|
runCLI,
|
||||||
|
runCommandUntil,
|
||||||
|
runCypressTests,
|
||||||
tmpProjPath,
|
tmpProjPath,
|
||||||
uniq,
|
uniq,
|
||||||
updateFile,
|
updateFile,
|
||||||
runCypressTests,
|
|
||||||
updateProjectConfig,
|
updateProjectConfig,
|
||||||
readFile,
|
|
||||||
runCommandUntil,
|
|
||||||
promisifiedTreeKill,
|
|
||||||
} from '@nrwl/e2e/utils';
|
} from '@nrwl/e2e/utils';
|
||||||
import { ChildProcess } from 'child_process';
|
import { ChildProcess } from 'child_process';
|
||||||
|
|
||||||
@ -222,7 +222,7 @@ describe('Angular Projects', () => {
|
|||||||
expect(buildOutput).toContain('Successfully ran target build');
|
expect(buildOutput).toContain('Successfully ran target build');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('MFE - should serve the host and remote apps successfully, even with a shared library with a secondary entry point between them', async () => {
|
it('MF - should serve the host and remote apps successfully, even with a shared library with a secondary entry point between them', async () => {
|
||||||
// ACT + ASSERT
|
// ACT + ASSERT
|
||||||
const port1 = 4200;
|
const port1 = 4200;
|
||||||
const port2 = 4206;
|
const port2 = 4206;
|
||||||
@ -343,7 +343,7 @@ describe('Angular Projects', () => {
|
|||||||
}
|
}
|
||||||
}, 300000);
|
}, 300000);
|
||||||
|
|
||||||
it('MFE - should build the host app successfully', async () => {
|
it('MF - should build the host app successfully', async () => {
|
||||||
// ARRANGE
|
// ARRANGE
|
||||||
const hostApp = uniq('app');
|
const hostApp = uniq('app');
|
||||||
const remoteApp1 = uniq('remote');
|
const remoteApp1 = uniq('remote');
|
||||||
|
|||||||
@ -77,8 +77,8 @@ describe('nx-dev: Packages Section', () => {
|
|||||||
path: '/packages/angular/generators/scam-pipe',
|
path: '/packages/angular/generators/scam-pipe',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '@nrwl/angular:setup-mfe',
|
title: '@nrwl/angular:setup-mf',
|
||||||
path: '/packages/angular/generators/setup-mfe',
|
path: '/packages/angular/generators/setup-mf',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '@nrwl/angular:setup-tailwind',
|
title: '@nrwl/angular:setup-tailwind',
|
||||||
|
|||||||
@ -33,14 +33,20 @@ const schemaUrls = {
|
|||||||
'/angular/library': '/packages/angular/generators/library',
|
'/angular/library': '/packages/angular/generators/library',
|
||||||
'/angular/library-secondary-entry-point':
|
'/angular/library-secondary-entry-point':
|
||||||
'/packages/angular/generators/library-secondary-entry-point',
|
'/packages/angular/generators/library-secondary-entry-point',
|
||||||
'/angular/mfe-host': '/packages/angular/generators/mfe-host',
|
'/angular/mfe-host': '/packages/angular/generators/mf-host',
|
||||||
'/angular/mfe-remote': '/packages/angular/generators/mfe-remote',
|
'/angular/mfe-remote': '/packages/angular/generators/mf-remote',
|
||||||
|
'/packages/angular/generators/mfe-host':
|
||||||
|
'/packages/angular/generators/mf-host',
|
||||||
|
'/packages/angular/generators/mfe-remote':
|
||||||
|
'/packages/angular/generators/mf-remote',
|
||||||
'/angular/move': '/packages/angular/generators/move',
|
'/angular/move': '/packages/angular/generators/move',
|
||||||
'/angular/ngrx': '/packages/angular/generators/ngrx',
|
'/angular/ngrx': '/packages/angular/generators/ngrx',
|
||||||
'/angular/scam': '/packages/angular/generators/scam',
|
'/angular/scam': '/packages/angular/generators/scam',
|
||||||
'/angular/scam-directive': '/packages/angular/generators/scam-directive',
|
'/angular/scam-directive': '/packages/angular/generators/scam-directive',
|
||||||
'/angular/scam-pipe': '/packages/angular/generators/scam-pipe',
|
'/angular/scam-pipe': '/packages/angular/generators/scam-pipe',
|
||||||
'/angular/setup-mfe': '/packages/angular/generators/setup-mfe',
|
'/angular/setup-mfe': '/packages/angular/generators/setup-mf',
|
||||||
|
'/packages/angular/generators/setup-mfe':
|
||||||
|
'/packages/angular/generators/setup-mf',
|
||||||
'/angular/setup-tailwind': '/packages/angular/generators/setup-tailwind',
|
'/angular/setup-tailwind': '/packages/angular/generators/setup-tailwind',
|
||||||
'/angular/stories': '/packages/angular/generators/stories',
|
'/angular/stories': '/packages/angular/generators/stories',
|
||||||
'/angular/storybook-configuration':
|
'/angular/storybook-configuration':
|
||||||
|
|||||||
@ -121,9 +121,9 @@
|
|||||||
"schema": "./src/generators/scam-pipe/schema.json",
|
"schema": "./src/generators/scam-pipe/schema.json",
|
||||||
"description": "Generate a pipe with an accompanying Single Component Angular Module (SCAM)."
|
"description": "Generate a pipe with an accompanying Single Component Angular Module (SCAM)."
|
||||||
},
|
},
|
||||||
"setup-mfe": {
|
"setup-mf": {
|
||||||
"factory": "./src/generators/setup-mfe/setup-mfe.compat",
|
"factory": "./src/generators/setup-mf/setup-mf.compat",
|
||||||
"schema": "./src/generators/setup-mfe/schema.json",
|
"schema": "./src/generators/setup-mf/schema.json",
|
||||||
"description": "Generate a Module Federation configuration for a given Angular application."
|
"description": "Generate a Module Federation configuration for a given Angular application."
|
||||||
},
|
},
|
||||||
"setup-tailwind": {
|
"setup-tailwind": {
|
||||||
@ -277,9 +277,9 @@
|
|||||||
"schema": "./src/generators/scam-pipe/schema.json",
|
"schema": "./src/generators/scam-pipe/schema.json",
|
||||||
"description": "Generate a pipe with an accompanying Single Component Angular Module (SCAM)."
|
"description": "Generate a pipe with an accompanying Single Component Angular Module (SCAM)."
|
||||||
},
|
},
|
||||||
"setup-mfe": {
|
"setup-mf": {
|
||||||
"factory": "./src/generators/setup-mfe/setup-mfe",
|
"factory": "./src/generators/setup-mf/setup-mf",
|
||||||
"schema": "./src/generators/setup-mfe/schema.json",
|
"schema": "./src/generators/setup-mf/schema.json",
|
||||||
"description": "Generate a Module Federation configuration for a given Angular application."
|
"description": "Generate a Module Federation configuration for a given Angular application."
|
||||||
},
|
},
|
||||||
"setup-tailwind": {
|
"setup-tailwind": {
|
||||||
|
|||||||
@ -12,7 +12,7 @@ export * from './src/generators/setup-tailwind/setup-tailwind';
|
|||||||
export * from './src/generators/stories/stories';
|
export * from './src/generators/stories/stories';
|
||||||
export * from './src/generators/storybook-configuration/storybook-configuration';
|
export * from './src/generators/storybook-configuration/storybook-configuration';
|
||||||
export * from './src/generators/upgrade-module/upgrade-module';
|
export * from './src/generators/upgrade-module/upgrade-module';
|
||||||
export * from './src/generators/setup-mfe/setup-mfe';
|
export * from './src/generators/setup-mf/setup-mf';
|
||||||
export * from './src/generators/host/host';
|
export * from './src/generators/host/host';
|
||||||
export * from './src/generators/scam/scam';
|
export * from './src/generators/scam/scam';
|
||||||
export * from './src/generators/scam-directive/scam-directive';
|
export * from './src/generators/scam-directive/scam-directive';
|
||||||
|
|||||||
@ -2,4 +2,4 @@ export {
|
|||||||
setRemoteUrlResolver,
|
setRemoteUrlResolver,
|
||||||
setRemoteDefinitions,
|
setRemoteDefinitions,
|
||||||
loadRemoteModule,
|
loadRemoteModule,
|
||||||
} from './mfe';
|
} from './mf';
|
||||||
@ -89,11 +89,11 @@
|
|||||||
"description": "A lot of changes to how MFEs operate were discovered and merged without appropriate migrations. This should cover migrating existing MFEs to the latest, using ESM and optmized production bundles.",
|
"description": "A lot of changes to how MFEs operate were discovered and merged without appropriate migrations. This should cover migrating existing MFEs to the latest, using ESM and optmized production bundles.",
|
||||||
"factory": "./src/migrations/update-13-5-0/update-mfe-configs"
|
"factory": "./src/migrations/update-13-5-0/update-mfe-configs"
|
||||||
},
|
},
|
||||||
"add-cypress-mfe-workaround": {
|
"add-cypress-mf-workaround": {
|
||||||
"cli": "nx",
|
"cli": "nx",
|
||||||
"version": "13.8.1",
|
"version": "13.8.1",
|
||||||
"description": "Angular doesn't attach styles.js to index.html with type=module in dev mode, meaning an error is written to the console. Cypress falls over on this error. Add logic to Cypress e2e projects to ignore this error.",
|
"description": "Angular doesn't attach styles.js to index.html with type=module in dev mode, meaning an error is written to the console. Cypress falls over on this error. Add logic to Cypress e2e projects to ignore this error.",
|
||||||
"factory": "./src/migrations/update-13-8-1/add-cypress-mfe-workaround"
|
"factory": "./src/migrations/update-13-8-1/add-cypress-mf-workaround"
|
||||||
},
|
},
|
||||||
"migrate-karma-config": {
|
"migrate-karma-config": {
|
||||||
"cli": "nx",
|
"cli": "nx",
|
||||||
@ -148,6 +148,12 @@
|
|||||||
"version": "14.2.0-beta.6",
|
"version": "14.2.0-beta.6",
|
||||||
"description": "Update `initialNavigation: 'enabled'` to `initialNavigation: 'enabledBlocking'`.",
|
"description": "Update `initialNavigation: 'enabled'` to `initialNavigation: 'enabledBlocking'`.",
|
||||||
"factory": "./src/migrations/update-14-2-0/update-router-initial-navigation"
|
"factory": "./src/migrations/update-14-2-0/update-router-initial-navigation"
|
||||||
|
},
|
||||||
|
"migrate-mfe-to-mf": {
|
||||||
|
"cli": "nx",
|
||||||
|
"version": "14.5.0-beta.0",
|
||||||
|
"description": "Update any references of MFE to MF.",
|
||||||
|
"factory": "./src/migrations/update-14-5-0/migrate-mfe-to-mf"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"packageJsonUpdates": {
|
"packageJsonUpdates": {
|
||||||
|
|||||||
@ -1,2 +1,2 @@
|
|||||||
export { withModuleFederation } from '../src/utils/mfe/with-module-federation';
|
export { withModuleFederation } from '../src/utils/mf/with-module-federation';
|
||||||
export * from '../src/utils/mfe/mfe-webpack';
|
export * from '../src/utils/mf/mf-webpack';
|
||||||
|
|||||||
@ -1,24 +1,24 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`app --mfe should add a remote application and add it to a specified host applications webpack config that contains a remote application already 1`] = `
|
exports[`app --mf should add a remote application and add it to a specified host applications webpack config that contains a remote application already 1`] = `
|
||||||
"const { withModuleFederation } = require('@nrwl/angular/module-federation');
|
"const { withModuleFederation } = require('@nrwl/angular/module-federation');
|
||||||
const config = require('./module-federation.config');
|
const config = require('./module-federation.config');
|
||||||
module.exports = withModuleFederation(config);"
|
module.exports = withModuleFederation(config);"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`app --mfe should add a remote application and add it to a specified host applications webpack config when no other remote has been added to it 1`] = `
|
exports[`app --mf should add a remote application and add it to a specified host applications webpack config when no other remote has been added to it 1`] = `
|
||||||
"const { withModuleFederation } = require('@nrwl/angular/module-federation');
|
"const { withModuleFederation } = require('@nrwl/angular/module-federation');
|
||||||
const config = require('./module-federation.config');
|
const config = require('./module-federation.config');
|
||||||
module.exports = withModuleFederation(config);"
|
module.exports = withModuleFederation(config);"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`app --mfe should generate a Module Federation correctly for a each app 1`] = `
|
exports[`app --mf should generate a Module Federation correctly for a each app 1`] = `
|
||||||
"const { withModuleFederation } = require('@nrwl/angular/module-federation');
|
"const { withModuleFederation } = require('@nrwl/angular/module-federation');
|
||||||
const config = require('./module-federation.config');
|
const config = require('./module-federation.config');
|
||||||
module.exports = withModuleFederation(config);"
|
module.exports = withModuleFederation(config);"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`app --mfe should generate a Module Federation correctly for a each app 2`] = `
|
exports[`app --mf should generate a Module Federation correctly for a each app 2`] = `
|
||||||
"const { withModuleFederation } = require('@nrwl/angular/module-federation');
|
"const { withModuleFederation } = require('@nrwl/angular/module-federation');
|
||||||
const config = require('./module-federation.config');
|
const config = require('./module-federation.config');
|
||||||
module.exports = withModuleFederation(config);"
|
module.exports = withModuleFederation(config);"
|
||||||
|
|||||||
@ -906,11 +906,11 @@ describe('app', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('--mfe', () => {
|
describe('--mf', () => {
|
||||||
test.each(['host', 'remote'])(
|
test.each(['host', 'remote'])(
|
||||||
'should generate a Module Federation correctly for a each app',
|
'should generate a Module Federation correctly for a each app',
|
||||||
async (type: 'host' | 'remote') => {
|
async (type: 'host' | 'remote') => {
|
||||||
await generateApp(appTree, 'my-app', { mfe: true, mfeType: type });
|
await generateApp(appTree, 'my-app', { mf: true, mfType: type });
|
||||||
|
|
||||||
expect(appTree.exists(`apps/my-app/webpack.config.js`)).toBeTruthy();
|
expect(appTree.exists(`apps/my-app/webpack.config.js`)).toBeTruthy();
|
||||||
expect(
|
expect(
|
||||||
@ -925,7 +925,7 @@ describe('app', () => {
|
|||||||
test.each(['host', 'remote'])(
|
test.each(['host', 'remote'])(
|
||||||
'should update the builder to use webpack-browser',
|
'should update the builder to use webpack-browser',
|
||||||
async (type: 'host' | 'remote') => {
|
async (type: 'host' | 'remote') => {
|
||||||
await generateApp(appTree, 'my-app', { mfe: true, mfeType: type });
|
await generateApp(appTree, 'my-app', { mf: true, mfType: type });
|
||||||
|
|
||||||
const projectConfig = readProjectConfiguration(appTree, 'my-app');
|
const projectConfig = readProjectConfiguration(appTree, 'my-app');
|
||||||
|
|
||||||
@ -938,14 +938,14 @@ describe('app', () => {
|
|||||||
it('should add a remote application and add it to a specified host applications webpack config when no other remote has been added to it', async () => {
|
it('should add a remote application and add it to a specified host applications webpack config when no other remote has been added to it', async () => {
|
||||||
// ARRANGE
|
// ARRANGE
|
||||||
await generateApp(appTree, 'app1', {
|
await generateApp(appTree, 'app1', {
|
||||||
mfe: true,
|
mf: true,
|
||||||
mfeType: 'host',
|
mfType: 'host',
|
||||||
});
|
});
|
||||||
|
|
||||||
// ACT
|
// ACT
|
||||||
await generateApp(appTree, 'remote1', {
|
await generateApp(appTree, 'remote1', {
|
||||||
mfe: true,
|
mf: true,
|
||||||
mfeType: 'remote',
|
mfType: 'remote',
|
||||||
host: 'app1',
|
host: 'app1',
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -960,21 +960,21 @@ describe('app', () => {
|
|||||||
it('should add a remote application and add it to a specified host applications webpack config that contains a remote application already', async () => {
|
it('should add a remote application and add it to a specified host applications webpack config that contains a remote application already', async () => {
|
||||||
// ARRANGE
|
// ARRANGE
|
||||||
await generateApp(appTree, 'app1', {
|
await generateApp(appTree, 'app1', {
|
||||||
mfe: true,
|
mf: true,
|
||||||
mfeType: 'host',
|
mfType: 'host',
|
||||||
});
|
});
|
||||||
|
|
||||||
await generateApp(appTree, 'remote1', {
|
await generateApp(appTree, 'remote1', {
|
||||||
mfe: true,
|
mf: true,
|
||||||
mfeType: 'remote',
|
mfType: 'remote',
|
||||||
host: 'app1',
|
host: 'app1',
|
||||||
port: 4201,
|
port: 4201,
|
||||||
});
|
});
|
||||||
|
|
||||||
// ACT
|
// ACT
|
||||||
await generateApp(appTree, 'remote2', {
|
await generateApp(appTree, 'remote2', {
|
||||||
mfe: true,
|
mf: true,
|
||||||
mfeType: 'remote',
|
mfType: 'remote',
|
||||||
host: 'app1',
|
host: 'app1',
|
||||||
port: 4202,
|
port: 4202,
|
||||||
});
|
});
|
||||||
@ -987,7 +987,7 @@ describe('app', () => {
|
|||||||
expect(hostWebpackConfig).toMatchSnapshot();
|
expect(hostWebpackConfig).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should add a port to a non-mfe app', async () => {
|
it('should add a port to a non-mf app', async () => {
|
||||||
// ACT
|
// ACT
|
||||||
await generateApp(appTree, 'app1', {
|
await generateApp(appTree, 'app1', {
|
||||||
port: 4205,
|
port: 4205,
|
||||||
|
|||||||
@ -12,7 +12,7 @@ import { setupTailwindGenerator } from '../setup-tailwind/setup-tailwind';
|
|||||||
import {
|
import {
|
||||||
addE2e,
|
addE2e,
|
||||||
addLinting,
|
addLinting,
|
||||||
addMfe,
|
addMf,
|
||||||
addProxyConfig,
|
addProxyConfig,
|
||||||
addRouterRootConfiguration,
|
addRouterRootConfiguration,
|
||||||
addUnitTestRunner,
|
addUnitTestRunner,
|
||||||
@ -126,8 +126,8 @@ export async function applicationGenerator(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.mfe) {
|
if (options.mf) {
|
||||||
await addMfe(host, options);
|
await addMf(host, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!options.skipFormat) {
|
if (!options.skipFormat) {
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
import type { Tree } from '@nrwl/devkit';
|
import type { Tree } from '@nrwl/devkit';
|
||||||
import type { NormalizedSchema } from './normalized-schema';
|
import type { NormalizedSchema } from './normalized-schema';
|
||||||
|
|
||||||
import { setupMfe } from '../../setup-mfe/setup-mfe';
|
import { setupMf } from '../../setup-mf/setup-mf';
|
||||||
|
|
||||||
export async function addMfe(host: Tree, options: NormalizedSchema) {
|
export async function addMf(host: Tree, options: NormalizedSchema) {
|
||||||
await setupMfe(host, {
|
await setupMf(host, {
|
||||||
appName: options.name,
|
appName: options.name,
|
||||||
mfeType: options.mfeType,
|
mfType: options.mfType,
|
||||||
port: options.port,
|
port: options.port,
|
||||||
remotes: options.remotes,
|
remotes: options.remotes,
|
||||||
host: options.host,
|
host: options.host,
|
||||||
@ -1,6 +1,6 @@
|
|||||||
export * from './add-e2e';
|
export * from './add-e2e';
|
||||||
export * from './add-linting';
|
export * from './add-linting';
|
||||||
export * from './add-mfe';
|
export * from './add-mf';
|
||||||
export * from './add-protractor';
|
export * from './add-protractor';
|
||||||
export * from './add-proxy-config';
|
export * from './add-proxy-config';
|
||||||
export * from './add-unit-test-runner';
|
export * from './add-unit-test-runner';
|
||||||
|
|||||||
@ -23,8 +23,8 @@ export interface Schema {
|
|||||||
backendProject?: string;
|
backendProject?: string;
|
||||||
strict?: boolean;
|
strict?: boolean;
|
||||||
standaloneConfig?: boolean;
|
standaloneConfig?: boolean;
|
||||||
mfe?: boolean;
|
mf?: boolean;
|
||||||
mfeType?: 'host' | 'remote';
|
mfType?: 'host' | 'remote';
|
||||||
remotes?: string[];
|
remotes?: string[];
|
||||||
port?: number;
|
port?: number;
|
||||||
host?: string;
|
host?: string;
|
||||||
|
|||||||
@ -133,13 +133,13 @@
|
|||||||
"description": "Split the project configuration into `<projectRoot>/project.json` rather than including it inside `workspace.json`.",
|
"description": "Split the project configuration into `<projectRoot>/project.json` rather than including it inside `workspace.json`.",
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
"mfe": {
|
"mf": {
|
||||||
"description": "Generate a Module Federation configuration for the application",
|
"description": "Generate a Module Federation configuration for the application",
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false,
|
"default": false,
|
||||||
"x-deprecated": "Use the `host` or `remote` generators instead. Support for generating Module Federation applications using the application generator will be removed in an upcoming version."
|
"x-deprecated": "Use the `host` or `remote` generators instead. Support for generating Module Federation applications using the application generator will be removed in an upcoming version."
|
||||||
},
|
},
|
||||||
"mfeType": {
|
"mfType": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["host", "remote"],
|
"enum": ["host", "remote"],
|
||||||
"description": "Type of application to generate the Module Federation configuration for.",
|
"description": "Type of application to generate the Module Federation configuration for.",
|
||||||
|
|||||||
@ -23,8 +23,8 @@ describe('Host App Generator', () => {
|
|||||||
|
|
||||||
await applicationGenerator(tree, {
|
await applicationGenerator(tree, {
|
||||||
name: 'remote',
|
name: 'remote',
|
||||||
mfe: true,
|
mf: true,
|
||||||
mfeType: 'remote',
|
mfType: 'remote',
|
||||||
routing: true,
|
routing: true,
|
||||||
port: 4201,
|
port: 4201,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -31,8 +31,8 @@ export default async function host(tree: Tree, options: Schema) {
|
|||||||
|
|
||||||
const installTask = await applicationGenerator(tree, {
|
const installTask = await applicationGenerator(tree, {
|
||||||
...options,
|
...options,
|
||||||
mfe: true,
|
mf: true,
|
||||||
mfeType: 'host',
|
mfType: 'host',
|
||||||
routing: true,
|
routing: true,
|
||||||
remotes: remotesToIntegrate ?? [],
|
remotes: remotesToIntegrate ?? [],
|
||||||
port: 4200,
|
port: 4200,
|
||||||
|
|||||||
@ -1,18 +1,18 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`MFE Remote App Generator should generate a remote mfe app with a host 1`] = `
|
exports[`MF Remote App Generator should generate a remote mf app with a host 1`] = `
|
||||||
"const { withModuleFederation } = require('@nrwl/angular/module-federation');
|
"const { withModuleFederation } = require('@nrwl/angular/module-federation');
|
||||||
const config = require('./module-federation.config');
|
const config = require('./module-federation.config');
|
||||||
module.exports = withModuleFederation(config);"
|
module.exports = withModuleFederation(config);"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`MFE Remote App Generator should generate a remote mfe app with a host 2`] = `
|
exports[`MF Remote App Generator should generate a remote mf app with a host 2`] = `
|
||||||
"const { withModuleFederation } = require('@nrwl/angular/module-federation');
|
"const { withModuleFederation } = require('@nrwl/angular/module-federation');
|
||||||
const config = require('./module-federation.config');
|
const config = require('./module-federation.config');
|
||||||
module.exports = withModuleFederation(config);"
|
module.exports = withModuleFederation(config);"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`MFE Remote App Generator should generate a remote mfe app with no host 1`] = `
|
exports[`MF Remote App Generator should generate a remote mf app with no host 1`] = `
|
||||||
"const { withModuleFederation } = require('@nrwl/angular/module-federation');
|
"const { withModuleFederation } = require('@nrwl/angular/module-federation');
|
||||||
const config = require('./module-federation.config');
|
const config = require('./module-federation.config');
|
||||||
module.exports = withModuleFederation(config);"
|
module.exports = withModuleFederation(config);"
|
||||||
|
|||||||
@ -3,8 +3,8 @@ import remote from './remote';
|
|||||||
import applicationGenerator from '../application/application';
|
import applicationGenerator from '../application/application';
|
||||||
import { readProjectConfiguration } from '@nrwl/devkit';
|
import { readProjectConfiguration } from '@nrwl/devkit';
|
||||||
|
|
||||||
describe('MFE Remote App Generator', () => {
|
describe('MF Remote App Generator', () => {
|
||||||
it('should generate a remote mfe app with no host', async () => {
|
it('should generate a remote mf app with no host', async () => {
|
||||||
// ARRANGE
|
// ARRANGE
|
||||||
const tree = createTreeWithEmptyWorkspace(2);
|
const tree = createTreeWithEmptyWorkspace(2);
|
||||||
|
|
||||||
@ -18,14 +18,14 @@ describe('MFE Remote App Generator', () => {
|
|||||||
expect(tree.read('apps/test/webpack.config.js', 'utf-8')).toMatchSnapshot();
|
expect(tree.read('apps/test/webpack.config.js', 'utf-8')).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should generate a remote mfe app with a host', async () => {
|
it('should generate a remote mf app with a host', async () => {
|
||||||
// ARRANGE
|
// ARRANGE
|
||||||
const tree = createTreeWithEmptyWorkspace(2);
|
const tree = createTreeWithEmptyWorkspace(2);
|
||||||
|
|
||||||
await applicationGenerator(tree, {
|
await applicationGenerator(tree, {
|
||||||
name: 'host',
|
name: 'host',
|
||||||
mfe: true,
|
mf: true,
|
||||||
mfeType: 'host',
|
mfType: 'host',
|
||||||
routing: true,
|
routing: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -60,7 +60,7 @@ describe('MFE Remote App Generator', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should generate a remote mfe app and automatically find the next port available', async () => {
|
it('should generate a remote mf app and automatically find the next port available', async () => {
|
||||||
// ARRANGE
|
// ARRANGE
|
||||||
const tree = createTreeWithEmptyWorkspace(2);
|
const tree = createTreeWithEmptyWorkspace(2);
|
||||||
await remote(tree, {
|
await remote(tree, {
|
||||||
@ -78,7 +78,7 @@ describe('MFE Remote App Generator', () => {
|
|||||||
expect(project.targets.serve.options.port).toEqual(4202);
|
expect(project.targets.serve.options.port).toEqual(4202);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should generate a remote mfe app and automatically find the next port available even when there are no other targets', async () => {
|
it('should generate a remote mf app and automatically find the next port available even when there are no other targets', async () => {
|
||||||
// ARRANGE
|
// ARRANGE
|
||||||
const tree = createTreeWithEmptyWorkspace(2);
|
const tree = createTreeWithEmptyWorkspace(2);
|
||||||
|
|
||||||
|
|||||||
@ -10,11 +10,11 @@ import { getMFProjects } from '../../utils/get-mf-projects';
|
|||||||
import { normalizeProjectName } from '../utils/project';
|
import { normalizeProjectName } from '../utils/project';
|
||||||
|
|
||||||
function findNextAvailablePort(tree: Tree) {
|
function findNextAvailablePort(tree: Tree) {
|
||||||
const mfeProjects = getMFProjects(tree);
|
const mfProjects = getMFProjects(tree);
|
||||||
|
|
||||||
const ports = new Set<number>([4200]);
|
const ports = new Set<number>([4200]);
|
||||||
for (const mfeProject of mfeProjects) {
|
for (const mfProject of mfProjects) {
|
||||||
const { targets } = readProjectConfiguration(tree, mfeProject);
|
const { targets } = readProjectConfiguration(tree, mfProject);
|
||||||
const port = targets?.serve?.options?.port ?? 4200;
|
const port = targets?.serve?.options?.port ?? 4200;
|
||||||
ports.add(port);
|
ports.add(port);
|
||||||
}
|
}
|
||||||
@ -34,8 +34,8 @@ export default async function remote(tree: Tree, options: Schema) {
|
|||||||
|
|
||||||
const installTask = await applicationGenerator(tree, {
|
const installTask = await applicationGenerator(tree, {
|
||||||
...options,
|
...options,
|
||||||
mfe: true,
|
mf: true,
|
||||||
mfeType: 'remote',
|
mfType: 'remote',
|
||||||
routing: true,
|
routing: true,
|
||||||
host: options.host,
|
host: options.host,
|
||||||
port: options.port ?? findNextAvailablePort(tree),
|
port: options.port ?? findNextAvailablePort(tree),
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`Init MFE --federationType=dynamic should create a host with the correct configurations 1`] = `
|
exports[`Init MF --federationType=dynamic should create a host with the correct configurations 1`] = `
|
||||||
"import { setRemoteDefinitions } from '@nrwl/angular/mfe';
|
"import { setRemoteDefinitions } from '@nrwl/angular/mf';
|
||||||
|
|
||||||
fetch('/assets/module-federation.manifest.json')
|
fetch('/assets/module-federation.manifest.json')
|
||||||
.then((res) => res.json())
|
.then((res) => res.json())
|
||||||
@ -9,7 +9,7 @@ exports[`Init MFE --federationType=dynamic should create a host with the correct
|
|||||||
.then(() => import('./bootstrap').catch(err => console.error(err)))"
|
.then(() => import('./bootstrap').catch(err => console.error(err)))"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`Init MFE should add a remote application and add it to a specified host applications router config 1`] = `
|
exports[`Init MF should add a remote application and add it to a specified host applications router config 1`] = `
|
||||||
"import { NgModule } from '@angular/core';
|
"import { NgModule } from '@angular/core';
|
||||||
import { BrowserModule } from '@angular/platform-browser';
|
import { BrowserModule } from '@angular/platform-browser';
|
||||||
|
|
||||||
@ -39,28 +39,28 @@ export class AppModule { }
|
|||||||
"
|
"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`Init MFE should add a remote application and add it to a specified host applications webpack config that contains a remote application already 1`] = `
|
exports[`Init MF should add a remote application and add it to a specified host applications webpack config that contains a remote application already 1`] = `
|
||||||
"module.exports = {
|
"module.exports = {
|
||||||
name: 'app1',
|
name: 'app1',
|
||||||
remotes: ['remote1','remote2',]
|
remotes: ['remote1','remote2',]
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`Init MFE should add a remote application and add it to a specified host applications webpack config when no other remote has been added to it 1`] = `
|
exports[`Init MF should add a remote application and add it to a specified host applications webpack config when no other remote has been added to it 1`] = `
|
||||||
"module.exports = {
|
"module.exports = {
|
||||||
name: 'app1',
|
name: 'app1',
|
||||||
remotes: ['remote1',]
|
remotes: ['remote1',]
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`Init MFE should add a remote to dynamic host correctly 1`] = `
|
exports[`Init MF should add a remote to dynamic host correctly 1`] = `
|
||||||
"import { NgModule } from '@angular/core';
|
"import { NgModule } from '@angular/core';
|
||||||
import { BrowserModule } from '@angular/platform-browser';
|
import { BrowserModule } from '@angular/platform-browser';
|
||||||
|
|
||||||
import { AppComponent } from './app.component';
|
import { AppComponent } from './app.component';
|
||||||
import { NxWelcomeComponent } from './nx-welcome.component';
|
import { NxWelcomeComponent } from './nx-welcome.component';
|
||||||
import { RouterModule } from '@angular/router';
|
import { RouterModule } from '@angular/router';
|
||||||
import { loadRemoteModule } from '@nrwl/angular/mfe';
|
import { loadRemoteModule } from '@nrwl/angular/mf';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
@ -81,26 +81,26 @@ export class AppModule { }
|
|||||||
"
|
"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`Init MFE should create webpack and mfe configs correctly 1`] = `
|
exports[`Init MF should create webpack and mf configs correctly 1`] = `
|
||||||
"const { withModuleFederation } = require('@nrwl/angular/module-federation');
|
"const { withModuleFederation } = require('@nrwl/angular/module-federation');
|
||||||
const config = require('./module-federation.config');
|
const config = require('./module-federation.config');
|
||||||
module.exports = withModuleFederation(config);"
|
module.exports = withModuleFederation(config);"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`Init MFE should create webpack and mfe configs correctly 2`] = `
|
exports[`Init MF should create webpack and mf configs correctly 2`] = `
|
||||||
"module.exports = {
|
"module.exports = {
|
||||||
name: 'app1',
|
name: 'app1',
|
||||||
remotes: []
|
remotes: []
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`Init MFE should create webpack and mfe configs correctly 3`] = `
|
exports[`Init MF should create webpack and mf configs correctly 3`] = `
|
||||||
"const { withModuleFederation } = require('@nrwl/angular/module-federation');
|
"const { withModuleFederation } = require('@nrwl/angular/module-federation');
|
||||||
const config = require('./module-federation.config');
|
const config = require('./module-federation.config');
|
||||||
module.exports = withModuleFederation(config);"
|
module.exports = withModuleFederation(config);"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`Init MFE should create webpack and mfe configs correctly 4`] = `
|
exports[`Init MF should create webpack and mf configs correctly 4`] = `
|
||||||
"module.exports = {
|
"module.exports = {
|
||||||
name: 'remote1',
|
name: 'remote1',
|
||||||
exposes: {
|
exposes: {
|
||||||
@ -109,7 +109,7 @@ exports[`Init MFE should create webpack and mfe configs correctly 4`] = `
|
|||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`Init MFE should generate the remote entry component correctly when prefix is not provided 1`] = `
|
exports[`Init MF should generate the remote entry component correctly when prefix is not provided 1`] = `
|
||||||
"import { Component } from '@angular/core';
|
"import { Component } from '@angular/core';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -120,7 +120,7 @@ export class RemoteEntryComponent {}
|
|||||||
"
|
"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`Init MFE should generate the remote entry module and component correctly 1`] = `
|
exports[`Init MF should generate the remote entry module and component correctly 1`] = `
|
||||||
"import { Component } from '@angular/core';
|
"import { Component } from '@angular/core';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -131,7 +131,7 @@ export class RemoteEntryComponent {}
|
|||||||
"
|
"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`Init MFE should generate the remote entry module and component correctly 2`] = `
|
exports[`Init MF should generate the remote entry module and component correctly 2`] = `
|
||||||
"import { NgModule } from '@angular/core';
|
"import { NgModule } from '@angular/core';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
|
|
||||||
@ -4,10 +4,10 @@ import type { Schema } from '../schema';
|
|||||||
|
|
||||||
export function addEntryModule(
|
export function addEntryModule(
|
||||||
host: Tree,
|
host: Tree,
|
||||||
{ appName, routing, mfeType, prefix }: Schema,
|
{ appName, routing, mfType, prefix }: Schema,
|
||||||
appRoot: string
|
appRoot: string
|
||||||
) {
|
) {
|
||||||
if (mfeType === 'remote') {
|
if (mfType === 'remote') {
|
||||||
generateFiles(
|
generateFiles(
|
||||||
host,
|
host,
|
||||||
joinPathFragments(__dirname, '../files/entry-module-files'),
|
joinPathFragments(__dirname, '../files/entry-module-files'),
|
||||||
@ -13,8 +13,8 @@ import { ArrayLiteralExpression } from 'typescript';
|
|||||||
import { addRoute } from '../../../utils/nx-devkit/ast-utils';
|
import { addRoute } from '../../../utils/nx-devkit/ast-utils';
|
||||||
import { insertImport } from '@nrwl/workspace/src/utilities/ast-utils';
|
import { insertImport } from '@nrwl/workspace/src/utilities/ast-utils';
|
||||||
|
|
||||||
export function checkIsCommaNeeded(mfeRemoteText: string) {
|
export function checkIsCommaNeeded(mfRemoteText: string) {
|
||||||
const remoteText = mfeRemoteText.replace(/\s+/g, '');
|
const remoteText = mfRemoteText.replace(/\s+/g, '');
|
||||||
return !remoteText.endsWith(',]')
|
return !remoteText.endsWith(',]')
|
||||||
? remoteText === '[]'
|
? remoteText === '[]'
|
||||||
? false
|
? false
|
||||||
@ -23,7 +23,7 @@ export function checkIsCommaNeeded(mfeRemoteText: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function addRemoteToHost(tree: Tree, options: Schema) {
|
export function addRemoteToHost(tree: Tree, options: Schema) {
|
||||||
if (options.mfeType === 'remote' && options.host) {
|
if (options.mfType === 'remote' && options.host) {
|
||||||
const hostProject = readProjectConfiguration(tree, options.host);
|
const hostProject = readProjectConfiguration(tree, options.host);
|
||||||
const pathToMFManifest = joinPathFragments(
|
const pathToMFManifest = joinPathFragments(
|
||||||
hostProject.sourceRoot,
|
hostProject.sourceRoot,
|
||||||
@ -57,9 +57,9 @@ export function addRemoteToHost(tree: Tree, options: Schema) {
|
|||||||
|
|
||||||
function determineHostFederationType(
|
function determineHostFederationType(
|
||||||
tree: Tree,
|
tree: Tree,
|
||||||
pathToMfeManifest: string
|
pathToMfManifest: string
|
||||||
): 'dynamic' | 'static' {
|
): 'dynamic' | 'static' {
|
||||||
return tree.exists(pathToMfeManifest) ? 'dynamic' : 'static';
|
return tree.exists(pathToMfManifest) ? 'dynamic' : 'static';
|
||||||
}
|
}
|
||||||
|
|
||||||
function addRemoteToStaticHost(
|
function addRemoteToStaticHost(
|
||||||
@ -99,9 +99,9 @@ function addRemoteToStaticHost(
|
|||||||
function addRemoteToDynamicHost(
|
function addRemoteToDynamicHost(
|
||||||
tree: Tree,
|
tree: Tree,
|
||||||
options: Schema,
|
options: Schema,
|
||||||
pathToMfeManifest: string
|
pathToMfManifest: string
|
||||||
) {
|
) {
|
||||||
updateJson(tree, pathToMfeManifest, (manifest) => {
|
updateJson(tree, pathToMfManifest, (manifest) => {
|
||||||
return {
|
return {
|
||||||
...manifest,
|
...manifest,
|
||||||
[options.appName]: `http://localhost:${options.port}`,
|
[options.appName]: `http://localhost:${options.port}`,
|
||||||
@ -139,7 +139,7 @@ function addLazyLoadedRouteToHostAppModule(
|
|||||||
sourceFile,
|
sourceFile,
|
||||||
pathToHostAppModule,
|
pathToHostAppModule,
|
||||||
'loadRemoteModule',
|
'loadRemoteModule',
|
||||||
'@nrwl/angular/mfe'
|
'@nrwl/angular/mf'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const routeToAdd =
|
const routeToAdd =
|
||||||
@ -1,7 +1,6 @@
|
|||||||
import type { Tree } from '@nrwl/devkit';
|
import type { Tree } from '@nrwl/devkit';
|
||||||
import type { Schema } from '../schema';
|
|
||||||
|
|
||||||
import { joinPathFragments } from '@nrwl/devkit';
|
import { joinPathFragments } from '@nrwl/devkit';
|
||||||
|
import type { Schema } from '../schema';
|
||||||
|
|
||||||
export function fixBootstrap(tree: Tree, appRoot: string, options: Schema) {
|
export function fixBootstrap(tree: Tree, appRoot: string, options: Schema) {
|
||||||
const mainFilePath = joinPathFragments(appRoot, 'src/main.ts');
|
const mainFilePath = joinPathFragments(appRoot, 'src/main.ts');
|
||||||
@ -10,7 +9,7 @@ export function fixBootstrap(tree: Tree, appRoot: string, options: Schema) {
|
|||||||
|
|
||||||
const bootstrapImportCode = `import('./bootstrap').catch(err => console.error(err))`;
|
const bootstrapImportCode = `import('./bootstrap').catch(err => console.error(err))`;
|
||||||
|
|
||||||
const fetchMFManifestCode = `import { setRemoteDefinitions } from '@nrwl/angular/mfe';
|
const fetchMFManifestCode = `import { setRemoteDefinitions } from '@nrwl/angular/mf';
|
||||||
|
|
||||||
fetch('/assets/module-federation.manifest.json')
|
fetch('/assets/module-federation.manifest.json')
|
||||||
.then((res) => res.json())
|
.then((res) => res.json())
|
||||||
@ -19,7 +18,7 @@ export function fixBootstrap(tree: Tree, appRoot: string, options: Schema) {
|
|||||||
|
|
||||||
tree.write(
|
tree.write(
|
||||||
mainFilePath,
|
mainFilePath,
|
||||||
options.mfeType === 'host' && options.federationType === 'dynamic'
|
options.mfType === 'host' && options.federationType === 'dynamic'
|
||||||
? fetchMFManifestCode
|
? fetchMFManifestCode
|
||||||
: bootstrapImportCode
|
: bootstrapImportCode
|
||||||
);
|
);
|
||||||
@ -25,7 +25,7 @@ export function generateWebpackConfig(
|
|||||||
appRoot,
|
appRoot,
|
||||||
{
|
{
|
||||||
tmpl: '',
|
tmpl: '',
|
||||||
type: options.mfeType,
|
type: options.mfType,
|
||||||
name: options.appName,
|
name: options.appName,
|
||||||
remotes: remotesWithPorts ?? [],
|
remotes: remotesWithPorts ?? [],
|
||||||
projectRoot: appRoot,
|
projectRoot: appRoot,
|
||||||
@ -1,13 +1,12 @@
|
|||||||
import type { Tree } from '@nrwl/devkit';
|
import type { Tree } from '@nrwl/devkit';
|
||||||
import type { Schema } from '../schema';
|
|
||||||
|
|
||||||
import { readProjectConfiguration } from '@nrwl/devkit';
|
import { readProjectConfiguration } from '@nrwl/devkit';
|
||||||
|
import type { Schema } from '../schema';
|
||||||
|
|
||||||
export function getRemotesWithPorts(host: Tree, options: Schema) {
|
export function getRemotesWithPorts(host: Tree, options: Schema) {
|
||||||
// If type is host and remotes supplied, check remotes exist
|
// If type is host and remotes supplied, check remotes exist
|
||||||
const remotesWithPort: { remoteName: string; port: number }[] = [];
|
const remotesWithPort: { remoteName: string; port: number }[] = [];
|
||||||
if (
|
if (
|
||||||
options.mfeType === 'host' &&
|
options.mfType === 'host' &&
|
||||||
Array.isArray(options.remotes) &&
|
Array.isArray(options.remotes) &&
|
||||||
options.remotes.length > 0
|
options.remotes.length > 0
|
||||||
) {
|
) {
|
||||||
@ -1,10 +1,9 @@
|
|||||||
import type { Tree } from '@nrwl/devkit';
|
import type { Tree } from '@nrwl/devkit';
|
||||||
|
import { joinPathFragments, readProjectConfiguration } from '@nrwl/devkit';
|
||||||
import type { Schema } from '../schema';
|
import type { Schema } from '../schema';
|
||||||
|
|
||||||
import { readProjectConfiguration, joinPathFragments } from '@nrwl/devkit';
|
|
||||||
|
|
||||||
export function setupHostIfDynamic(tree: Tree, options: Schema) {
|
export function setupHostIfDynamic(tree: Tree, options: Schema) {
|
||||||
if (options.federationType === 'static' || options.mfeType === 'remote') {
|
if (options.federationType === 'static' || options.mfType === 'remote') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1,10 +1,9 @@
|
|||||||
import type { Tree } from '@nrwl/devkit';
|
import type { Tree } from '@nrwl/devkit';
|
||||||
import type { Schema } from '../schema';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
readProjectConfiguration,
|
readProjectConfiguration,
|
||||||
updateProjectConfiguration,
|
updateProjectConfiguration,
|
||||||
} from '@nrwl/devkit';
|
} from '@nrwl/devkit';
|
||||||
|
import type { Schema } from '../schema';
|
||||||
|
|
||||||
export function setupServeTarget(host: Tree, options: Schema) {
|
export function setupServeTarget(host: Tree, options: Schema) {
|
||||||
const appConfig = readProjectConfiguration(host, options.appName);
|
const appConfig = readProjectConfiguration(host, options.appName);
|
||||||
@ -12,7 +11,7 @@ export function setupServeTarget(host: Tree, options: Schema) {
|
|||||||
appConfig.targets['serve'] = {
|
appConfig.targets['serve'] = {
|
||||||
...appConfig.targets['serve'],
|
...appConfig.targets['serve'],
|
||||||
executor:
|
executor:
|
||||||
options.mfeType === 'host'
|
options.mfType === 'host'
|
||||||
? '@nrwl/angular:module-federation-dev-server'
|
? '@nrwl/angular:module-federation-dev-server'
|
||||||
: '@nrwl/angular:webpack-server',
|
: '@nrwl/angular:webpack-server',
|
||||||
options: {
|
options: {
|
||||||
@ -22,7 +21,7 @@ export function setupServeTarget(host: Tree, options: Schema) {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
if (options.mfeType === 'remote') {
|
if (options.mfType === 'remote') {
|
||||||
appConfig.targets['serve-static'] = {
|
appConfig.targets['serve-static'] = {
|
||||||
executor: '@nrwl/angular:file-server',
|
executor: '@nrwl/angular:file-server',
|
||||||
defaultConfiguration: 'development',
|
defaultConfiguration: 'development',
|
||||||
@ -1,6 +1,6 @@
|
|||||||
export interface Schema {
|
export interface Schema {
|
||||||
appName: string;
|
appName: string;
|
||||||
mfeType: 'host' | 'remote';
|
mfType: 'host' | 'remote';
|
||||||
port?: number;
|
port?: number;
|
||||||
remotes?: string[];
|
remotes?: string[];
|
||||||
host?: string;
|
host?: string;
|
||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"$schema": "http://json-schema.org/schema",
|
"$schema": "http://json-schema.org/schema",
|
||||||
"$id": "GeneratorAngularMFESetup",
|
"$id": "GeneratorAngularMFSetup",
|
||||||
"cli": "nx",
|
"cli": "nx",
|
||||||
"title": "Generate Module Federation Setup for Angular App",
|
"title": "Generate Module Federation Setup for Angular App",
|
||||||
"description": "Create Module Federation configuration files for given Angular Application.",
|
"description": "Create Module Federation configuration files for given Angular Application.",
|
||||||
@ -15,7 +15,7 @@
|
|||||||
},
|
},
|
||||||
"x-prompt": "What app would you like to generate a Module Federation configuration for?"
|
"x-prompt": "What app would you like to generate a Module Federation configuration for?"
|
||||||
},
|
},
|
||||||
"mfeType": {
|
"mfType": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["host", "remote"],
|
"enum": ["host", "remote"],
|
||||||
"description": "Type of application to generate the Module Federation configuration for.",
|
"description": "Type of application to generate the Module Federation configuration for.",
|
||||||
@ -61,6 +61,6 @@
|
|||||||
"description": "The prefix to use for any generated component."
|
"description": "The prefix to use for any generated component."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": ["appName", "mfeType"],
|
"required": ["appName", "mfType"],
|
||||||
"additionalProperties": false
|
"additionalProperties": false
|
||||||
}
|
}
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
import { convertNxGenerator } from '@nrwl/devkit';
|
||||||
|
import { setupMf } from './setup-mf';
|
||||||
|
|
||||||
|
export default convertNxGenerator(setupMf);
|
||||||
@ -1,10 +1,10 @@
|
|||||||
import { readJson, Tree } from '@nrwl/devkit';
|
import { readJson, readProjectConfiguration, Tree } from '@nrwl/devkit';
|
||||||
import { readProjectConfiguration } from '@nrwl/devkit';
|
|
||||||
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
|
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
|
||||||
|
|
||||||
import { setupMfe } from './setup-mfe';
|
import { setupMf } from './setup-mf';
|
||||||
import applicationGenerator from '../application/application';
|
import applicationGenerator from '../application/application';
|
||||||
describe('Init MFE', () => {
|
|
||||||
|
describe('Init MF', () => {
|
||||||
let tree: Tree;
|
let tree: Tree;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
@ -23,12 +23,12 @@ describe('Init MFE', () => {
|
|||||||
['app1', 'host'],
|
['app1', 'host'],
|
||||||
['remote1', 'remote'],
|
['remote1', 'remote'],
|
||||||
])(
|
])(
|
||||||
'should create webpack and mfe configs correctly',
|
'should create webpack and mf configs correctly',
|
||||||
async (app, type: 'host' | 'remote') => {
|
async (app, type: 'host' | 'remote') => {
|
||||||
// ACT
|
// ACT
|
||||||
await setupMfe(tree, {
|
await setupMf(tree, {
|
||||||
appName: app,
|
appName: app,
|
||||||
mfeType: type,
|
mfType: type,
|
||||||
});
|
});
|
||||||
|
|
||||||
// ASSERT
|
// ASSERT
|
||||||
@ -44,11 +44,11 @@ describe('Init MFE', () => {
|
|||||||
);
|
);
|
||||||
expect(webpackContents).toMatchSnapshot();
|
expect(webpackContents).toMatchSnapshot();
|
||||||
|
|
||||||
const mfeConfigContents = tree.read(
|
const mfConfigContents = tree.read(
|
||||||
`apps/${app}/module-federation.config.js`,
|
`apps/${app}/module-federation.config.js`,
|
||||||
'utf-8'
|
'utf-8'
|
||||||
);
|
);
|
||||||
expect(mfeConfigContents).toMatchSnapshot();
|
expect(mfConfigContents).toMatchSnapshot();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -62,9 +62,9 @@ describe('Init MFE', () => {
|
|||||||
const mainContents = tree.read(`apps/${app}/src/main.ts`, 'utf-8');
|
const mainContents = tree.read(`apps/${app}/src/main.ts`, 'utf-8');
|
||||||
|
|
||||||
// ACT
|
// ACT
|
||||||
await setupMfe(tree, {
|
await setupMf(tree, {
|
||||||
appName: app,
|
appName: app,
|
||||||
mfeType: type,
|
mfType: type,
|
||||||
});
|
});
|
||||||
|
|
||||||
// ASSERT
|
// ASSERT
|
||||||
@ -89,9 +89,9 @@ describe('Init MFE', () => {
|
|||||||
const mainContents = tree.read(`apps/${app}/src/main.ts`, 'utf-8');
|
const mainContents = tree.read(`apps/${app}/src/main.ts`, 'utf-8');
|
||||||
|
|
||||||
// ACT
|
// ACT
|
||||||
await setupMfe(tree, {
|
await setupMf(tree, {
|
||||||
appName: app,
|
appName: app,
|
||||||
mfeType: type,
|
mfType: type,
|
||||||
});
|
});
|
||||||
|
|
||||||
// ASSERT
|
// ASSERT
|
||||||
@ -111,9 +111,9 @@ describe('Init MFE', () => {
|
|||||||
'should change the build and serve target and set correct path to webpack config',
|
'should change the build and serve target and set correct path to webpack config',
|
||||||
async (app, type: 'host' | 'remote') => {
|
async (app, type: 'host' | 'remote') => {
|
||||||
// ACT
|
// ACT
|
||||||
await setupMfe(tree, {
|
await setupMf(tree, {
|
||||||
appName: app,
|
appName: app,
|
||||||
mfeType: type,
|
mfType: type,
|
||||||
});
|
});
|
||||||
|
|
||||||
// ASSERT
|
// ASSERT
|
||||||
@ -133,9 +133,9 @@ describe('Init MFE', () => {
|
|||||||
|
|
||||||
it('should generate the remote entry module and component correctly', async () => {
|
it('should generate the remote entry module and component correctly', async () => {
|
||||||
// ACT
|
// ACT
|
||||||
await setupMfe(tree, {
|
await setupMf(tree, {
|
||||||
appName: 'remote1',
|
appName: 'remote1',
|
||||||
mfeType: 'remote',
|
mfType: 'remote',
|
||||||
prefix: 'my-org',
|
prefix: 'my-org',
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -150,7 +150,7 @@ describe('Init MFE', () => {
|
|||||||
|
|
||||||
it('should generate the remote entry component correctly when prefix is not provided', async () => {
|
it('should generate the remote entry component correctly when prefix is not provided', async () => {
|
||||||
// ACT
|
// ACT
|
||||||
await setupMfe(tree, { appName: 'remote1', mfeType: 'remote' });
|
await setupMf(tree, { appName: 'remote1', mfType: 'remote' });
|
||||||
|
|
||||||
// ASSERT
|
// ASSERT
|
||||||
expect(
|
expect(
|
||||||
@ -160,41 +160,41 @@ describe('Init MFE', () => {
|
|||||||
|
|
||||||
it('should add the remote config to the host when --remotes flag supplied', async () => {
|
it('should add the remote config to the host when --remotes flag supplied', async () => {
|
||||||
// ACT
|
// ACT
|
||||||
await setupMfe(tree, {
|
await setupMf(tree, {
|
||||||
appName: 'app1',
|
appName: 'app1',
|
||||||
mfeType: 'host',
|
mfType: 'host',
|
||||||
remotes: ['remote1'],
|
remotes: ['remote1'],
|
||||||
});
|
});
|
||||||
|
|
||||||
// ASSERT
|
// ASSERT
|
||||||
const mfeConfigContents = tree.read(
|
const mfConfigContents = tree.read(
|
||||||
`apps/app1/module-federation.config.js`,
|
`apps/app1/module-federation.config.js`,
|
||||||
'utf-8'
|
'utf-8'
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(mfeConfigContents).toContain(`'remote1'`);
|
expect(mfConfigContents).toContain(`'remote1'`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should add a remote application and add it to a specified host applications webpack config when no other remote has been added to it', async () => {
|
it('should add a remote application and add it to a specified host applications webpack config when no other remote has been added to it', async () => {
|
||||||
// ARRANGE
|
// ARRANGE
|
||||||
await setupMfe(tree, {
|
await setupMf(tree, {
|
||||||
appName: 'app1',
|
appName: 'app1',
|
||||||
mfeType: 'host',
|
mfType: 'host',
|
||||||
});
|
});
|
||||||
|
|
||||||
// ACT
|
// ACT
|
||||||
await setupMfe(tree, {
|
await setupMf(tree, {
|
||||||
appName: 'remote1',
|
appName: 'remote1',
|
||||||
mfeType: 'remote',
|
mfType: 'remote',
|
||||||
host: 'app1',
|
host: 'app1',
|
||||||
});
|
});
|
||||||
|
|
||||||
// ASSERT
|
// ASSERT
|
||||||
const hostMfeConfig = tree.read(
|
const hostMfConfig = tree.read(
|
||||||
'apps/app1/module-federation.config.js',
|
'apps/app1/module-federation.config.js',
|
||||||
'utf-8'
|
'utf-8'
|
||||||
);
|
);
|
||||||
expect(hostMfeConfig).toMatchSnapshot();
|
expect(hostMfConfig).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should add a remote application and add it to a specified host applications webpack config that contains a remote application already', async () => {
|
it('should add a remote application and add it to a specified host applications webpack config that contains a remote application already', async () => {
|
||||||
@ -203,32 +203,32 @@ describe('Init MFE', () => {
|
|||||||
name: 'remote2',
|
name: 'remote2',
|
||||||
});
|
});
|
||||||
|
|
||||||
await setupMfe(tree, {
|
await setupMf(tree, {
|
||||||
appName: 'app1',
|
appName: 'app1',
|
||||||
mfeType: 'host',
|
mfType: 'host',
|
||||||
});
|
});
|
||||||
|
|
||||||
await setupMfe(tree, {
|
await setupMf(tree, {
|
||||||
appName: 'remote1',
|
appName: 'remote1',
|
||||||
mfeType: 'remote',
|
mfType: 'remote',
|
||||||
host: 'app1',
|
host: 'app1',
|
||||||
port: 4201,
|
port: 4201,
|
||||||
});
|
});
|
||||||
|
|
||||||
// ACT
|
// ACT
|
||||||
await setupMfe(tree, {
|
await setupMf(tree, {
|
||||||
appName: 'remote2',
|
appName: 'remote2',
|
||||||
mfeType: 'remote',
|
mfType: 'remote',
|
||||||
host: 'app1',
|
host: 'app1',
|
||||||
port: 4202,
|
port: 4202,
|
||||||
});
|
});
|
||||||
|
|
||||||
// ASSERT
|
// ASSERT
|
||||||
const hostMfeConfig = tree.read(
|
const hostMfConfig = tree.read(
|
||||||
'apps/app1/module-federation.config.js',
|
'apps/app1/module-federation.config.js',
|
||||||
'utf-8'
|
'utf-8'
|
||||||
);
|
);
|
||||||
expect(hostMfeConfig).toMatchSnapshot();
|
expect(hostMfConfig).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should add a remote application and add it to a specified host applications router config', async () => {
|
it('should add a remote application and add it to a specified host applications router config', async () => {
|
||||||
@ -238,24 +238,24 @@ describe('Init MFE', () => {
|
|||||||
routing: true,
|
routing: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
await setupMfe(tree, {
|
await setupMf(tree, {
|
||||||
appName: 'app1',
|
appName: 'app1',
|
||||||
mfeType: 'host',
|
mfType: 'host',
|
||||||
routing: true,
|
routing: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
await setupMfe(tree, {
|
await setupMf(tree, {
|
||||||
appName: 'remote1',
|
appName: 'remote1',
|
||||||
mfeType: 'remote',
|
mfType: 'remote',
|
||||||
host: 'app1',
|
host: 'app1',
|
||||||
port: 4201,
|
port: 4201,
|
||||||
routing: true,
|
routing: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
// ACT
|
// ACT
|
||||||
await setupMfe(tree, {
|
await setupMf(tree, {
|
||||||
appName: 'remote2',
|
appName: 'remote2',
|
||||||
mfeType: 'remote',
|
mfType: 'remote',
|
||||||
host: 'app1',
|
host: 'app1',
|
||||||
port: 4202,
|
port: 4202,
|
||||||
routing: true,
|
routing: true,
|
||||||
@ -274,9 +274,9 @@ describe('Init MFE', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// ACT
|
// ACT
|
||||||
await setupMfe(tree, {
|
await setupMf(tree, {
|
||||||
appName: 'test-app',
|
appName: 'test-app',
|
||||||
mfeType: 'host',
|
mfType: 'host',
|
||||||
routing: true,
|
routing: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -293,9 +293,9 @@ describe('Init MFE', () => {
|
|||||||
describe('--federationType=dynamic', () => {
|
describe('--federationType=dynamic', () => {
|
||||||
it('should create a host with the correct configurations', async () => {
|
it('should create a host with the correct configurations', async () => {
|
||||||
// ARRANGE & ACT
|
// ARRANGE & ACT
|
||||||
await setupMfe(tree, {
|
await setupMf(tree, {
|
||||||
appName: 'app1',
|
appName: 'app1',
|
||||||
mfeType: 'host',
|
mfType: 'host',
|
||||||
routing: true,
|
routing: true,
|
||||||
federationType: 'dynamic',
|
federationType: 'dynamic',
|
||||||
});
|
});
|
||||||
@ -313,17 +313,17 @@ describe('Init MFE', () => {
|
|||||||
|
|
||||||
it('should add a remote to dynamic host correctly', async () => {
|
it('should add a remote to dynamic host correctly', async () => {
|
||||||
// ARRANGE
|
// ARRANGE
|
||||||
await setupMfe(tree, {
|
await setupMf(tree, {
|
||||||
appName: 'app1',
|
appName: 'app1',
|
||||||
mfeType: 'host',
|
mfType: 'host',
|
||||||
routing: true,
|
routing: true,
|
||||||
federationType: 'dynamic',
|
federationType: 'dynamic',
|
||||||
});
|
});
|
||||||
|
|
||||||
// ACT
|
// ACT
|
||||||
await setupMfe(tree, {
|
await setupMf(tree, {
|
||||||
appName: 'remote1',
|
appName: 'remote1',
|
||||||
mfeType: 'remote',
|
mfType: 'remote',
|
||||||
port: 4201,
|
port: 4201,
|
||||||
host: 'app1',
|
host: 'app1',
|
||||||
routing: true,
|
routing: true,
|
||||||
@ -1,8 +1,7 @@
|
|||||||
import type { Tree } from '@nrwl/devkit';
|
import type { Tree } from '@nrwl/devkit';
|
||||||
|
import { formatFiles, readProjectConfiguration } from '@nrwl/devkit';
|
||||||
import type { Schema } from './schema';
|
import type { Schema } from './schema';
|
||||||
|
|
||||||
import { readProjectConfiguration, formatFiles } from '@nrwl/devkit';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
addCypressOnErrorWorkaround,
|
addCypressOnErrorWorkaround,
|
||||||
addEntryModule,
|
addEntryModule,
|
||||||
@ -11,12 +10,12 @@ import {
|
|||||||
fixBootstrap,
|
fixBootstrap,
|
||||||
generateWebpackConfig,
|
generateWebpackConfig,
|
||||||
getRemotesWithPorts,
|
getRemotesWithPorts,
|
||||||
setupServeTarget,
|
|
||||||
setupHostIfDynamic,
|
setupHostIfDynamic,
|
||||||
|
setupServeTarget,
|
||||||
updateTsConfigTarget,
|
updateTsConfigTarget,
|
||||||
} from './lib';
|
} from './lib';
|
||||||
|
|
||||||
export async function setupMfe(tree: Tree, options: Schema) {
|
export async function setupMf(tree: Tree, options: Schema) {
|
||||||
const projectConfig = readProjectConfiguration(tree, options.appName);
|
const projectConfig = readProjectConfiguration(tree, options.appName);
|
||||||
|
|
||||||
options.federationType = options.federationType ?? 'static';
|
options.federationType = options.federationType ?? 'static';
|
||||||
@ -43,4 +42,4 @@ export async function setupMfe(tree: Tree, options: Schema) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default setupMfe;
|
export default setupMf;
|
||||||
@ -1,4 +0,0 @@
|
|||||||
import { convertNxGenerator } from '@nrwl/devkit';
|
|
||||||
import { setupMfe } from './setup-mfe';
|
|
||||||
|
|
||||||
export default convertNxGenerator(setupMfe);
|
|
||||||
@ -1,8 +1,8 @@
|
|||||||
import { removeProjectConfiguration, Tree } from '@nrwl/devkit';
|
import { removeProjectConfiguration } from '@nrwl/devkit';
|
||||||
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
|
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
|
||||||
import applicationGenerator from '../../generators/application/application';
|
import applicationGenerator from '../../generators/application/application';
|
||||||
import setupMfe from '../../generators/setup-mfe/setup-mfe';
|
import setupMf from '../../generators/setup-mf/setup-mf';
|
||||||
import addCypressMfeWorkaround from './add-cypress-mfe-workaround';
|
import addCypressMfWorkaround from './add-cypress-mf-workaround';
|
||||||
|
|
||||||
describe('Add Cypress MFE Workaround', () => {
|
describe('Add Cypress MFE Workaround', () => {
|
||||||
it('should add the cypress command to the index.ts for project that has associated e2e', async () => {
|
it('should add the cypress command to the index.ts for project that has associated e2e', async () => {
|
||||||
@ -13,12 +13,12 @@ describe('Add Cypress MFE Workaround', () => {
|
|||||||
routing: true,
|
routing: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
await setupMfe(tree, { appName: 'app1', mfeType: 'host', routing: true });
|
await setupMf(tree, { appName: 'app1', mfType: 'host', routing: true });
|
||||||
|
|
||||||
tree.write('apps/app1-e2e/src/support/index.ts', '');
|
tree.write('apps/app1-e2e/src/support/index.ts', '');
|
||||||
|
|
||||||
// ACT
|
// ACT
|
||||||
await addCypressMfeWorkaround(tree);
|
await addCypressMfWorkaround(tree);
|
||||||
|
|
||||||
// ASSERT
|
// ASSERT
|
||||||
expect(tree.read('apps/app1-e2e/src/support/index.ts', 'utf-8')).toContain(
|
expect(tree.read('apps/app1-e2e/src/support/index.ts', 'utf-8')).toContain(
|
||||||
@ -34,13 +34,13 @@ describe('Add Cypress MFE Workaround', () => {
|
|||||||
routing: true,
|
routing: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
await setupMfe(tree, { appName: 'app1', mfeType: 'host', routing: true });
|
await setupMf(tree, { appName: 'app1', mfType: 'host', routing: true });
|
||||||
|
|
||||||
removeProjectConfiguration(tree, 'app1-e2e');
|
removeProjectConfiguration(tree, 'app1-e2e');
|
||||||
tree.delete('apps/app1-e2e');
|
tree.delete('apps/app1-e2e');
|
||||||
|
|
||||||
// ACT
|
// ACT
|
||||||
await addCypressMfeWorkaround(tree);
|
await addCypressMfWorkaround(tree);
|
||||||
|
|
||||||
// ASSERT
|
// ASSERT
|
||||||
expect(tree.exists('apps/app1-e2e/src/support/index.ts')).toBeFalsy();
|
expect(tree.exists('apps/app1-e2e/src/support/index.ts')).toBeFalsy();
|
||||||
@ -0,0 +1,229 @@
|
|||||||
|
import type { Tree } from '@nrwl/devkit';
|
||||||
|
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
|
||||||
|
|
||||||
|
import migrateMfeToMf, {
|
||||||
|
renameSetupMfeGeneratorUsages,
|
||||||
|
replaceExportedMFETypes,
|
||||||
|
replaceNrwlAngularMfImport,
|
||||||
|
} from './migrate-mfe-to-mf';
|
||||||
|
|
||||||
|
describe('migrate-mfe-to-mf', () => {
|
||||||
|
let tree: Tree;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
tree = createTreeWithEmptyWorkspace(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should replace any imports from nrwl/angular/mfe', () => {
|
||||||
|
// ARRANGE
|
||||||
|
const file = `import { loadRemoteModule } from '@nrwl/angular/mfe';
|
||||||
|
// But not comments, or other markdown etc @nrwl/angular/mfe
|
||||||
|
|
||||||
|
function something() {
|
||||||
|
// but this should change
|
||||||
|
import('@nrwl/angular/mfe');
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
// ACT
|
||||||
|
const updatedFile = replaceNrwlAngularMfImport(file);
|
||||||
|
|
||||||
|
// ASSERT
|
||||||
|
expect(updatedFile).toMatchInlineSnapshot(`
|
||||||
|
"import { loadRemoteModule } from '@nrwl/angular/mf';
|
||||||
|
// But not comments, or other markdown etc @nrwl/angular/mfe
|
||||||
|
|
||||||
|
function something() {
|
||||||
|
// but this should change
|
||||||
|
import('@nrwl/angular/mf');
|
||||||
|
}
|
||||||
|
"
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should replace type imports from nrwl/angular/module-federation', () => {
|
||||||
|
// ARRANGE
|
||||||
|
const file = `import { MFERemotes } from '@nrwl/angular/module-federation';
|
||||||
|
import { MFEConfig } from '@nrwl/angular/module-federation';
|
||||||
|
|
||||||
|
const myValue: MFEConfig = {};
|
||||||
|
const myRemotes: MFERemotes = [];
|
||||||
|
|
||||||
|
function doSomething(v: MFERemotes): MFEConfig {};
|
||||||
|
`;
|
||||||
|
|
||||||
|
// ACT
|
||||||
|
const updatedFile = replaceExportedMFETypes(file);
|
||||||
|
|
||||||
|
// ASSERT
|
||||||
|
expect(updatedFile).toMatchInlineSnapshot(`
|
||||||
|
"import { MFRemotes } from '@nrwl/angular/module-federation';
|
||||||
|
import { MFConfig } from '@nrwl/angular/module-federation';
|
||||||
|
|
||||||
|
const myValue: MFConfig = {};
|
||||||
|
const myRemotes: MFRemotes = [];
|
||||||
|
|
||||||
|
function doSomething(v: MFRemotes): MFConfig {};
|
||||||
|
"
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should rename usages of setupMfe', () => {
|
||||||
|
// ARRANGE
|
||||||
|
const file = `import { setupMfe } from '@nrwl/angular/generators';
|
||||||
|
import { setupMfe, somethingElse } from '@nrwl/angular/generators';
|
||||||
|
|
||||||
|
function doSomething(v: MFERemotes): MFEConfig {
|
||||||
|
|
||||||
|
setupMfe();
|
||||||
|
|
||||||
|
setupMfe({
|
||||||
|
mfeType: 'doSomething'
|
||||||
|
})
|
||||||
|
|
||||||
|
};
|
||||||
|
`;
|
||||||
|
|
||||||
|
// ACT
|
||||||
|
const updatedFile = renameSetupMfeGeneratorUsages(file);
|
||||||
|
|
||||||
|
// ASSERT
|
||||||
|
expect(updatedFile).toMatchInlineSnapshot(`
|
||||||
|
"import { setupMf } from '@nrwl/angular/generators';
|
||||||
|
import { setupMf, somethingElse } from '@nrwl/angular/generators';
|
||||||
|
|
||||||
|
function doSomething(v: MFERemotes): MFEConfig {
|
||||||
|
|
||||||
|
setupMf();
|
||||||
|
|
||||||
|
setupMf({
|
||||||
|
mfType: 'doSomething'
|
||||||
|
})
|
||||||
|
|
||||||
|
};
|
||||||
|
"
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update files correctly', async () => {
|
||||||
|
// ARRANGE
|
||||||
|
tree.write(
|
||||||
|
'test1.js',
|
||||||
|
`import { loadRemoteModule } from '@nrwl/angular/mfe';
|
||||||
|
// But not comments, or other markdown etc @nrwl/angular/mfe
|
||||||
|
|
||||||
|
function something() {
|
||||||
|
// but this should change
|
||||||
|
import('@nrwl/angular/mfe');
|
||||||
|
}`
|
||||||
|
);
|
||||||
|
|
||||||
|
tree.write(
|
||||||
|
'test2.ts',
|
||||||
|
`import { MFERemotes } from '@nrwl/angular/module-federation';
|
||||||
|
import { MFEConfig } from '@nrwl/angular/module-federation';
|
||||||
|
|
||||||
|
const myValue: MFEConfig = {};
|
||||||
|
const myRemotes: MFERemotes = [];
|
||||||
|
|
||||||
|
function doSomething(v: MFERemotes): MFEConfig {};
|
||||||
|
`
|
||||||
|
);
|
||||||
|
|
||||||
|
tree.write(
|
||||||
|
'apps/app1/test3.ts',
|
||||||
|
`import { loadRemoteModule } from '@nrwl/angular/mfe';
|
||||||
|
import { MFERemotes, MFEConfig } from '@nrwl/angular/module-federation';
|
||||||
|
// But not comments, or other markdown etc @nrwl/angular/mfe
|
||||||
|
|
||||||
|
function something() {
|
||||||
|
// but this should change
|
||||||
|
import('@nrwl/angular/mfe');
|
||||||
|
}
|
||||||
|
|
||||||
|
const myValue: MFEConfig = {};
|
||||||
|
const myRemotes: MFERemotes = [];
|
||||||
|
|
||||||
|
function doSomething(v: MFERemotes): MFEConfig {};
|
||||||
|
`
|
||||||
|
);
|
||||||
|
|
||||||
|
tree.write(
|
||||||
|
'libs/plugins/my-plugin/src/generators/my-generator.ts',
|
||||||
|
`import { setupMfe } from '@nrwl/angular/generators';
|
||||||
|
import { setupMfe, somethingElse } from '@nrwl/angular/generators';
|
||||||
|
|
||||||
|
function doSomething(v: MFERemotes): MFEConfig {
|
||||||
|
|
||||||
|
setupMfe();
|
||||||
|
|
||||||
|
setupMfe({
|
||||||
|
mfeType: 'doSomething'
|
||||||
|
})
|
||||||
|
|
||||||
|
};
|
||||||
|
`
|
||||||
|
);
|
||||||
|
|
||||||
|
// ACT
|
||||||
|
|
||||||
|
await migrateMfeToMf(tree);
|
||||||
|
|
||||||
|
// ASSERT
|
||||||
|
expect(tree.read('test1.js', 'utf-8')).toMatchInlineSnapshot(`
|
||||||
|
"import { loadRemoteModule } from '@nrwl/angular/mf';
|
||||||
|
// But not comments, or other markdown etc @nrwl/angular/mfe
|
||||||
|
|
||||||
|
function something() {
|
||||||
|
// but this should change
|
||||||
|
import('@nrwl/angular/mf');
|
||||||
|
}"
|
||||||
|
`);
|
||||||
|
expect(tree.read('test2.ts', 'utf-8')).toMatchInlineSnapshot(`
|
||||||
|
"import { MFRemotes } from '@nrwl/angular/module-federation';
|
||||||
|
import { MFConfig } from '@nrwl/angular/module-federation';
|
||||||
|
|
||||||
|
const myValue: MFConfig = {};
|
||||||
|
const myRemotes: MFRemotes = [];
|
||||||
|
|
||||||
|
function doSomething(v: MFRemotes): MFConfig {};
|
||||||
|
"
|
||||||
|
`);
|
||||||
|
expect(tree.read('apps/app1/test3.ts', 'utf-8')).toMatchInlineSnapshot(`
|
||||||
|
"import { loadRemoteModule } from '@nrwl/angular/mf';
|
||||||
|
import { MFRemotes, MFConfig } from '@nrwl/angular/module-federation';
|
||||||
|
// But not comments, or other markdown etc @nrwl/angular/mfe
|
||||||
|
|
||||||
|
function something() {
|
||||||
|
// but this should change
|
||||||
|
import('@nrwl/angular/mf');
|
||||||
|
}
|
||||||
|
|
||||||
|
const myValue: MFConfig = {};
|
||||||
|
const myRemotes: MFRemotes = [];
|
||||||
|
|
||||||
|
function doSomething(v: MFRemotes): MFConfig {};
|
||||||
|
"
|
||||||
|
`);
|
||||||
|
expect(
|
||||||
|
tree.read(
|
||||||
|
'libs/plugins/my-plugin/src/generators/my-generator.ts',
|
||||||
|
'utf-8'
|
||||||
|
)
|
||||||
|
).toMatchInlineSnapshot(`
|
||||||
|
"import { setupMf } from '@nrwl/angular/generators';
|
||||||
|
import { setupMf, somethingElse } from '@nrwl/angular/generators';
|
||||||
|
|
||||||
|
function doSomething(v: MFERemotes): MFEConfig {
|
||||||
|
|
||||||
|
setupMf();
|
||||||
|
|
||||||
|
setupMf({
|
||||||
|
mfType: 'doSomething'
|
||||||
|
})
|
||||||
|
|
||||||
|
};
|
||||||
|
"
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -0,0 +1,144 @@
|
|||||||
|
import type { Tree } from '@nrwl/devkit';
|
||||||
|
import { visitNotIgnoredFiles } from '@nrwl/devkit';
|
||||||
|
import { extname } from 'path';
|
||||||
|
import { tsquery } from '@phenomnomnominal/tsquery';
|
||||||
|
import { SourceFile } from 'typescript';
|
||||||
|
|
||||||
|
const NRWL_ANGULAR_MFE_STATIC_IMPORT_SELECTOR =
|
||||||
|
'ImportDeclaration > StringLiteral[value="@nrwl/angular/mfe"]';
|
||||||
|
|
||||||
|
const NRWL_ANGULAR_MFE_DYNAMIC_IMPORT_SELECTOR =
|
||||||
|
'CallExpression:has(ImportKeyword) > StringLiteral[value="@nrwl/angular/mfe"]';
|
||||||
|
|
||||||
|
const NRWL_ANGULAR_MFE_TYPES_SELECTOR =
|
||||||
|
'ImportDeclaration:has(StringLiteral[value=@nrwl/angular/module-federation]) > ImportClause > NamedImports';
|
||||||
|
|
||||||
|
export function replaceNrwlAngularMfImport(fileContents: string) {
|
||||||
|
let fileAst: SourceFile = tsquery.ast(fileContents);
|
||||||
|
if (fileContents.includes('@nrwl/angular/mfe')) {
|
||||||
|
// This file definitely contains the string, however, we're interested in whether it is an import
|
||||||
|
const staticQueryResult = tsquery(
|
||||||
|
fileAst,
|
||||||
|
NRWL_ANGULAR_MFE_STATIC_IMPORT_SELECTOR,
|
||||||
|
{
|
||||||
|
visitAllChildren: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (staticQueryResult && staticQueryResult.length > 0) {
|
||||||
|
fileContents = `${fileContents.slice(
|
||||||
|
0,
|
||||||
|
staticQueryResult[0].getStart()
|
||||||
|
)}'@nrwl/angular/mf'${fileContents.slice(staticQueryResult[0].getEnd())}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
fileAst = tsquery.ast(fileContents);
|
||||||
|
|
||||||
|
const dynamicQueryResult = tsquery(
|
||||||
|
fileAst,
|
||||||
|
NRWL_ANGULAR_MFE_DYNAMIC_IMPORT_SELECTOR,
|
||||||
|
{
|
||||||
|
visitAllChildren: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (dynamicQueryResult && dynamicQueryResult.length > 0) {
|
||||||
|
fileContents = `${fileContents.slice(
|
||||||
|
0,
|
||||||
|
dynamicQueryResult[0].getStart()
|
||||||
|
)}'@nrwl/angular/mf'${fileContents.slice(
|
||||||
|
dynamicQueryResult[0].getEnd()
|
||||||
|
)}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fileContents;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function replaceExportedMFETypes(fileContents: string) {
|
||||||
|
const ast = tsquery.ast(fileContents);
|
||||||
|
const queryResult = tsquery(ast, NRWL_ANGULAR_MFE_TYPES_SELECTOR, {
|
||||||
|
visitAllChildren: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (queryResult && queryResult.length > 0) {
|
||||||
|
const TYPES_IMPORTED_FROM_NRWL_REGEX =
|
||||||
|
/(MFERemotes|MFEConfig)+.*from+.+(@nrwl\/angular\/module-federation)+/g;
|
||||||
|
if (TYPES_IMPORTED_FROM_NRWL_REGEX.test(fileContents)) {
|
||||||
|
fileContents = fileContents.replace(/MFERemotes/g, 'MFRemotes');
|
||||||
|
fileContents = fileContents.replace(/MFEConfig/g, 'MFConfig');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fileContents;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function renameSetupMfeGeneratorUsages(fileContents: string) {
|
||||||
|
// Attempt to update any custom generator usage of the changed generators
|
||||||
|
const NRWL_SETUP_MFE_IMPORT_SELECTOR =
|
||||||
|
'ImportDeclaration:has(StringLiteral[value=@nrwl/angular/generators]) > ImportClause:has(NamedImports:has(ImportSpecifier > Identifier[name=setupMfe]))';
|
||||||
|
const SETUP_MFE_IMPORTED_FROM_NRWL_REGEX =
|
||||||
|
/(setupMfe)+.*from+.+(@nrwl\/angular\/generators)+/g;
|
||||||
|
const SETUP_MFE_FUNCTION_CALL_MFE_TYPE_PROPERTY_ASSIGNMENT_SELECTOR =
|
||||||
|
'CallExpression:has(Identifier[name=setupMf]) ObjectLiteralExpression > PropertyAssignment > Identifier[name=mfeType]';
|
||||||
|
|
||||||
|
let ast = tsquery.ast(fileContents);
|
||||||
|
let queryResult = tsquery(ast, NRWL_SETUP_MFE_IMPORT_SELECTOR, {
|
||||||
|
visitAllChildren: true,
|
||||||
|
});
|
||||||
|
if (
|
||||||
|
queryResult &&
|
||||||
|
queryResult.length > 0 &&
|
||||||
|
SETUP_MFE_IMPORTED_FROM_NRWL_REGEX.test(fileContents)
|
||||||
|
) {
|
||||||
|
fileContents = fileContents.replace(/setupMfe/g, 'setupMf');
|
||||||
|
}
|
||||||
|
|
||||||
|
ast = tsquery.ast(fileContents);
|
||||||
|
|
||||||
|
queryResult = tsquery(
|
||||||
|
ast,
|
||||||
|
SETUP_MFE_FUNCTION_CALL_MFE_TYPE_PROPERTY_ASSIGNMENT_SELECTOR,
|
||||||
|
{
|
||||||
|
visitAllChildren: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
while (queryResult && queryResult.length > 0) {
|
||||||
|
const node = queryResult[0];
|
||||||
|
fileContents = `${fileContents.slice(
|
||||||
|
0,
|
||||||
|
node.getStart()
|
||||||
|
)}mfType${fileContents.slice(node.getEnd())}`;
|
||||||
|
|
||||||
|
ast = tsquery.ast(fileContents);
|
||||||
|
|
||||||
|
queryResult = tsquery(
|
||||||
|
ast,
|
||||||
|
SETUP_MFE_FUNCTION_CALL_MFE_TYPE_PROPERTY_ASSIGNMENT_SELECTOR,
|
||||||
|
{
|
||||||
|
visitAllChildren: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return fileContents;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function (tree: Tree) {
|
||||||
|
visitNotIgnoredFiles(tree, '/', (path) => {
|
||||||
|
const pathExtName = extname(path);
|
||||||
|
|
||||||
|
let fileContents = tree.read(path, 'utf-8');
|
||||||
|
if (pathExtName === '.ts' || pathExtName === '.js') {
|
||||||
|
fileContents = replaceNrwlAngularMfImport(fileContents);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pathExtName === '.ts') {
|
||||||
|
// Only TS files can import types and interfaces
|
||||||
|
fileContents = replaceExportedMFETypes(fileContents);
|
||||||
|
|
||||||
|
fileContents = renameSetupMfeGeneratorUsages(fileContents);
|
||||||
|
}
|
||||||
|
|
||||||
|
tree.write(path, fileContents);
|
||||||
|
});
|
||||||
|
}
|
||||||
@ -4,9 +4,9 @@ import * as fs from 'fs';
|
|||||||
import * as tsUtils from '@nrwl/workspace/src/utilities/typescript';
|
import * as tsUtils from '@nrwl/workspace/src/utilities/typescript';
|
||||||
|
|
||||||
import * as devkit from '@nrwl/devkit';
|
import * as devkit from '@nrwl/devkit';
|
||||||
import { sharePackages, shareWorkspaceLibraries } from './mfe-webpack';
|
import { sharePackages, shareWorkspaceLibraries } from './mf-webpack';
|
||||||
|
|
||||||
describe('MFE Webpack Utils', () => {
|
describe('MF Webpack Utils', () => {
|
||||||
afterEach(() => jest.clearAllMocks());
|
afterEach(() => jest.clearAllMocks());
|
||||||
|
|
||||||
describe('ShareWorkspaceLibraries', () => {
|
describe('ShareWorkspaceLibraries', () => {
|
||||||
@ -20,7 +20,7 @@ describe('MFE Webpack Utils', () => {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
// ASSERT
|
// ASSERT
|
||||||
expect(error.message).toContain(
|
expect(error.message).toContain(
|
||||||
'NX MFE: TsConfig Path for workspace libraries does not exist!'
|
'NX MF: TsConfig Path for workspace libraries does not exist!'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -79,7 +79,7 @@ describe('MFE Webpack Utils', () => {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
// ASSERT
|
// ASSERT
|
||||||
expect(error.message).toEqual(
|
expect(error.message).toEqual(
|
||||||
'NX MFE: Could not find root package.json to determine dependency versions.'
|
'NX MF: Could not find root package.json to determine dependency versions.'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -87,7 +87,7 @@ export function shareWorkspaceLibraries(
|
|||||||
) {
|
) {
|
||||||
if (!existsSync(tsConfigPath)) {
|
if (!existsSync(tsConfigPath)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`NX MFE: TsConfig Path for workspace libraries does not exist! (${tsConfigPath})`
|
`NX MF: TsConfig Path for workspace libraries does not exist! (${tsConfigPath})`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -8,7 +8,7 @@ export function readRootPackageJson(): {
|
|||||||
const pkgJsonPath = joinPathFragments(workspaceRoot, 'package.json');
|
const pkgJsonPath = joinPathFragments(workspaceRoot, 'package.json');
|
||||||
if (!existsSync(pkgJsonPath)) {
|
if (!existsSync(pkgJsonPath)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'NX MFE: Could not find root package.json to determine dependency versions.'
|
'NX MF: Could not find root package.json to determine dependency versions.'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3,7 +3,7 @@ import {
|
|||||||
SharedLibraryConfig,
|
SharedLibraryConfig,
|
||||||
sharePackages,
|
sharePackages,
|
||||||
shareWorkspaceLibraries,
|
shareWorkspaceLibraries,
|
||||||
} from './mfe-webpack';
|
} from './mf-webpack';
|
||||||
import {
|
import {
|
||||||
createProjectGraphAsync,
|
createProjectGraphAsync,
|
||||||
ProjectGraph,
|
ProjectGraph,
|
||||||
@ -16,10 +16,10 @@ import {
|
|||||||
import { ParsedCommandLine } from 'typescript';
|
import { ParsedCommandLine } from 'typescript';
|
||||||
import { readRootPackageJson } from './utils';
|
import { readRootPackageJson } from './utils';
|
||||||
import { extname, join } from 'path';
|
import { extname, join } from 'path';
|
||||||
import ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin');
|
|
||||||
import { readCachedProjectConfiguration } from 'nx/src/project-graph/project-graph';
|
import { readCachedProjectConfiguration } from 'nx/src/project-graph/project-graph';
|
||||||
|
import ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin');
|
||||||
|
|
||||||
export type MFERemotes = string[] | [remoteName: string, remoteUrl: string][];
|
export type MFRemotes = string[] | [remoteName: string, remoteUrl: string][];
|
||||||
|
|
||||||
type SharedFunction = (
|
type SharedFunction = (
|
||||||
libraryName: string,
|
libraryName: string,
|
||||||
@ -31,9 +31,9 @@ type AdditionalSharedConfig = Array<
|
|||||||
| { libraryName: string; sharedConfig: SharedLibraryConfig }
|
| { libraryName: string; sharedConfig: SharedLibraryConfig }
|
||||||
>;
|
>;
|
||||||
|
|
||||||
export interface MFEConfig {
|
export interface MFConfig {
|
||||||
name: string;
|
name: string;
|
||||||
remotes?: MFERemotes;
|
remotes?: MFRemotes;
|
||||||
exposes?: Record<string, string>;
|
exposes?: Record<string, string>;
|
||||||
shared?: SharedFunction;
|
shared?: SharedFunction;
|
||||||
additionalShared?: AdditionalSharedConfig;
|
additionalShared?: AdditionalSharedConfig;
|
||||||
@ -134,7 +134,7 @@ function determineRemoteUrl(remote: string) {
|
|||||||
}/remoteEntry.mjs`;
|
}/remoteEntry.mjs`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function mapRemotes(remotes: MFERemotes) {
|
function mapRemotes(remotes: MFRemotes) {
|
||||||
const mappedRemotes = {};
|
const mappedRemotes = {};
|
||||||
|
|
||||||
for (const remote of remotes) {
|
for (const remote of remotes) {
|
||||||
@ -233,8 +233,8 @@ function applyDefaultEagerPackages(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function withModuleFederation(options: MFEConfig) {
|
export async function withModuleFederation(options: MFConfig) {
|
||||||
const DEFAULT_NPM_PACKAGES_TO_AVOID = ['zone.js', '@nrwl/angular/mfe'];
|
const DEFAULT_NPM_PACKAGES_TO_AVOID = ['zone.js', '@nrwl/angular/mf'];
|
||||||
|
|
||||||
let projectGraph: ProjectGraph<any>;
|
let projectGraph: ProjectGraph<any>;
|
||||||
try {
|
try {
|
||||||
Loading…
x
Reference in New Issue
Block a user