Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
feat(angular): add mfe-remote generator (#9191)
  • Loading branch information
Coly010 committed Mar 8, 2022
1 parent 7442030 commit 6c99959
Show file tree
Hide file tree
Showing 10 changed files with 397 additions and 0 deletions.
60 changes: 60 additions & 0 deletions docs/generated/api-angular/generators/mfe-remote.md
@@ -0,0 +1,60 @@
---
title: '@nrwl/angular:mfe-remote generator'
description: 'Generate a Remote Angular Micro-Frontend Application.'
---

# @nrwl/angular:mfe-remote

Generate a Remote Angular Micro-Frontend Application.

## Usage

```bash
nx generate mfe-remote ...
```

```bash
nx g remote ... # same
```

By default, Nx will search for `mfe-remote` in the default collection provisioned in `workspace.json`.

You can specify the collection explicitly as follows:

```bash
nx g @nrwl/angular:mfe-remote ...
```

Show what will be generated without writing to disk:

```bash
nx g mfe-remote ... --dry-run
```

### Examples

Create an Angular app with configuration in place for MFE. If host is provided, attach this remote app to host app's configuration.:

```bash
nx g @nrwl/angular:mfe-remote appName --host=host --port=4201
```

## Options

### name (_**required**_)

Type: `string`

The name to give to the remote Angular app.

### host

Type: `string`

The name of the host app to attach this remote app to.

### port

Type: `string`

The port on which this app should be served.
5 changes: 5 additions & 0 deletions docs/map.json
Expand Up @@ -643,6 +643,11 @@
"id": "mfe-host",
"file": "generated/api-angular/generators/mfe-host"
},
{
"name": "mfe-remote generator",
"id": "mfe-remote",
"file": "generated/api-angular/generators/mfe-remote"
},
{
"name": "move generator",
"id": "move",
Expand Down
12 changes: 12 additions & 0 deletions packages/angular/generators.json
Expand Up @@ -68,6 +68,12 @@
"aliases": ["secondary-entry-point", "entry-point"],
"description": "Creates a secondary entry point for an Angular publishable library."
},
"mfe-remote": {
"factory": "./src/generators/mfe-remote/mfe-remote.compat",
"schema": "./src/generators/mfe-remote/schema.json",
"aliases": ["remote"],
"description": "Generate a Remote Angular Micro-Frontend Application."
},
"move": {
"factory": "./src/generators/move/move#angularMoveSchematic",
"schema": "./src/generators/move/schema.json",
Expand Down Expand Up @@ -207,6 +213,12 @@
"aliases": ["secondary-entry-point", "entry-point"],
"description": "Creates a secondary entry point for an Angular publishable library."
},
"mfe-remote": {
"factory": "./src/generators/mfe-remote/mfe-remote",
"schema": "./src/generators/mfe-remote/schema.json",
"aliases": ["remote"],
"description": "Generate a Remote Angular Micro-Frontend Application."
},
"move": {
"factory": "./src/generators/move/move#angularMoveGenerator",
"schema": "./src/generators/move/schema.json",
Expand Down
1 change: 1 addition & 0 deletions packages/angular/generators.ts
Expand Up @@ -23,3 +23,4 @@ export * from './src/generators/add-linting/add-linting';
export * from './src/generators/component-cypress-spec/component-cypress-spec';
export * from './src/generators/component-story/component-story';
export * from './src/generators/web-worker/web-worker';
export * from './src/generators/mfe-remote/mfe-remote';
@@ -0,0 +1,192 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`MFE Remote App Generator should generate a remote mfe app with a host 1`] = `
"const ModuleFederationPlugin = require(\\"webpack/lib/container/ModuleFederationPlugin\\");
const mf = require(\\"@angular-architects/module-federation/webpack\\");
const path = require(\\"path\\");
const share = mf.share;
/**
* We use the NX_TSCONFIG_PATH environment variable when using the @nrwl/angular:webpack-browser
* builder as it will generate a temporary tsconfig file which contains any required remappings of
* shared libraries.
* A remapping will occur when a library is buildable, as webpack needs to know the location of the
* built files for the buildable library.
* This NX_TSCONFIG_PATH environment variable is set by the @nrwl/angular:webpack-browser and it contains
* the location of the generated temporary tsconfig file.
*/
const tsConfigPath = process.env.NX_TSCONFIG_PATH ?? path.join(__dirname, '../../tsconfig.base.json');
const workspaceRootPath = path.join(__dirname, '../../');
const sharedMappings = new mf.SharedMappings();
sharedMappings.register(tsConfigPath, [
/* mapped paths to share */
], workspaceRootPath);
module.exports = {
output: {
uniqueName: \\"host\\",
publicPath: \\"auto\\",
},
optimization: {
runtimeChunk: false,
},
experiments: {
outputModule: true
},
resolve: {
alias: {
...sharedMappings.getAliases(),
},
},
plugins: [
new ModuleFederationPlugin({
remotes: {
\\"test\\": 'http://localhost:4201/remoteEntry.js',
},
shared: share({
\\"@angular/core\\": { singleton: true, strictVersion: true, requiredVersion: 'auto', includeSecondaries: true },
\\"@angular/common\\": { singleton: true, strictVersion: true, requiredVersion: 'auto', includeSecondaries: true },
\\"@angular/common/http\\": { singleton: true, strictVersion: true, requiredVersion: 'auto', includeSecondaries: true },
\\"@angular/router\\": { singleton: true, strictVersion: true, requiredVersion: 'auto', includeSecondaries: true },
\\"rxjs\\": { singleton: true, strictVersion: true, requiredVersion: 'auto', includeSecondaries: true },
...sharedMappings.getDescriptors(),
}),
library: {
type: 'module'
},
}),
sharedMappings.getPlugin(),
],
};
"
`;

exports[`MFE Remote App Generator should generate a remote mfe app with a host 2`] = `
"const ModuleFederationPlugin = require(\\"webpack/lib/container/ModuleFederationPlugin\\");
const mf = require(\\"@angular-architects/module-federation/webpack\\");
const path = require(\\"path\\");
const share = mf.share;
/**
* We use the NX_TSCONFIG_PATH environment variable when using the @nrwl/angular:webpack-browser
* builder as it will generate a temporary tsconfig file which contains any required remappings of
* shared libraries.
* A remapping will occur when a library is buildable, as webpack needs to know the location of the
* built files for the buildable library.
* This NX_TSCONFIG_PATH environment variable is set by the @nrwl/angular:webpack-browser and it contains
* the location of the generated temporary tsconfig file.
*/
const tsConfigPath = process.env.NX_TSCONFIG_PATH ?? path.join(__dirname, '../../tsconfig.base.json');
const workspaceRootPath = path.join(__dirname, '../../');
const sharedMappings = new mf.SharedMappings();
sharedMappings.register(tsConfigPath, [
/* mapped paths to share */
], workspaceRootPath);
module.exports = {
output: {
uniqueName: \\"test\\",
publicPath: \\"auto\\",
},
optimization: {
runtimeChunk: false,
},
experiments: {
outputModule: true
},
resolve: {
alias: {
...sharedMappings.getAliases(),
},
},
plugins: [
new ModuleFederationPlugin({
name: \\"test\\",
filename: \\"remoteEntry.js\\",
exposes: {
'./Module': 'apps/test/src/app/remote-entry/entry.module.ts',
},
shared: share({
\\"@angular/core\\": { singleton: true, strictVersion: true, requiredVersion: 'auto', includeSecondaries: true },
\\"@angular/common\\": { singleton: true, strictVersion: true, requiredVersion: 'auto', includeSecondaries: true },
\\"@angular/common/http\\": { singleton: true, strictVersion: true, requiredVersion: 'auto', includeSecondaries: true },
\\"@angular/router\\": { singleton: true, strictVersion: true, requiredVersion: 'auto', includeSecondaries: true },
\\"rxjs\\": { singleton: true, strictVersion: true, requiredVersion: 'auto', includeSecondaries: true },
...sharedMappings.getDescriptors(),
}),
library: {
type: 'module'
},
}),
sharedMappings.getPlugin(),
],
};
"
`;

exports[`MFE Remote App Generator should generate a remote mfe app with no host 1`] = `
"const ModuleFederationPlugin = require(\\"webpack/lib/container/ModuleFederationPlugin\\");
const mf = require(\\"@angular-architects/module-federation/webpack\\");
const path = require(\\"path\\");
const share = mf.share;
/**
* We use the NX_TSCONFIG_PATH environment variable when using the @nrwl/angular:webpack-browser
* builder as it will generate a temporary tsconfig file which contains any required remappings of
* shared libraries.
* A remapping will occur when a library is buildable, as webpack needs to know the location of the
* built files for the buildable library.
* This NX_TSCONFIG_PATH environment variable is set by the @nrwl/angular:webpack-browser and it contains
* the location of the generated temporary tsconfig file.
*/
const tsConfigPath = process.env.NX_TSCONFIG_PATH ?? path.join(__dirname, '../../tsconfig.base.json');
const workspaceRootPath = path.join(__dirname, '../../');
const sharedMappings = new mf.SharedMappings();
sharedMappings.register(tsConfigPath, [
/* mapped paths to share */
], workspaceRootPath);
module.exports = {
output: {
uniqueName: \\"test\\",
publicPath: \\"auto\\",
},
optimization: {
runtimeChunk: false,
},
experiments: {
outputModule: true
},
resolve: {
alias: {
...sharedMappings.getAliases(),
},
},
plugins: [
new ModuleFederationPlugin({
name: \\"test\\",
filename: \\"remoteEntry.js\\",
exposes: {
'./Module': 'apps/test/src/app/remote-entry/entry.module.ts',
},
shared: share({
\\"@angular/core\\": { singleton: true, strictVersion: true, requiredVersion: 'auto', includeSecondaries: true },
\\"@angular/common\\": { singleton: true, strictVersion: true, requiredVersion: 'auto', includeSecondaries: true },
\\"@angular/common/http\\": { singleton: true, strictVersion: true, requiredVersion: 'auto', includeSecondaries: true },
\\"@angular/router\\": { singleton: true, strictVersion: true, requiredVersion: 'auto', includeSecondaries: true },
\\"rxjs\\": { singleton: true, strictVersion: true, requiredVersion: 'auto', includeSecondaries: true },
...sharedMappings.getDescriptors(),
}),
library: {
type: 'module'
},
}),
sharedMappings.getPlugin(),
],
};
"
`;
@@ -0,0 +1,4 @@
import { convertNxGenerator } from '@nrwl/devkit';
import mfeRemote from './mfe-remote';

export default convertNxGenerator(mfeRemote);
61 changes: 61 additions & 0 deletions packages/angular/src/generators/mfe-remote/mfe-remote.spec.ts
@@ -0,0 +1,61 @@
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
import mfeRemote from './mfe-remote';
import applicationGenerator from '../application/application';

describe('MFE Remote App Generator', () => {
it('should generate a remote mfe app with no host', async () => {
// ARRANGE
const tree = createTreeWithEmptyWorkspace(2);

// ACT
await mfeRemote(tree, {
name: 'test',
port: 4201,
});

// ASSERT
expect(tree.read('apps/test/webpack.config.js', 'utf-8')).toMatchSnapshot();
});

it('should generate a remote mfe app with a host', async () => {
// ARRANGE
const tree = createTreeWithEmptyWorkspace(2);

await applicationGenerator(tree, {
name: 'host',
mfe: true,
mfeType: 'host',
routing: true,
});

// ACT
await mfeRemote(tree, {
name: 'test',
host: 'host',
port: 4201,
});

// ASSERT
expect(tree.read('apps/host/webpack.config.js', 'utf-8')).toMatchSnapshot();
expect(tree.read('apps/test/webpack.config.js', 'utf-8')).toMatchSnapshot();
});

it('should error when a remote app is attempted to be generated with an incorrect host', async () => {
// ARRANGE
const tree = createTreeWithEmptyWorkspace(2);

// ACT
try {
await mfeRemote(tree, {
name: 'test',
host: 'host',
port: 4201,
});
} catch (error) {
// ASSERT
expect(error.message).toEqual(
'The name of the application to be used as the host app does not exist. (host)'
);
}
});
});
24 changes: 24 additions & 0 deletions packages/angular/src/generators/mfe-remote/mfe-remote.ts
@@ -0,0 +1,24 @@
import type { Tree } from '@nrwl/devkit';
import type { Schema } from './schema';
import { getProjects } from '@nrwl/devkit';
import applicationGenerator from '../application/application';

export default async function mfeRemote(tree: Tree, options: Schema) {
const projects = getProjects(tree);
if (options.host && !projects.has(options.host)) {
throw new Error(
`The name of the application to be used as the host app does not exist. (${options.host})`
);
}

const installTask = await applicationGenerator(tree, {
name: options.name,
mfe: true,
mfeType: 'remote',
routing: true,
host: options.host,
port: options.port ?? 4200,
});

return installTask;
}
5 changes: 5 additions & 0 deletions packages/angular/src/generators/mfe-remote/schema.d.ts
@@ -0,0 +1,5 @@
export interface Schema {
name: string;
host?: string;
port?: number;
}

1 comment on commit 6c99959

@vercel
Copy link

@vercel vercel bot commented on 6c99959 Mar 8, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.