Skip to content

Commit

Permalink
feat(angular): add generator to migrate old mfe config
Browse files Browse the repository at this point in the history
  • Loading branch information
Coly010 committed Mar 23, 2022
1 parent fd98044 commit f6ca622
Show file tree
Hide file tree
Showing 23 changed files with 1,545 additions and 0 deletions.
48 changes: 48 additions & 0 deletions docs/generated/api-angular/generators/convert-to-with-mf.md
@@ -0,0 +1,48 @@
---
title: '@nrwl/angular:convert-to-with-mf generator'
description:
'Converts an old micro frontend configuration to use the new withModuleFederation helper. It will run successfully if the following conditions are met:
- Is either a host or remote application
- Shared npm package configurations have not been modified
- Name used to identify the Micro Frontend application matches the project name
_**Note:** This generator will overwrite your webpack config. If you have additional custom configuration in your config file, it will be lost!_'
---

# @nrwl/angular:convert-to-with-mf

Converts an old micro frontend configuration to use the new withModuleFederation helper. It will run successfully if the following conditions are met:

- Is either a host or remote application
- Shared npm package configurations have not been modified
- Name used to identify the Micro Frontend application matches the project name

_**Note:** This generator will overwrite your webpack config. If you have additional custom configuration in your config file, it will be lost!_

## Usage

```bash
nx generate convert-to-with-mf ...
```

By default, Nx will search for `convert-to-with-mf` in the default collection provisioned in `workspace.json`.

You can specify the collection explicitly as follows:

```bash
nx g @nrwl/angular:convert-to-with-mf ...
```

Show what will be generated without writing to disk:

```bash
nx g convert-to-with-mf ... --dry-run
```

## Options

### project

Type: `string`

The name of the micro frontend project to migrate.
5 changes: 5 additions & 0 deletions docs/map.json
Expand Up @@ -689,6 +689,11 @@
"id": "move",
"file": "generated/api-angular/generators/move"
},
{
"name": "convert-to-with-mf generator",
"id": "convert-to-with-mf",
"file": "generated/api-angular/generators/convert-to-with-mf"
},
{
"name": "ngrx generator",
"id": "ngrx",
Expand Down
10 changes: 10 additions & 0 deletions packages/angular/generators.json
Expand Up @@ -80,6 +80,11 @@
"aliases": ["mv"],
"description": "Moves an Angular application or library to another folder within the workspace and updates the project configuration."
},
"convert-to-with-mf": {
"factory": "./src/generators/move-to-with-mf/move-to-with-mf.compat",
"schema": "./src/generators/move-to-with-mf/schema.json",
"description": "Converts an old micro frontend configuration to use the new withModuleFederation helper. It will run successfully if the following conditions are met: \n - Is either a host or remote application \n - Shared npm package configurations have not been modified \n - Name used to identify the Micro Frontend application matches the project name \n\n _**Note:** This generator will overwrite your webpack config. If you have additional custom configuration in your config file, it will be lost!_"
},
"mfe-host": {
"factory": "./src/generators/mfe-host/mfe-host.compat",
"schema": "./src/generators/mfe-host/schema.json",
Expand Down Expand Up @@ -225,6 +230,11 @@
"aliases": ["mv"],
"description": "Moves an Angular application or library to another folder within the workspace and updates the project configuration."
},
"convert-to-with-mf": {
"factory": "./src/generators/move-to-with-mf/move-to-with-mf",
"schema": "./src/generators/move-to-with-mf/schema.json",
"description": "Converts an old micro frontend configuration to use the new withModuleFederation helper. It will run successfully if the following conditions are met: \n - Is either a host or remote application \n - Shared npm package configurations have not been modified \n - Name used to identify the Micro Frontend application matches the project name \n\n _**Note:** This generator will overwrite your webpack config. If you have additional custom configuration in your config file, it will be lost!_"
},
"mfe-host": {
"factory": "./src/generators/mfe-host/mfe-host",
"schema": "./src/generators/mfe-host/schema.json",
Expand Down
@@ -0,0 +1,29 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`moveToWithMF should migrate a standard previous generated host config correctly 1`] = `
"const { withModuleFederation } = require('@nrwl/angular/module-federation');
module.exports = withModuleFederation({
name: 'host1',
remotes: [['remote1', 'http://localhost:4201']],
});"
`;

exports[`moveToWithMF should migrate a standard previous generated remote config correctly 1`] = `
"const { withModuleFederation } = require('@nrwl/angular/module-federation');
module.exports = withModuleFederation({
name: 'remote1',
exposes: {
'./Module': 'apps/remote1/src/app/remote-entry/entry.module.ts',
},
});"
`;

exports[`moveToWithMF should migrate a standard previous generated remote config using object shared syntax correctly 1`] = `
"const { withModuleFederation } = require('@nrwl/angular/module-federation');
module.exports = withModuleFederation({
name: 'remote1',
exposes: {
'./Module': 'apps/remote1/src/app/remote-entry/entry.module.ts',
},
});"
`;
@@ -0,0 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`isHostRemoteConfig should return remote when correct remote config found 1`] = `
"{
'./Module': 'apps/remote1/src/app/remote-entry/entry.module.ts'
}"
`;
@@ -0,0 +1,37 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`writeNewWebpackConfig should convert config that is both remote and host correctly 1`] = `
"const { withModuleFederation } = require('@nrwl/angular/module-federation');
module.exports = withModuleFederation({
name: 'both1',
remotes: [['remote1', 'http://localhost:4201']],
exposes: {
'./Module': 'apps/both/src/app/remote-entry/entry.module.ts'
},
});"
`;

exports[`writeNewWebpackConfig should convert config that is neither remote and host correctly 1`] = `
"const { withModuleFederation } = require('@nrwl/angular/module-federation');
module.exports = withModuleFederation({
name: 'neither',
});"
`;

exports[`writeNewWebpackConfig should convert host config correctly 1`] = `
"const { withModuleFederation } = require('@nrwl/angular/module-federation');
module.exports = withModuleFederation({
name: 'host1',
remotes: [['remote1', 'http://localhost:4201']],
});"
`;

exports[`writeNewWebpackConfig should convert remote config correctly 1`] = `
"const { withModuleFederation } = require('@nrwl/angular/module-federation');
module.exports = withModuleFederation({
name: 'remote1',
exposes: {
'./Module': 'apps/remote1/src/app/remote-entry/entry.module.ts'
},
});"
`;
@@ -0,0 +1,37 @@
import { tsquery } from '@phenomnomnominal/tsquery';
import { checkOutputNameMatchesProjectName } from './check-name-matches';
describe('checkOutputNameMatchesProjectName', () => {
it('should return true if the uniqueName matches the project name', () => {
// ARRANGE
const sourceText = `module.exports = {
output: {
uniqueName: 'proj'
}
}`;

const ast = tsquery.ast(sourceText);

// ACT
const result = checkOutputNameMatchesProjectName(ast, 'proj');

// ASSERT
expect(result).toBeTruthy();
});

it('should return false if the uniqueName does not match the project name', () => {
// ARRANGE
const sourceText = `module.exports = {
output: {
uniqueName: 'app1'
}
}`;

const ast = tsquery.ast(sourceText);

// ACT
const result = checkOutputNameMatchesProjectName(ast, 'proj');

// ASSERT
expect(result).toBeFalsy();
});
});
@@ -0,0 +1,29 @@
import type { SourceFile } from 'typescript';
import { tsquery } from '@phenomnomnominal/tsquery';

export function checkOutputNameMatchesProjectName(
ast: SourceFile,
projectName: string
) {
const OUTPUT_SELECTOR =
'PropertyAssignment:has(Identifier[name=output]) > ObjectLiteralExpression:has(PropertyAssignment:has(Identifier[name=uniqueName]))';
const UNIQUENAME_SELECTOR =
'ObjectLiteralExpression > PropertyAssignment:has(Identifier[name=uniqueName]) > StringLiteral';

const outputNodes = tsquery(ast, OUTPUT_SELECTOR, { visitAllChildren: true });
if (outputNodes.length === 0) {
// If the output isnt set in the config, then we can still set the project name correctly
return true;
}

const uniqueNameNodes = tsquery(outputNodes[0], UNIQUENAME_SELECTOR, {
visitAllChildren: true,
});
if (uniqueNameNodes.length === 0) {
// If the uniqeName isnt set in the config, then we can still set the project name correctly
return true;
}
const uniqueName = uniqueNameNodes[0].getText().replace(/'/g, '');

return uniqueName === projectName;
}

0 comments on commit f6ca622

Please sign in to comment.