diff --git a/.verdaccio/htpasswd b/.verdaccio/htpasswd index 8391cd4b0a9012..79e8cd928acc54 100644 --- a/.verdaccio/htpasswd +++ b/.verdaccio/htpasswd @@ -1 +1,2 @@ test:$6FrCaT/v0dwE:autocreated 2020-03-25T19:10:50.254Z +colum:H9ouz8XKFn.2k:autocreated 2022-03-24T12:11:51.589Z diff --git a/packages/angular/src/generators/application/__snapshots__/application.spec.ts.snap b/packages/angular/src/generators/application/__snapshots__/application.spec.ts.snap index cb574f99a99a79..32ff7f0716604e 100644 --- a/packages/angular/src/generators/application/__snapshots__/application.spec.ts.snap +++ b/packages/angular/src/generators/application/__snapshots__/application.spec.ts.snap @@ -2,36 +2,26 @@ 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`] = ` "const { withModuleFederation } = require('@nrwl/angular/module-federation'); -module.exports = withModuleFederation({ - name: 'app1', - remotes: ['remote1','remote2',] -});" +const config = require('./mfe.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`] = ` "const { withModuleFederation } = require('@nrwl/angular/module-federation'); -module.exports = withModuleFederation({ - name: 'app1', - remotes: ['remote1',] -});" +const config = require('./mfe.config'); +module.exports = withModuleFederation(config);" `; exports[`app --mfe should generate a Module Federation correctly for a each app 1`] = ` "const { withModuleFederation } = require('@nrwl/angular/module-federation'); -module.exports = withModuleFederation({ - name: 'my-app', - remotes: [] -});" +const config = require('./mfe.config'); +module.exports = withModuleFederation(config);" `; exports[`app --mfe should generate a Module Federation correctly for a each app 2`] = ` "const { withModuleFederation } = require('@nrwl/angular/module-federation'); -module.exports = withModuleFederation({ - name: 'my-app', - exposes: { - './Module': 'apps/my-app/src/app/remote-entry/entry.module.ts', - }, -});" +const config = require('./mfe.config'); +module.exports = withModuleFederation(config);" `; exports[`app at the root should accept numbers in the path 1`] = `"src/9-websites/my-app"`; diff --git a/packages/angular/src/generators/convert-to-with-mf/convert-to-with-mf.ts b/packages/angular/src/generators/convert-to-with-mf/convert-to-with-mf.ts index bbec9cbdc59ea9..95776f01136267 100644 --- a/packages/angular/src/generators/convert-to-with-mf/convert-to-with-mf.ts +++ b/packages/angular/src/generators/convert-to-with-mf/convert-to-with-mf.ts @@ -1,4 +1,4 @@ -import { logger, Tree } from '@nrwl/devkit'; +import { joinPathFragments, logger, Tree } from '@nrwl/devkit'; import type { Schema } from './schema'; import { readProjectConfiguration, formatFiles } from '@nrwl/devkit'; @@ -43,12 +43,13 @@ export default async function convertToWithMF(tree: Tree, schema: Schema) { `This Micro Frontend configuration conversion will overwrite "${schema.project}"'s current webpack config. If you have anything custom that is not related to Micro Frontends, it will be lost. You should be able to see the changes in your version control system.` ); - const updatedWebpackConfig = writeNewWebpackConfig( + const [updatedWebpackConfig, mfeConfig] = writeNewWebpackConfig( webpackAst, isHostRemoteConfig(webpackAst), schema.project ); tree.write(pathToWebpackConfig, updatedWebpackConfig); + tree.write(joinPathFragments(project.root, 'mfe.config.js'), mfeConfig); await formatFiles(tree); } diff --git a/packages/angular/src/generators/convert-to-with-mf/lib/write-new-webpack-config.ts b/packages/angular/src/generators/convert-to-with-mf/lib/write-new-webpack-config.ts index 87dd62a1f80231..e19e9b5f85eb2c 100644 --- a/packages/angular/src/generators/convert-to-with-mf/lib/write-new-webpack-config.ts +++ b/packages/angular/src/generators/convert-to-with-mf/lib/write-new-webpack-config.ts @@ -10,38 +10,42 @@ export function writeNewWebpackConfig( mfType: IsHostRemoteConfigResult, projectName: string ) { - let webpackConfig = ''; + const webpackConfig = `const { withModuleFederation } = require('@nrwl/angular/module-federation'); + const config = require('./mfe.config'); + module.exports = withModuleFederation(config);`; + + let mfeConfig = ''; if (!mfType) { - webpackConfig = `const { withModuleFederation } = require('@nrwl/angular/module-federation'); - module.exports = withModuleFederation({ + mfeConfig = ` + module.exports = { name: '${projectName}', - });`; + };`; } else if (mfType === 'host') { const remotes = hostRemotesToString(ast); - webpackConfig = `const { withModuleFederation } = require('@nrwl/angular/module-federation'); - module.exports = withModuleFederation({ + mfeConfig = ` + module.exports = { name: '${projectName}', remotes: ${remotes}, - });`; + };`; } else if (mfType === 'remote') { const exposedModules = getExposedModulesFromRemote(ast); - webpackConfig = `const { withModuleFederation } = require('@nrwl/angular/module-federation'); - module.exports = withModuleFederation({ + mfeConfig = ` + module.exports = { name: '${projectName}', exposes: ${exposedModules}, - });`; + };`; } else if (mfType === 'both') { const remotes = hostRemotesToString(ast); const exposedModules = getExposedModulesFromRemote(ast); - webpackConfig = `const { withModuleFederation } = require('@nrwl/angular/module-federation'); - module.exports = withModuleFederation({ + mfeConfig = ` + module.exports = { name: '${projectName}', remotes: ${remotes}, exposes: ${exposedModules}, - });`; + };`; } - return webpackConfig; + return [webpackConfig, mfeConfig]; } function hostRemotesToString(ast: SourceFile) { diff --git a/packages/angular/src/generators/mfe-host/__snapshots__/mfe-host.spec.ts.snap b/packages/angular/src/generators/mfe-host/__snapshots__/mfe-host.spec.ts.snap index 78c810e069467f..346e856aef4474 100644 --- a/packages/angular/src/generators/mfe-host/__snapshots__/mfe-host.spec.ts.snap +++ b/packages/angular/src/generators/mfe-host/__snapshots__/mfe-host.spec.ts.snap @@ -2,26 +2,18 @@ exports[`MFE Host App Generator should generate a host mfe app with a remote 1`] = ` "const { withModuleFederation } = require('@nrwl/angular/module-federation'); -module.exports = withModuleFederation({ - name: 'remote', - exposes: { - './Module': 'apps/remote/src/app/remote-entry/entry.module.ts', - }, -});" +const config = require('./mfe.config'); +module.exports = withModuleFederation(config);" `; exports[`MFE Host App Generator should generate a host mfe app with a remote 2`] = ` "const { withModuleFederation } = require('@nrwl/angular/module-federation'); -module.exports = withModuleFederation({ - name: 'test', - remotes: ['remote',] -});" +const config = require('./mfe.config'); +module.exports = withModuleFederation(config);" `; exports[`MFE Host App Generator should generate a host mfe app with no remotes 1`] = ` "const { withModuleFederation } = require('@nrwl/angular/module-federation'); -module.exports = withModuleFederation({ - name: 'test', - remotes: [] -});" +const config = require('./mfe.config'); +module.exports = withModuleFederation(config);" `; diff --git a/packages/angular/src/generators/mfe-remote/__snapshots__/mfe-remote.spec.ts.snap b/packages/angular/src/generators/mfe-remote/__snapshots__/mfe-remote.spec.ts.snap index 31c1cf1aec832a..ec152aa7a02ff3 100644 --- a/packages/angular/src/generators/mfe-remote/__snapshots__/mfe-remote.spec.ts.snap +++ b/packages/angular/src/generators/mfe-remote/__snapshots__/mfe-remote.spec.ts.snap @@ -2,28 +2,18 @@ exports[`MFE Remote App Generator should generate a remote mfe app with a host 1`] = ` "const { withModuleFederation } = require('@nrwl/angular/module-federation'); -module.exports = withModuleFederation({ - name: 'host', - remotes: ['test',] -});" +const config = require('./mfe.config'); +module.exports = withModuleFederation(config);" `; exports[`MFE Remote App Generator should generate a remote mfe app with a host 2`] = ` "const { withModuleFederation } = require('@nrwl/angular/module-federation'); -module.exports = withModuleFederation({ - name: 'test', - exposes: { - './Module': 'apps/test/src/app/remote-entry/entry.module.ts', - }, -});" +const config = require('./mfe.config'); +module.exports = withModuleFederation(config);" `; exports[`MFE Remote App Generator should generate a remote mfe app with no host 1`] = ` "const { withModuleFederation } = require('@nrwl/angular/module-federation'); -module.exports = withModuleFederation({ - name: 'test', - exposes: { - './Module': 'apps/test/src/app/remote-entry/entry.module.ts', - }, -});" +const config = require('./mfe.config'); +module.exports = withModuleFederation(config);" `; diff --git a/packages/angular/src/generators/setup-mfe/__snapshots__/setup-mfe.spec.ts.snap b/packages/angular/src/generators/setup-mfe/__snapshots__/setup-mfe.spec.ts.snap index dd8c26371e8783..240c15d367ec44 100644 --- a/packages/angular/src/generators/setup-mfe/__snapshots__/setup-mfe.spec.ts.snap +++ b/packages/angular/src/generators/setup-mfe/__snapshots__/setup-mfe.spec.ts.snap @@ -31,35 +31,43 @@ 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`] = ` -"const { withModuleFederation } = require('@nrwl/angular/module-federation'); -module.exports = withModuleFederation({ +"module.exports = { name: 'app1', 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`] = ` -"const { withModuleFederation } = require('@nrwl/angular/module-federation'); -module.exports = withModuleFederation({ +"module.exports = { name: 'app1', remotes: ['remote1',] -});" +}" `; -exports[`Init MFE should create webpack configs correctly 1`] = ` +exports[`Init MFE should create webpack and mfe configs correctly 1`] = ` "const { withModuleFederation } = require('@nrwl/angular/module-federation'); -module.exports = withModuleFederation({ +const config = require('./mfe.config'); +module.exports = withModuleFederation(config);" +`; + +exports[`Init MFE should create webpack and mfe configs correctly 2`] = ` +"module.exports = { name: 'app1', remotes: [] -});" +}" `; -exports[`Init MFE should create webpack configs correctly 2`] = ` +exports[`Init MFE should create webpack and mfe configs correctly 3`] = ` "const { withModuleFederation } = require('@nrwl/angular/module-federation'); -module.exports = withModuleFederation({ +const config = require('./mfe.config'); +module.exports = withModuleFederation(config);" +`; + +exports[`Init MFE should create webpack and mfe configs correctly 4`] = ` +"module.exports = { name: 'remote1', exposes: { './Module': 'apps/remote1/src/app/remote-entry/entry.module.ts', }, -});" +}" `; diff --git a/packages/angular/src/generators/setup-mfe/files/webpack/mfe.config.js__tmpl__ b/packages/angular/src/generators/setup-mfe/files/webpack/mfe.config.js__tmpl__ new file mode 100644 index 00000000000000..ca6571b0c597d4 --- /dev/null +++ b/packages/angular/src/generators/setup-mfe/files/webpack/mfe.config.js__tmpl__ @@ -0,0 +1,7 @@ +module.exports = { + name: '<%= name %>',<% if(type === 'host') { %> + remotes: [<% remotes.forEach(function(remote) { %>'<%= remote.remoteName %>',<% }); %>]<% } %><% if(type === 'remote') { %> + exposes: { + './Module': '<%= projectRoot %>/src/app/remote-entry/entry.module.ts', + },<% } %> +} \ No newline at end of file diff --git a/packages/angular/src/generators/setup-mfe/files/webpack/webpack.config.js__tmpl__ b/packages/angular/src/generators/setup-mfe/files/webpack/webpack.config.js__tmpl__ index f6b7303e32c8ec..d3576ea4abd01e 100644 --- a/packages/angular/src/generators/setup-mfe/files/webpack/webpack.config.js__tmpl__ +++ b/packages/angular/src/generators/setup-mfe/files/webpack/webpack.config.js__tmpl__ @@ -1,8 +1,3 @@ const { withModuleFederation } = require('@nrwl/angular/module-federation'); -module.exports = withModuleFederation({ - name: '<%= name %>',<% if(type === 'host') { %> - remotes: [<% remotes.forEach(function(remote) { %>'<%= remote.remoteName %>',<% }); %>]<% } %><% if(type === 'remote') { %> - exposes: { - './Module': '<%= projectRoot %>/src/app/remote-entry/entry.module.ts', - },<% } %> -}); \ No newline at end of file +const config = require('./mfe.config'); +module.exports = withModuleFederation(config); \ No newline at end of file diff --git a/packages/angular/src/generators/setup-mfe/lib/add-remote-to-host.ts b/packages/angular/src/generators/setup-mfe/lib/add-remote-to-host.ts index 16c47f548179a7..732efb4e069e37 100644 --- a/packages/angular/src/generators/setup-mfe/lib/add-remote-to-host.ts +++ b/packages/angular/src/generators/setup-mfe/lib/add-remote-to-host.ts @@ -20,17 +20,19 @@ export function checkIsCommaNeeded(mfeRemoteText: string) { export function addRemoteToHost(host: Tree, options: Schema) { if (options.mfeType === 'remote' && options.host) { const hostProject = readProjectConfiguration(host, options.host); - const hostWebpackPath = - hostProject.targets['build'].options.customWebpackConfig?.path; + const hostMfeConfigPath = joinPathFragments( + hostProject.root, + 'mfe.config.js' + ); - if (!hostWebpackPath || !host.exists(hostWebpackPath)) { + if (!hostMfeConfigPath || !host.exists(hostMfeConfigPath)) { throw new Error( - `The selected host application, ${options.host}, does not contain a webpack.config.js. Are you sure it has been set up as a host application?` + `The selected host application, ${options.host}, does not contain a mfe.config.js. Are you sure it has been set up as a host application?` ); } - const hostWebpackConfig = host.read(hostWebpackPath, 'utf-8'); - const webpackAst = tsquery.ast(hostWebpackConfig); + const hostMFEConfig = host.read(hostMfeConfigPath, 'utf-8'); + const webpackAst = tsquery.ast(hostMFEConfig); const mfRemotesNode = tsquery( webpackAst, 'Identifier[name=remotes] ~ ArrayLiteralExpression', @@ -40,11 +42,11 @@ export function addRemoteToHost(host: Tree, options: Schema) { const endOfPropertiesPos = mfRemotesNode.getEnd() - 1; const isCommaNeeded = checkIsCommaNeeded(mfRemotesNode.getText()); - const updatedConfig = `${hostWebpackConfig.slice(0, endOfPropertiesPos)}${ + const updatedConfig = `${hostMFEConfig.slice(0, endOfPropertiesPos)}${ isCommaNeeded ? ',' : '' - }'${options.appName}',${hostWebpackConfig.slice(endOfPropertiesPos)}`; + }'${options.appName}',${hostMFEConfig.slice(endOfPropertiesPos)}`; - host.write(hostWebpackPath, updatedConfig); + host.write(hostMfeConfigPath, updatedConfig); const declarationFilePath = joinPathFragments( hostProject.sourceRoot, diff --git a/packages/angular/src/generators/setup-mfe/lib/generate-config.ts b/packages/angular/src/generators/setup-mfe/lib/generate-config.ts index a24b27b788a634..51c457aa90eb9d 100644 --- a/packages/angular/src/generators/setup-mfe/lib/generate-config.ts +++ b/packages/angular/src/generators/setup-mfe/lib/generate-config.ts @@ -9,6 +9,7 @@ export function generateWebpackConfig( remotesWithPorts: { remoteName: string; port: number }[] ) { if ( + host.exists(`${appRoot}/mfe.config.js`) || host.exists(`${appRoot}/webpack.config.js`) || host.exists(`${appRoot}/webpack.prod.config.js`) ) { diff --git a/packages/angular/src/generators/setup-mfe/setup-mfe.spec.ts b/packages/angular/src/generators/setup-mfe/setup-mfe.spec.ts index ef09d587c15a73..081c833765ed00 100644 --- a/packages/angular/src/generators/setup-mfe/setup-mfe.spec.ts +++ b/packages/angular/src/generators/setup-mfe/setup-mfe.spec.ts @@ -23,7 +23,7 @@ describe('Init MFE', () => { ['app1', 'host'], ['remote1', 'remote'], ])( - 'should create webpack configs correctly', + 'should create webpack and mfe configs correctly', async (app, type: 'host' | 'remote') => { // ACT await setupMfe(host, { @@ -32,14 +32,18 @@ describe('Init MFE', () => { }); // ASSERT + expect(host.exists(`apps/${app}/mfe.config.js`)).toBeTruthy(); expect(host.exists(`apps/${app}/webpack.config.js`)).toBeTruthy(); expect(host.exists(`apps/${app}/webpack.prod.config.js`)).toBeTruthy(); - const webpackContetnts = host.read( + const webpackContents = host.read( `apps/${app}/webpack.config.js`, 'utf-8' ); - expect(webpackContetnts).toMatchSnapshot(); + expect(webpackContents).toMatchSnapshot(); + + const mfeConfigContents = host.read(`apps/${app}/mfe.config.js`, 'utf-8'); + expect(mfeConfigContents).toMatchSnapshot(); } ); @@ -127,9 +131,9 @@ describe('Init MFE', () => { }); // ASSERT - const webpackContents = host.read(`apps/app1/webpack.config.js`, 'utf-8'); + const mfeConfigContents = host.read(`apps/app1/mfe.config.js`, 'utf-8'); - expect(webpackContents).toContain(`'remote1'`); + expect(mfeConfigContents).toContain(`'remote1'`); }); it('should update the implicit dependencies of the host when --remotes flag supplied', async () => { // ACT @@ -163,8 +167,8 @@ describe('Init MFE', () => { }); // ASSERT - const hostWebpackConfig = host.read('apps/app1/webpack.config.js', 'utf-8'); - expect(hostWebpackConfig).toMatchSnapshot(); + const hostMfeConfig = host.read('apps/app1/mfe.config.js', 'utf-8'); + expect(hostMfeConfig).toMatchSnapshot(); }); it('should add a remote application and add it to a specified host applications webpack config that contains a remote application already', async () => { @@ -194,8 +198,8 @@ describe('Init MFE', () => { }); // ASSERT - const hostWebpackConfig = host.read('apps/app1/webpack.config.js', 'utf-8'); - expect(hostWebpackConfig).toMatchSnapshot(); + const hostMfeConfig = host.read('apps/app1/mfe.config.js', 'utf-8'); + expect(hostMfeConfig).toMatchSnapshot(); }); it('should add a remote application and add it to a specified host applications router config', async () => { diff --git a/packages/angular/src/utils/mfe/with-module-federation.ts b/packages/angular/src/utils/mfe/with-module-federation.ts index 8cc7255ea6f0f0..8f680b55539916 100644 --- a/packages/angular/src/utils/mfe/with-module-federation.ts +++ b/packages/angular/src/utils/mfe/with-module-federation.ts @@ -161,7 +161,12 @@ function mapRemotes(remotes: MFERemotes) { for (const remote of remotes) { if (Array.isArray(remote)) { - mappedRemotes[remote[0]] = remote[1]; + const remoteLocation = remote[1].match(/remoteEntry\.(js|mjs)/) + ? remote[1] + : `${ + remote[1].endsWith('/') ? remote[1].slice(0, -1) : remote[1] + }/remoteEntry.mjs`; + mappedRemotes[remote[0]] = remoteLocation; } else if (typeof remote === 'string') { mappedRemotes[remote] = determineRemoteUrl(remote); }