Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(angular): add generator to migrate old mfe config
- Loading branch information
Showing
23 changed files
with
1,535 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
--- | ||
title: '@nrwl/angular:move-to-with-mf generator' | ||
description: 'Moves an old micro frontend configuration to use withModuleFederation helper.' | ||
--- | ||
|
||
# @nrwl/angular:move-to-with-mf | ||
|
||
Moves an old micro frontend configuration to use withModuleFederation helper. | ||
|
||
## Usage | ||
|
||
```bash | ||
nx generate move-to-with-mf ... | ||
``` | ||
|
||
By default, Nx will search for `move-to-with-mf` in the default collection provisioned in `workspace.json`. | ||
|
||
You can specify the collection explicitly as follows: | ||
|
||
```bash | ||
nx g @nrwl/angular:move-to-with-mf ... | ||
``` | ||
|
||
Show what will be generated without writing to disk: | ||
|
||
```bash | ||
nx g move-to-with-mf ... --dry-run | ||
``` | ||
|
||
## Options | ||
|
||
### project | ||
|
||
Type: `string` | ||
|
||
The name of the micro frontend project to migrate. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
29 changes: 29 additions & 0 deletions
29
packages/angular/src/generators/move-to-with-mf/__snapshots__/move-to-with-mf.spec.ts.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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', | ||
}, | ||
});" | ||
`; |
7 changes: 7 additions & 0 deletions
7
...gular/src/generators/move-to-with-mf/lib/__snapshots__/is-host-remote-config.spec.ts.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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' | ||
}" | ||
`; |
37 changes: 37 additions & 0 deletions
37
...ar/src/generators/move-to-with-mf/lib/__snapshots__/write-new-webpack-config.spec.ts.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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' | ||
}, | ||
});" | ||
`; |
37 changes: 37 additions & 0 deletions
37
packages/angular/src/generators/move-to-with-mf/lib/check-name-matches.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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(); | ||
}); | ||
}); |
29 changes: 29 additions & 0 deletions
29
packages/angular/src/generators/move-to-with-mf/lib/check-name-matches.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
} |
182 changes: 182 additions & 0 deletions
182
packages/angular/src/generators/move-to-with-mf/lib/check-shared-npm-packages.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,182 @@ | ||
import { tsquery } from '@phenomnomnominal/tsquery'; | ||
import { checkSharedNpmPackagesMatchExpected } from './check-shared-npm-packages'; | ||
|
||
describe('checkSharedNpmPackagesMatchExpected', () => { | ||
it('should return true if all shared packages match the config object we expect', () => { | ||
// ARRANGE | ||
const sourceText = `module.exports = { | ||
plugins: [ | ||
new ModuleFederationPlugin({ | ||
shared: share({ | ||
'@angular/core': { | ||
singleton: true, | ||
strictVersion: true, | ||
requiredVersion: 'auto', | ||
includeSecondaries: true | ||
}, | ||
'@angular/common': { | ||
singleton: true, | ||
strictVersion: true, | ||
requiredVersion: 'auto', | ||
includeSecondaries: true | ||
}, | ||
'rxjs': { | ||
singleton: true, | ||
strictVersion: true, | ||
requiredVersion: 'auto', | ||
includeSecondaries: true | ||
}, | ||
}) | ||
}) | ||
] | ||
}`; | ||
|
||
const ast = tsquery.ast(sourceText); | ||
|
||
// ACT | ||
const result = checkSharedNpmPackagesMatchExpected(ast); | ||
|
||
// ASSERT | ||
expect(result).toBeTruthy(); | ||
}); | ||
|
||
it('should return true if all shared packages match the config object we expect using object syntax', () => { | ||
// ARRANGE | ||
const sourceText = `module.exports = { | ||
plugins: [ | ||
new ModuleFederationPlugin({ | ||
shared: { | ||
'@angular/core': { | ||
singleton: true, | ||
strictVersion: true, | ||
}, | ||
'@angular/common': { | ||
singleton: true, | ||
strictVersion: true, | ||
}, | ||
'rxjs': { | ||
singleton: true, | ||
strictVersion: true, | ||
}, | ||
} | ||
}) | ||
] | ||
}`; | ||
|
||
const ast = tsquery.ast(sourceText); | ||
|
||
// ACT | ||
const result = checkSharedNpmPackagesMatchExpected(ast); | ||
|
||
// ASSERT | ||
expect(result).toBeTruthy(); | ||
}); | ||
|
||
it('should return false if any shared packages do not match the config object we expect using object syntax', () => { | ||
// ARRANGE | ||
const sourceText = `module.exports = { | ||
plugins: [ | ||
new ModuleFederationPlugin({ | ||
shared: { | ||
'@angular/core': { | ||
singleton: true, | ||
strictVersion: true, | ||
}, | ||
'@angular/common': { | ||
singleton: true, | ||
strictVersion: false, | ||
}, | ||
'rxjs': { | ||
singleton: true, | ||
strictVersion: true, | ||
}, | ||
} | ||
}) | ||
] | ||
}`; | ||
|
||
const ast = tsquery.ast(sourceText); | ||
|
||
// ACT | ||
const result = checkSharedNpmPackagesMatchExpected(ast); | ||
|
||
// ASSERT | ||
expect(result).toBeFalsy(); | ||
}); | ||
|
||
it('should return true if we arent sharing packages with the share helper', () => { | ||
// ARRANGE | ||
const sourceText = `module.exports = { | ||
plugins: [ | ||
new ModuleFederationPlugin({ | ||
shared: share({}) | ||
}) | ||
] | ||
}`; | ||
|
||
const ast = tsquery.ast(sourceText); | ||
|
||
// ACT | ||
const result = checkSharedNpmPackagesMatchExpected(ast); | ||
|
||
// ASSERT | ||
expect(result).toBeTruthy(); | ||
}); | ||
|
||
it('should return true if we arent sharing packages with the standard shared syntax', () => { | ||
// ARRANGE | ||
const sourceText = `module.exports = { | ||
plugins: [ | ||
new ModuleFederationPlugin({ | ||
shared: {} | ||
}) | ||
] | ||
}`; | ||
|
||
const ast = tsquery.ast(sourceText); | ||
|
||
// ACT | ||
const result = checkSharedNpmPackagesMatchExpected(ast); | ||
|
||
// ASSERT | ||
expect(result).toBeTruthy(); | ||
}); | ||
|
||
it('should return false if any shared packages does not match the config object we expect', () => { | ||
// ARRANGE | ||
const sourceText = `module.exports = { | ||
plugins: [ | ||
new ModuleFederationPlugin({ | ||
shared: share({ | ||
'@angular/core': { | ||
singleton: true, | ||
strictVersion: true, | ||
requiredVersion: 'auto', | ||
includeSecondaries: true | ||
}, | ||
'@angular/common': { | ||
singleton: true, | ||
strictVersion: false, | ||
requiredVersion: 'auto', | ||
includeSecondaries: true | ||
}, | ||
'rxjs': { | ||
singleton: true, | ||
strictVersion: true, | ||
requiredVersion: 'auto', | ||
includeSecondaries: true | ||
}, | ||
}) | ||
}) | ||
] | ||
}`; | ||
|
||
const ast = tsquery.ast(sourceText); | ||
|
||
// ACT | ||
const result = checkSharedNpmPackagesMatchExpected(ast); | ||
|
||
// ASSERT | ||
expect(result).toBeFalsy(); | ||
}); | ||
}); |
Oops, something went wrong.