feat(module-federation): move withModuleFederation for angular to new package (#29021)

<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->
The `withModuleFederation` helper currently lives in the `@nx/angular`
package.
With the goal of consolidating the module federation support into a
single package, this introduces a divergence in where module-federation
support lies


## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->
Move `withModuleFederation` helper for angular into the
`@nx/module-federation` package, exposed via
`@nx/module-federation/angular`.
Adds a migration to migrate existing projects to use the new package

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #
This commit is contained in:
Colum Ferry 2024-11-21 11:07:51 -05:00 committed by GitHub
parent 940ada38b4
commit 9ca15f75b0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 245 additions and 37 deletions

View File

@ -272,6 +272,12 @@
"version": "20.2.0-beta.2",
"description": "Update the ModuleFederationConfig import use @nx/module-federation.",
"factory": "./src/migrations/update-20-2-0/migrate-mf-imports-to-new-package"
},
"update-20-2-0-update-with-module-federation-import": {
"cli": "nx",
"version": "20.2.0-beta.2",
"description": "Update the withModuleFederation import use @nx/module-federation/angular.",
"factory": "./src/migrations/update-20-2-0/migrate-with-mf-import-to-new-package"
}
},
"packageJsonUpdates": {

View File

@ -1,2 +1,9 @@
export { withModuleFederation } from '../src/utils/mf/with-module-federation';
export { withModuleFederationForSSR } from '../src/utils/mf/with-module-federation-ssr';
import {
withModuleFederation,
withModuleFederationForSSR,
} from '@nx/module-federation/angular';
/**
* @deprecated Update the import path to `@nx/module-federation/angular` instead. This import path will be removed in Nx v22.
*/
export { withModuleFederation, withModuleFederationForSSR };

View File

@ -57,8 +57,6 @@
"semver": "^7.5.3",
"tslib": "^2.3.0",
"webpack-merge": "^5.8.0",
"webpack": "^5.88.0",
"@module-federation/enhanced": "0.7.6",
"@nx/devkit": "file:../devkit",
"@nx/js": "file:../js",
"@nx/eslint": "file:../eslint",

View File

@ -255,7 +255,7 @@ module.exports = {
`;
exports[`Host App Generator --ssr should generate the correct files 7`] = `
"const { withModuleFederationForSSR } = require('@nx/angular/module-federation');
"const { withModuleFederationForSSR } = require('@nx/module-federation/angular');
const config = require('./module-federation.config');
/**
* DTS Plugin is disabled in Nx Workspaces as Nx already provides Typing support for Module Federation
@ -447,7 +447,7 @@ module.exports = {
`;
exports[`Host App Generator --ssr should generate the correct files for standalone 6`] = `
"const { withModuleFederationForSSR } = require('@nx/angular/module-federation');
"const { withModuleFederationForSSR } = require('@nx/module-federation/angular');
const config = require('./module-federation.config');
/**
* DTS Plugin is disabled in Nx Workspaces as Nx already provides Typing support for Module Federation
@ -669,7 +669,7 @@ export default config;
`;
exports[`Host App Generator --ssr should generate the correct files for standalone when --typescript=true 6`] = `
"import { withModuleFederationForSSR } from '@nx/angular/module-federation';
"import { withModuleFederationForSSR } from '@nx/module-federation/angular';
import config from './module-federation.config';
/**
@ -907,7 +907,7 @@ export default config;
`;
exports[`Host App Generator --ssr should generate the correct files when --typescript=true 7`] = `
"import { withModuleFederationForSSR } from '@nx/angular/module-federation';
"import { withModuleFederationForSSR } from '@nx/module-federation/angular';
import config from './module-federation.config';
/**
@ -978,7 +978,7 @@ exports[`Host App Generator --ssr should generate the correct files when --types
`;
exports[`Host App Generator should generate a host app with a remote 1`] = `
"const { withModuleFederation } = require('@nx/angular/module-federation');
"const { withModuleFederation } = require('@nx/module-federation/angular');
const config = require('./module-federation.config');
/**
@ -991,7 +991,7 @@ module.exports = withModuleFederation(config, { dts: false });
`;
exports[`Host App Generator should generate a host app with a remote 2`] = `
"const { withModuleFederation } = require('@nx/angular/module-federation');
"const { withModuleFederation } = require('@nx/module-federation/angular');
const config = require('./module-federation.config');
/**
@ -1004,7 +1004,7 @@ module.exports = withModuleFederation(config, { dts: false });
`;
exports[`Host App Generator should generate a host app with a remote when --typesscript=true 1`] = `
"import { withModuleFederation } from '@nx/angular/module-federation';
"import { withModuleFederation } from '@nx/module-federation/angular';
import config from './module-federation.config';
/**
@ -1017,7 +1017,7 @@ export default withModuleFederation(config, { dts: false });
`;
exports[`Host App Generator should generate a host app with a remote when --typesscript=true 2`] = `
"import { withModuleFederation } from '@nx/angular/module-federation';
"import { withModuleFederation } from '@nx/module-federation/angular';
import config from './module-federation.config';
/**
@ -1030,7 +1030,7 @@ export default withModuleFederation(config, { dts: false });
`;
exports[`Host App Generator should generate a host app with no remotes 1`] = `
"const { withModuleFederation } = require('@nx/angular/module-federation');
"const { withModuleFederation } = require('@nx/module-federation/angular');
const config = require('./module-federation.config');
/**
@ -1043,7 +1043,7 @@ module.exports = withModuleFederation(config, { dts: false });
`;
exports[`Host App Generator should generate a host app with no remotes when --typescript=true 1`] = `
"import { withModuleFederation } from '@nx/angular/module-federation';
"import { withModuleFederation } from '@nx/module-federation/angular';
import config from './module-federation.config';
/**

View File

@ -1,4 +1,4 @@
const { withModuleFederationForSSR } = require('@nx/angular/module-federation');
const { withModuleFederationForSSR } = require('@nx/module-federation/angular');
const config = require('./module-federation.config');
/**
* DTS Plugin is disabled in Nx Workspaces as Nx already provides Typing support for Module Federation

View File

@ -1,4 +1,4 @@
import { withModuleFederationForSSR } from '@nx/angular/module-federation';
import { withModuleFederationForSSR } from '@nx/module-federation/angular';
import config from './module-federation.config';
/**

View File

@ -219,7 +219,7 @@ module.exports = {
`;
exports[`MF Remote App Generator --ssr should generate the correct files 7`] = `
"const { withModuleFederationForSSR } = require('@nx/angular/module-federation');
"const { withModuleFederationForSSR } = require('@nx/module-federation/angular');
const config = require('./module-federation.config');
/**
@ -452,7 +452,7 @@ export default config;
`;
exports[`MF Remote App Generator --ssr should generate the correct files when --typescriptConfiguration=true 7`] = `
"import { withModuleFederationForSSR } from '@nx/angular/module-federation';
"import { withModuleFederationForSSR } from '@nx/module-federation/angular';
import config from './module-federation.config';
/**
@ -540,7 +540,7 @@ exports[`MF Remote App Generator --ssr should generate the correct files when --
`;
exports[`MF Remote App Generator should generate a remote mf app with a host 1`] = `
"const { withModuleFederation } = require('@nx/angular/module-federation');
"const { withModuleFederation } = require('@nx/module-federation/angular');
const config = require('./module-federation.config');
/**
@ -553,7 +553,7 @@ module.exports = withModuleFederation(config, { dts: false });
`;
exports[`MF Remote App Generator should generate a remote mf app with a host 2`] = `
"const { withModuleFederation } = require('@nx/angular/module-federation');
"const { withModuleFederation } = require('@nx/module-federation/angular');
const config = require('./module-federation.config');
/**
@ -566,7 +566,7 @@ module.exports = withModuleFederation(config, { dts: false });
`;
exports[`MF Remote App Generator should generate a remote mf app with a host when --typescriptConfiguration=true 1`] = `
"import { withModuleFederation } from '@nx/angular/module-federation';
"import { withModuleFederation } from '@nx/module-federation/angular';
import config from './module-federation.config';
/**
@ -579,7 +579,7 @@ export default withModuleFederation(config, { dts: false });
`;
exports[`MF Remote App Generator should generate a remote mf app with a host when --typescriptConfiguration=true 2`] = `
"import { withModuleFederation } from '@nx/angular/module-federation';
"import { withModuleFederation } from '@nx/module-federation/angular';
import config from './module-federation.config';
/**
@ -592,7 +592,7 @@ export default withModuleFederation(config, { dts: false });
`;
exports[`MF Remote App Generator should generate a remote mf app with no host 1`] = `
"const { withModuleFederation } = require('@nx/angular/module-federation');
"const { withModuleFederation } = require('@nx/module-federation/angular');
const config = require('./module-federation.config');
/**
@ -605,7 +605,7 @@ module.exports = withModuleFederation(config, { dts: false });
`;
exports[`MF Remote App Generator should generate a remote mf app with no host when --typescriptConfiguration=true 1`] = `
"import { withModuleFederation } from '@nx/angular/module-federation';
"import { withModuleFederation } from '@nx/module-federation/angular';
import config from './module-federation.config';
/**

View File

@ -1,4 +1,4 @@
import { withModuleFederationForSSR } from '@nx/angular/module-federation';
import { withModuleFederationForSSR } from '@nx/module-federation/angular';
import config from './module-federation.config';
/**

View File

@ -1,4 +1,4 @@
const { withModuleFederationForSSR } = require('@nx/angular/module-federation');
const { withModuleFederationForSSR } = require('@nx/module-federation/angular');
const config = require('./module-federation.config');
/**

View File

@ -209,7 +209,7 @@ export const appRoutes: Route[] = [
`;
exports[`Init MF should create webpack and mf configs correctly 1`] = `
"const { withModuleFederation } = require('@nx/angular/module-federation');
"const { withModuleFederation } = require('@nx/module-federation/angular');
const config = require('./module-federation.config');
/**
@ -245,7 +245,7 @@ module.exports = {
`;
exports[`Init MF should create webpack and mf configs correctly 3`] = `
"const { withModuleFederation } = require('@nx/angular/module-federation');
"const { withModuleFederation } = require('@nx/module-federation/angular');
const config = require('./module-federation.config');
/**
@ -271,7 +271,7 @@ module.exports = {
`;
exports[`Init MF should create webpack and mf configs correctly when --typescriptConfiguration=true 1`] = `
"import { withModuleFederation } from '@nx/angular/module-federation';
"import { withModuleFederation } from '@nx/module-federation/angular';
import config from './module-federation.config';
/**
@ -311,7 +311,7 @@ export default config;
`;
exports[`Init MF should create webpack and mf configs correctly when --typescriptConfiguration=true 3`] = `
"import { withModuleFederation } from '@nx/angular/module-federation';
"import { withModuleFederation } from '@nx/module-federation/angular';
import config from './module-federation.config';
/**

View File

@ -1,4 +1,4 @@
import { withModuleFederation } from '@nx/angular/module-federation';
import { withModuleFederation } from '@nx/module-federation/angular';
import config from './module-federation.config';
/**

View File

@ -1,4 +1,4 @@
import { withModuleFederation } from '@nx/angular/module-federation';
import { withModuleFederation } from '@nx/module-federation/angular';
import config from './module-federation.config';
/**

View File

@ -1,4 +1,4 @@
const { withModuleFederation } = require('@nx/angular/module-federation');
const { withModuleFederation } = require('@nx/module-federation/angular');
const config = require('./module-federation.config');
/**

View File

@ -1,4 +1,4 @@
const { withModuleFederation } = require('@nx/angular/module-federation');
const { withModuleFederation } = require('@nx/module-federation/angular');
const config = require('./module-federation.config');
/**

View File

@ -0,0 +1,138 @@
import { type Tree } from '@nx/devkit';
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import migrateWithMfImport from './migrate-with-mf-import-to-new-package';
describe('migrate-with-mf-import-to-new-package', () => {
let tree: Tree;
beforeEach(() => {
tree = createTreeWithEmptyWorkspace();
tree.write(
'apps/shell/project.json',
JSON.stringify({
name: 'shell',
root: 'apps/shell',
sourceRoot: 'apps/shell/src',
projectType: 'application',
targets: {
build: {
executor: '@nx/angular:webpack-browser',
options: {},
},
},
})
);
});
it('should migrate the import correctly for withMf', async () => {
// ARRANGE
tree.write(
'apps/shell/webpack.config.ts',
`import { withModuleFederation } from '@nx/angular/module-federation';`
);
// ACT
await migrateWithMfImport(tree);
// ASSERT
expect(tree.read('apps/shell/webpack.config.ts', 'utf-8'))
.toMatchInlineSnapshot(`
"import { withModuleFederation } from '@nx/module-federation/angular';
"
`);
});
it('should migrate the require correctly for withMf', async () => {
// ARRANGE
tree.write(
'apps/shell/webpack.config.js',
`const { withModuleFederation } = require('@nx/angular/module-federation');`
);
// ACT
await migrateWithMfImport(tree);
// ASSERT
expect(tree.read('apps/shell/webpack.config.js', 'utf-8'))
.toMatchInlineSnapshot(`
"const { withModuleFederation } = require('@nx/module-federation/angular');
"
`);
});
it('should migrate the import correctly for withMfSSR', async () => {
// ARRANGE
tree.write(
'apps/shell/webpack.config.ts',
`import { withModuleFederationForSSR } from '@nx/angular/module-federation';`
);
// ACT
await migrateWithMfImport(tree);
// ASSERT
expect(tree.read('apps/shell/webpack.config.ts', 'utf-8'))
.toMatchInlineSnapshot(`
"import { withModuleFederationForSSR } from '@nx/module-federation/angular';
"
`);
});
it('should migrate the require correctly for withMfSSR', async () => {
// ARRANGE
tree.write(
'apps/shell/webpack.config.js',
`const { withModuleFederationForSSR } = require('@nx/angular/module-federation');`
);
// ACT
await migrateWithMfImport(tree);
// ASSERT
expect(tree.read('apps/shell/webpack.config.js', 'utf-8'))
.toMatchInlineSnapshot(`
"const { withModuleFederationForSSR } = require('@nx/module-federation/angular');
"
`);
});
describe('idempotent', () => {
it('should migrate the import correctly for withMf even when run twice', async () => {
// ARRANGE
tree.write(
'apps/shell/webpack.config.ts',
`import { withModuleFederation } from '@nx/angular/module-federation';`
);
// ACT
await migrateWithMfImport(tree);
await migrateWithMfImport(tree);
// ASSERT
expect(tree.read('apps/shell/webpack.config.ts', 'utf-8'))
.toMatchInlineSnapshot(`
"import { withModuleFederation } from '@nx/module-federation/angular';
"
`);
});
it('should migrate the require correctly for withMfSSR even when run twice', async () => {
// ARRANGE
tree.write(
'apps/shell/webpack.config.js',
`const { withModuleFederationForSSR } = require('@nx/angular/module-federation');`
);
// ACT
await migrateWithMfImport(tree);
await migrateWithMfImport(tree);
// ASSERT
expect(tree.read('apps/shell/webpack.config.js', 'utf-8'))
.toMatchInlineSnapshot(`
"const { withModuleFederationForSSR } = require('@nx/module-federation/angular');
"
`);
});
});
});

View File

@ -0,0 +1,57 @@
import {
type Tree,
formatFiles,
readProjectConfiguration,
visitNotIgnoredFiles,
} from '@nx/devkit';
import { forEachExecutorOptions } from '@nx/devkit/src/generators/executor-options-utils';
import { tsquery } from '@phenomnomnominal/tsquery';
const NX_ANGULAR_MODULE_FEDERATION_IMPORT_SELECTOR =
'ImportDeclaration > StringLiteral[value=@nx/angular/module-federation], VariableStatement CallExpression:has(Identifier[name=require]) > StringLiteral[value=@nx/angular/module-federation]';
const NEW_IMPORT_PATH = `'@nx/module-federation/angular'`;
export default async function migrateWithMfImport(tree: Tree) {
const projects = new Set<string>();
forEachExecutorOptions(
tree,
'@nx/angular:webpack-browser',
(options, project, target) => {
const projectConfig = readProjectConfiguration(tree, project);
projects.add(projectConfig.root);
}
);
for (const projectRoot of projects) {
visitNotIgnoredFiles(tree, projectRoot, (filePath) => {
if (!filePath.endsWith('.ts') && !filePath.endsWith('.js')) {
return;
}
let contents = tree.read(filePath, 'utf-8');
if (!contents.includes('@nx/angular/module-federation')) {
return;
}
const ast = tsquery.ast(contents);
const importNodes = tsquery(
ast,
NX_ANGULAR_MODULE_FEDERATION_IMPORT_SELECTOR
);
if (importNodes.length === 0) {
return;
}
const importPathNode = importNodes[0];
contents = `${contents.slice(
0,
importPathNode.getStart()
)}${NEW_IMPORT_PATH}${contents.slice(importPathNode.getEnd())}`;
tree.write(filePath, contents);
});
}
await formatFiles(tree);
}

View File

@ -0,0 +1,2 @@
export * from './src/with-module-federation/angular/with-module-federation';
export * from './src/with-module-federation/angular/with-module-federation-ssr';

View File

@ -8,7 +8,7 @@ import {
SharedLibraryConfig,
sharePackages,
shareWorkspaceLibraries,
} from '@nx/module-federation';
} from '../../utils';
import {
createProjectGraphAsync,

View File

@ -1,7 +1,7 @@
import type {
ModuleFederationConfig,
NxModuleFederationConfigOverride,
} from '@nx/module-federation';
} from '../../utils';
import { getModuleFederationConfig } from './utils';
export async function withModuleFederationForSSR(

View File

@ -1,7 +1,7 @@
import type {
ModuleFederationConfig,
NxModuleFederationConfigOverride,
} from '@nx/module-federation';
} from '../../utils';
import { getModuleFederationConfig } from './utils';
import { ModuleFederationPlugin } from '@module-federation/enhanced/webpack';