From 432d9d3b17dc6bbd2adffec25959cdcbf25594dd Mon Sep 17 00:00:00 2001 From: Colum Ferry Date: Fri, 22 Nov 2024 08:28:13 -0500 Subject: [PATCH] feat(module-federation): move withModuleFederation for webpack to new package (#29031) ## Current Behavior The `withModuleFederation` helper currently lives in the `@nx/react` 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 Move `withModuleFederation` helper for angular into the `@nx/module-federation` package, exposed via `@nx/module-federation/webpack`. Adds a migration to migrate existing projects to use the new package ## Related Issue(s) Fixes # --- packages/module-federation/.eslintrc.json | 3 +- packages/module-federation/package.json | 3 +- .../with-module-federation/webpack}/utils.ts | 2 +- .../webpack}/with-module-federation-ssr.ts | 2 +- .../webpack}/with-module-federation.ts | 6 +- packages/module-federation/webpack.ts | 2 + packages/react/migrations.json | 6 + packages/react/module-federation.ts | 19 ++- packages/react/package.json | 1 - .../__snapshots__/host.webpack.spec.ts.snap | 8 +- .../webpack.server.config.ts__tmpl__ | 2 +- .../webpack.server.config.js__tmpl__ | 2 +- .../webpack.config.prod.ts__tmpl__ | 2 +- .../webpack.config.ts__tmpl__ | 2 +- .../webpack.config.js__tmpl__ | 2 +- .../webpack.config.prod.js__tmpl__ | 2 +- .../__snapshots__/remote.webpack.spec.ts.snap | 10 +- .../webpack.server.config.ts__tmpl__ | 2 +- .../webpack.server.config.js__tmpl__ | 2 +- .../webpack.config.ts__tmpl__ | 2 +- .../webpack.config.js__tmpl__ | 2 +- ...rate-with-mf-import-to-new-package.spec.ts | 138 ++++++++++++++++++ .../migrate-with-mf-import-to-new-package.ts | 57 ++++++++ .../convert-webpack/lib/transform-cjs.ts | 4 +- .../convert-webpack/lib/transform-esm.ts | 4 +- 25 files changed, 249 insertions(+), 36 deletions(-) rename packages/{react/src/module-federation => module-federation/src/with-module-federation/webpack}/utils.ts (99%) rename packages/{react/src/module-federation => module-federation/src/with-module-federation/webpack}/with-module-federation-ssr.ts (98%) rename packages/{react/src/module-federation => module-federation/src/with-module-federation/webpack}/with-module-federation.ts (92%) create mode 100644 packages/module-federation/webpack.ts create mode 100644 packages/react/src/migrations/update-20-2-0/migrate-with-mf-import-to-new-package.spec.ts create mode 100644 packages/react/src/migrations/update-20-2-0/migrate-with-mf-import-to-new-package.ts diff --git a/packages/module-federation/.eslintrc.json b/packages/module-federation/.eslintrc.json index 85e1f5edfb9ab..dee476ba6a4e0 100644 --- a/packages/module-federation/.eslintrc.json +++ b/packages/module-federation/.eslintrc.json @@ -35,7 +35,8 @@ "typescript", "@nx/cypress", "@nx/playwright", - "@nx/vite" + "@nx/vite", + "@module-federation/node" ] } ] diff --git a/packages/module-federation/package.json b/packages/module-federation/package.json index cce3a83214b41..959c83a70dac5 100644 --- a/packages/module-federation/package.json +++ b/packages/module-federation/package.json @@ -28,10 +28,11 @@ "@nx/devkit": "file:../devkit", "@nx/js": "file:../js", "picocolors": "^1.1.0", - "@module-federation/sdk": "0.7.6", "webpack": "5.88.0", "@rspack/core": "1.1.2", "@module-federation/enhanced": "0.7.6", + "@module-federation/node": "2.6.11", + "@module-federation/sdk": "0.7.6", "express": "^4.19.2", "http-proxy-middleware": "^3.0.3" }, diff --git a/packages/react/src/module-federation/utils.ts b/packages/module-federation/src/with-module-federation/webpack/utils.ts similarity index 99% rename from packages/react/src/module-federation/utils.ts rename to packages/module-federation/src/with-module-federation/webpack/utils.ts index 439da5847b62c..bfd975d127a9a 100644 --- a/packages/react/src/module-federation/utils.ts +++ b/packages/module-federation/src/with-module-federation/webpack/utils.ts @@ -7,7 +7,7 @@ import { ModuleFederationConfig, sharePackages, shareWorkspaceLibraries, -} from '@nx/module-federation'; +} from '../../utils'; import { createProjectGraphAsync, diff --git a/packages/react/src/module-federation/with-module-federation-ssr.ts b/packages/module-federation/src/with-module-federation/webpack/with-module-federation-ssr.ts similarity index 98% rename from packages/react/src/module-federation/with-module-federation-ssr.ts rename to packages/module-federation/src/with-module-federation/webpack/with-module-federation-ssr.ts index 0b16606972954..4c3c32b72d5d5 100644 --- a/packages/react/src/module-federation/with-module-federation-ssr.ts +++ b/packages/module-federation/src/with-module-federation/webpack/with-module-federation-ssr.ts @@ -1,7 +1,7 @@ import { ModuleFederationConfig, NxModuleFederationConfigOverride, -} from '@nx/module-federation'; +} from '../../utils'; import { getModuleFederationConfig } from './utils'; import type { NormalModuleReplacementPlugin } from 'webpack'; diff --git a/packages/react/src/module-federation/with-module-federation.ts b/packages/module-federation/src/with-module-federation/webpack/with-module-federation.ts similarity index 92% rename from packages/react/src/module-federation/with-module-federation.ts rename to packages/module-federation/src/with-module-federation/webpack/with-module-federation.ts index f3bd9813989e9..5c7d0d6ad3391 100644 --- a/packages/react/src/module-federation/with-module-federation.ts +++ b/packages/module-federation/src/with-module-federation/webpack/with-module-federation.ts @@ -1,20 +1,18 @@ import { ModuleFederationConfig, NxModuleFederationConfigOverride, -} from '@nx/module-federation'; +} from '../../utils'; import { getModuleFederationConfig } from './utils'; -import type { AsyncNxComposableWebpackPlugin } from '@nx/webpack'; import { ModuleFederationPlugin } from '@module-federation/enhanced/webpack'; import type { NormalModuleReplacementPlugin } from 'webpack'; /** * @param {ModuleFederationConfig} options - * @return {Promise} */ export async function withModuleFederation( options: ModuleFederationConfig, configOverride?: NxModuleFederationConfigOverride -): Promise { +) { if (global.NX_GRAPH_CREATION) { return (config) => config; } diff --git a/packages/module-federation/webpack.ts b/packages/module-federation/webpack.ts new file mode 100644 index 0000000000000..c4183eaf163c9 --- /dev/null +++ b/packages/module-federation/webpack.ts @@ -0,0 +1,2 @@ +export * from './src/with-module-federation/webpack/with-module-federation'; +export * from './src/with-module-federation/webpack/with-module-federation-ssr'; diff --git a/packages/react/migrations.json b/packages/react/migrations.json index ac3528baf1aef..83c5716ced6e8 100644 --- a/packages/react/migrations.json +++ b/packages/react/migrations.json @@ -35,6 +35,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/webpack.", + "factory": "./src/migrations/update-20-2-0/migrate-with-mf-import-to-new-package" } }, "packageJsonUpdates": { diff --git a/packages/react/module-federation.ts b/packages/react/module-federation.ts index 8fbc447290b30..1f8ce92793fc8 100644 --- a/packages/react/module-federation.ts +++ b/packages/react/module-federation.ts @@ -1,12 +1,23 @@ -import { withModuleFederation } from './src/module-federation/with-module-federation'; -import { withModuleFederationForSSR } from './src/module-federation/with-module-federation-ssr'; +import { withModuleFederation } from '@nx/module-federation/webpack'; +import { withModuleFederationForSSR } from '@nx/module-federation/webpack'; -export { withModuleFederation }; -export { withModuleFederationForSSR }; +/** + * @deprecated Use `@nx/module-federation/webpack` instead. This will be removed in Nx v22. + */ +export { withModuleFederation, withModuleFederationForSSR }; // Support for older generated code: `const withModuleFederation = require('@nx/react/module-federation')` +/** + * @deprecated Use `@nx/module-federation/webpack` instead. This will be removed in Nx v22. + */ module.exports = withModuleFederation; // Allow newer generated code to work: `const { withModuleFederation } = require(...)`; +/** + * @deprecated Use `@nx/module-federation/webpack` instead. This will be removed in Nx v22. + */ module.exports.withModuleFederation = withModuleFederation; +/** + * @deprecated Use `@nx/module-federation/webpack` instead. This will be removed in Nx v22. + */ module.exports.withModuleFederationForSSR = withModuleFederationForSSR; diff --git a/packages/react/package.json b/packages/react/package.json index 6aada4cf168af..e5d7f0a3348d8 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -38,7 +38,6 @@ "minimatch": "9.0.3", "picocolors": "^1.1.0", "tslib": "^2.3.0", - "@module-federation/enhanced": "0.7.6", "@nx/devkit": "file:../devkit", "@nx/js": "file:../js", "@nx/eslint": "file:../eslint", diff --git a/packages/react/src/generators/host/__snapshots__/host.webpack.spec.ts.snap b/packages/react/src/generators/host/__snapshots__/host.webpack.spec.ts.snap index ccf8e7bab0099..9edb301069eee 100644 --- a/packages/react/src/generators/host/__snapshots__/host.webpack.spec.ts.snap +++ b/packages/react/src/generators/host/__snapshots__/host.webpack.spec.ts.snap @@ -3,7 +3,7 @@ exports[`hostGenerator bundler=webpack should generate host files and configs for SSR 1`] = ` "const { composePlugins, withNx } = require('@nx/webpack'); const { withReact } = require('@nx/react'); -const { withModuleFederationForSSR } = require('@nx/react/module-federation'); +const { withModuleFederationForSSR } = require('@nx/module-federation/webpack'); const baseConfig = require('./module-federation.config'); @@ -46,7 +46,7 @@ module.exports = moduleFederationConfig; exports[`hostGenerator bundler=webpack should generate host files and configs for SSR when --typescriptConfiguration=true 1`] = ` "import { composePlugins, withNx } from '@nx/webpack'; import { withReact } from '@nx/react'; -import { withModuleFederationForSSR } from '@nx/react/module-federation'; +import { withModuleFederationForSSR } from '@nx/module-federation/webpack'; import baseConfig from './module-federation.config'; @@ -86,7 +86,7 @@ export default config; exports[`hostGenerator bundler=webpack should generate host files and configs when --typescriptConfiguration=false 1`] = ` "const { composePlugins, withNx } = require('@nx/webpack'); const { withReact } = require('@nx/react'); -const { withModuleFederation } = require('@nx/react/module-federation'); +const { withModuleFederation } = require('@nx/module-federation/webpack'); const baseConfig = require('./module-federation.config'); @@ -134,7 +134,7 @@ module.exports = { exports[`hostGenerator bundler=webpack should generate host files and configs when --typescriptConfiguration=true 1`] = ` "import {composePlugins, withNx} from '@nx/webpack'; import {withReact} from '@nx/react'; -import {withModuleFederation} from '@nx/react/module-federation'; +import {withModuleFederation} from '@nx/module-federation/webpack'; import { ModuleFederationConfig } from '@nx/module-federation'; import baseConfig from './module-federation.config'; diff --git a/packages/react/src/generators/host/files/webpack-module-federation-ssr-ts/webpack.server.config.ts__tmpl__ b/packages/react/src/generators/host/files/webpack-module-federation-ssr-ts/webpack.server.config.ts__tmpl__ index 2388154cc15b6..f07d594e596e3 100644 --- a/packages/react/src/generators/host/files/webpack-module-federation-ssr-ts/webpack.server.config.ts__tmpl__ +++ b/packages/react/src/generators/host/files/webpack-module-federation-ssr-ts/webpack.server.config.ts__tmpl__ @@ -1,6 +1,6 @@ import {composePlugins, withNx} from '@nx/webpack'; import {withReact} from '@nx/react'; -import {withModuleFederationForSSR} from '@nx/react/module-federation'; +import {withModuleFederationForSSR} from '@nx/module-federation/webpack'; import baseConfig from './module-federation.config'; diff --git a/packages/react/src/generators/host/files/webpack-module-federation-ssr/webpack.server.config.js__tmpl__ b/packages/react/src/generators/host/files/webpack-module-federation-ssr/webpack.server.config.js__tmpl__ index 93a23c66de1b6..8c66eec549aac 100644 --- a/packages/react/src/generators/host/files/webpack-module-federation-ssr/webpack.server.config.js__tmpl__ +++ b/packages/react/src/generators/host/files/webpack-module-federation-ssr/webpack.server.config.js__tmpl__ @@ -1,6 +1,6 @@ const {composePlugins, withNx} = require('@nx/webpack'); const {withReact} = require('@nx/react'); -const {withModuleFederationForSSR} = require('@nx/react/module-federation'); +const {withModuleFederationForSSR} = require('@nx/module-federation/webpack'); const baseConfig = require('./module-federation.config'); diff --git a/packages/react/src/generators/host/files/webpack-module-federation-ts/webpack.config.prod.ts__tmpl__ b/packages/react/src/generators/host/files/webpack-module-federation-ts/webpack.config.prod.ts__tmpl__ index 03a55a321e764..85849e9a71fe8 100644 --- a/packages/react/src/generators/host/files/webpack-module-federation-ts/webpack.config.prod.ts__tmpl__ +++ b/packages/react/src/generators/host/files/webpack-module-federation-ts/webpack.config.prod.ts__tmpl__ @@ -1,6 +1,6 @@ import { composePlugins, withNx } from '@nx/webpack'; import { withReact } from '@nx/react'; -import { withModuleFederation } from '@nx/react/module-federation'; +import { withModuleFederation } from '@nx/module-federation/webpack'; import { ModuleFederationConfig } from '@nx/module-federation'; import baseConfig from './module-federation.config'; diff --git a/packages/react/src/generators/host/files/webpack-module-federation-ts/webpack.config.ts__tmpl__ b/packages/react/src/generators/host/files/webpack-module-federation-ts/webpack.config.ts__tmpl__ index c97fe8055beaf..ea5a39d03eb98 100644 --- a/packages/react/src/generators/host/files/webpack-module-federation-ts/webpack.config.ts__tmpl__ +++ b/packages/react/src/generators/host/files/webpack-module-federation-ts/webpack.config.ts__tmpl__ @@ -1,6 +1,6 @@ import {composePlugins, withNx} from '@nx/webpack'; import {withReact} from '@nx/react'; -import {withModuleFederation} from '@nx/react/module-federation'; +import {withModuleFederation} from '@nx/module-federation/webpack'; import { ModuleFederationConfig } from '@nx/module-federation'; import baseConfig from './module-federation.config'; diff --git a/packages/react/src/generators/host/files/webpack-module-federation/webpack.config.js__tmpl__ b/packages/react/src/generators/host/files/webpack-module-federation/webpack.config.js__tmpl__ index 3becbedf8c7b5..9e2040e90dec2 100644 --- a/packages/react/src/generators/host/files/webpack-module-federation/webpack.config.js__tmpl__ +++ b/packages/react/src/generators/host/files/webpack-module-federation/webpack.config.js__tmpl__ @@ -1,6 +1,6 @@ const { composePlugins, withNx } = require('@nx/webpack'); const { withReact } = require('@nx/react'); -const { withModuleFederation } = require('@nx/react/module-federation'); +const { withModuleFederation } = require('@nx/module-federation/webpack'); const baseConfig = require('./module-federation.config'); diff --git a/packages/react/src/generators/host/files/webpack-module-federation/webpack.config.prod.js__tmpl__ b/packages/react/src/generators/host/files/webpack-module-federation/webpack.config.prod.js__tmpl__ index cf879affc167d..568c9dde53cdd 100644 --- a/packages/react/src/generators/host/files/webpack-module-federation/webpack.config.prod.js__tmpl__ +++ b/packages/react/src/generators/host/files/webpack-module-federation/webpack.config.prod.js__tmpl__ @@ -1,6 +1,6 @@ const { composePlugins, withNx } = require('@nx/webpack'); const { withReact } = require('@nx/react'); -const { withModuleFederation } = require('@nx/react/module-federation'); +const { withModuleFederation } = require('@nx/module-federation/webpack'); const baseConfig = require('./module-federation.config'); diff --git a/packages/react/src/generators/remote/__snapshots__/remote.webpack.spec.ts.snap b/packages/react/src/generators/remote/__snapshots__/remote.webpack.spec.ts.snap index e39f6b75ab55f..2a242306aa694 100644 --- a/packages/react/src/generators/remote/__snapshots__/remote.webpack.spec.ts.snap +++ b/packages/react/src/generators/remote/__snapshots__/remote.webpack.spec.ts.snap @@ -3,7 +3,7 @@ exports[`remote generator bundler=webpack should create the remote with the correct config files 1`] = ` "const { composePlugins, withNx } = require('@nx/webpack'); const { withReact } = require('@nx/react'); -const { withModuleFederation } = require('@nx/react/module-federation'); +const { withModuleFederation } = require('@nx/module-federation/webpack'); const baseConfig = require('./module-federation.config'); @@ -39,7 +39,7 @@ module.exports = { exports[`remote generator bundler=webpack should create the remote with the correct config files when --js=true 1`] = ` "const { composePlugins, withNx } = require('@nx/webpack'); const { withReact } = require('@nx/react'); -const { withModuleFederation } = require('@nx/react/module-federation'); +const { withModuleFederation } = require('@nx/module-federation/webpack'); const baseConfig = require('./module-federation.config'); @@ -75,7 +75,7 @@ module.exports = { exports[`remote generator bundler=webpack should create the remote with the correct config files when --typescriptConfiguration=true 1`] = ` "import { composePlugins, withNx } from '@nx/webpack'; import { withReact } from '@nx/react'; -import { withModuleFederation } from '@nx/react/module-federation'; +import { withModuleFederation } from '@nx/module-federation/webpack'; import baseConfig from './module-federation.config'; @@ -122,7 +122,7 @@ export default config; exports[`remote generator bundler=webpack should generate correct remote with config files when using --ssr 1`] = ` "const {composePlugins, withNx} = require('@nx/webpack'); const {withReact} = require('@nx/react'); -const {withModuleFederationForSSR} = require('@nx/react/module-federation'); +const {withModuleFederationForSSR} = require('@nx/module-federation/webpack'); const baseConfig = require("./module-federation.server.config"); @@ -156,7 +156,7 @@ module.exports = { exports[`remote generator bundler=webpack should generate correct remote with config files when using --ssr and --typescriptConfiguration=true 1`] = ` "import { composePlugins, withNx } from '@nx/webpack'; import { withReact } from '@nx/react'; -import { withModuleFederationForSSR } from '@nx/react/module-federation'; +import { withModuleFederationForSSR } from '@nx/module-federation/webpack'; import baseConfig from './module-federation.server.config'; diff --git a/packages/react/src/generators/remote/files/webpack-module-federation-ssr-ts/webpack.server.config.ts__tmpl__ b/packages/react/src/generators/remote/files/webpack-module-federation-ssr-ts/webpack.server.config.ts__tmpl__ index 7b9ce041565e6..8ea68a1bd592d 100644 --- a/packages/react/src/generators/remote/files/webpack-module-federation-ssr-ts/webpack.server.config.ts__tmpl__ +++ b/packages/react/src/generators/remote/files/webpack-module-federation-ssr-ts/webpack.server.config.ts__tmpl__ @@ -1,6 +1,6 @@ import {composePlugins, withNx} from '@nx/webpack'; import {withReact} from '@nx/react'; -import {withModuleFederationForSSR} from '@nx/react/module-federation'; +import {withModuleFederationForSSR} from '@nx/module-federation/webpack'; import baseConfig from "./module-federation.server.config"; diff --git a/packages/react/src/generators/remote/files/webpack-module-federation-ssr/webpack.server.config.js__tmpl__ b/packages/react/src/generators/remote/files/webpack-module-federation-ssr/webpack.server.config.js__tmpl__ index e400aa73858c5..28533d88f9005 100644 --- a/packages/react/src/generators/remote/files/webpack-module-federation-ssr/webpack.server.config.js__tmpl__ +++ b/packages/react/src/generators/remote/files/webpack-module-federation-ssr/webpack.server.config.js__tmpl__ @@ -1,6 +1,6 @@ const {composePlugins, withNx} = require('@nx/webpack'); const {withReact} = require('@nx/react'); -const {withModuleFederationForSSR} = require('@nx/react/module-federation'); +const {withModuleFederationForSSR} = require('@nx/module-federation/webpack'); const baseConfig = require("./module-federation.server.config"); diff --git a/packages/react/src/generators/remote/files/webpack-module-federation-ts/webpack.config.ts__tmpl__ b/packages/react/src/generators/remote/files/webpack-module-federation-ts/webpack.config.ts__tmpl__ index f3248eafd7651..d5c85abc36d14 100644 --- a/packages/react/src/generators/remote/files/webpack-module-federation-ts/webpack.config.ts__tmpl__ +++ b/packages/react/src/generators/remote/files/webpack-module-federation-ts/webpack.config.ts__tmpl__ @@ -1,6 +1,6 @@ import {composePlugins, withNx} from '@nx/webpack'; import {withReact} from '@nx/react'; -import {withModuleFederation} from '@nx/react/module-federation'; +import {withModuleFederation} from '@nx/module-federation/webpack'; import baseConfig from './module-federation.config'; diff --git a/packages/react/src/generators/remote/files/webpack-module-federation/webpack.config.js__tmpl__ b/packages/react/src/generators/remote/files/webpack-module-federation/webpack.config.js__tmpl__ index e0a8ab4049f74..a12c1adfa4424 100644 --- a/packages/react/src/generators/remote/files/webpack-module-federation/webpack.config.js__tmpl__ +++ b/packages/react/src/generators/remote/files/webpack-module-federation/webpack.config.js__tmpl__ @@ -1,6 +1,6 @@ const { composePlugins, withNx } = require('@nx/webpack'); const { withReact } = require('@nx/react'); -const { withModuleFederation } = require('@nx/react/module-federation'); +const { withModuleFederation } = require('@nx/module-federation/webpack'); const baseConfig = require('./module-federation.config'); diff --git a/packages/react/src/migrations/update-20-2-0/migrate-with-mf-import-to-new-package.spec.ts b/packages/react/src/migrations/update-20-2-0/migrate-with-mf-import-to-new-package.spec.ts new file mode 100644 index 0000000000000..2db548d143899 --- /dev/null +++ b/packages/react/src/migrations/update-20-2-0/migrate-with-mf-import-to-new-package.spec.ts @@ -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: { + serve: { + executor: '@nx/react:module-federation-dev-server', + options: {}, + }, + }, + }) + ); + }); + + it('should migrate the import correctly for withMf', async () => { + // ARRANGE + tree.write( + 'apps/shell/webpack.config.ts', + `import { withModuleFederation } from '@nx/react/module-federation';` + ); + + // ACT + await migrateWithMfImport(tree); + + // ASSERT + expect(tree.read('apps/shell/webpack.config.ts', 'utf-8')) + .toMatchInlineSnapshot(` + "import { withModuleFederation } from '@nx/module-federation/webpack'; + " + `); + }); + + it('should migrate the require correctly for withMf', async () => { + // ARRANGE + tree.write( + 'apps/shell/webpack.config.js', + `const { withModuleFederation } = require('@nx/react/module-federation');` + ); + + // ACT + await migrateWithMfImport(tree); + + // ASSERT + expect(tree.read('apps/shell/webpack.config.js', 'utf-8')) + .toMatchInlineSnapshot(` + "const { withModuleFederation } = require('@nx/module-federation/webpack'); + " + `); + }); + + it('should migrate the import correctly for withMfSSR', async () => { + // ARRANGE + tree.write( + 'apps/shell/webpack.config.ts', + `import { withModuleFederationForSSR } from '@nx/react/module-federation';` + ); + + // ACT + await migrateWithMfImport(tree); + + // ASSERT + expect(tree.read('apps/shell/webpack.config.ts', 'utf-8')) + .toMatchInlineSnapshot(` + "import { withModuleFederationForSSR } from '@nx/module-federation/webpack'; + " + `); + }); + + it('should migrate the require correctly for withMfSSR', async () => { + // ARRANGE + tree.write( + 'apps/shell/webpack.config.js', + `const { withModuleFederationForSSR } = require('@nx/react/module-federation');` + ); + + // ACT + await migrateWithMfImport(tree); + + // ASSERT + expect(tree.read('apps/shell/webpack.config.js', 'utf-8')) + .toMatchInlineSnapshot(` + "const { withModuleFederationForSSR } = require('@nx/module-federation/webpack'); + " + `); + }); + + 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/react/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/webpack'; + " + `); + }); + + 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/react/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/webpack'); + " + `); + }); + }); +}); diff --git a/packages/react/src/migrations/update-20-2-0/migrate-with-mf-import-to-new-package.ts b/packages/react/src/migrations/update-20-2-0/migrate-with-mf-import-to-new-package.ts new file mode 100644 index 0000000000000..273f56bb7db8e --- /dev/null +++ b/packages/react/src/migrations/update-20-2-0/migrate-with-mf-import-to-new-package.ts @@ -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/react/module-federation], VariableStatement CallExpression:has(Identifier[name=require]) > StringLiteral[value=@nx/react/module-federation]'; +const NEW_IMPORT_PATH = `'@nx/module-federation/webpack'`; + +export default async function migrateWithMfImport(tree: Tree) { + const projects = new Set(); + + forEachExecutorOptions( + tree, + '@nx/react:module-federation-dev-server', + (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/react/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); +} diff --git a/packages/rspack/src/generators/convert-webpack/lib/transform-cjs.ts b/packages/rspack/src/generators/convert-webpack/lib/transform-cjs.ts index 6e6657ebb4315..5ef6523aeae9b 100644 --- a/packages/rspack/src/generators/convert-webpack/lib/transform-cjs.ts +++ b/packages/rspack/src/generators/convert-webpack/lib/transform-cjs.ts @@ -186,7 +186,7 @@ function transformWithModuleFederation( const configContents = tree.read(configPath, 'utf-8'); const ast = tsquery.ast(configContents); - const HAS_WITH_MODULE_FEDERATION_FROM_NX_REACT = `VariableDeclaration:has(Identifier[name=withModuleFederation]) > CallExpression:has(Identifier[name=require]) StringLiteral[value=${scope}/react/module-federation]`; + const HAS_WITH_MODULE_FEDERATION_FROM_NX_REACT = `VariableDeclaration:has(Identifier[name=withModuleFederation]) > CallExpression:has(Identifier[name=require]) StringLiteral[value=${scope}/module-federation/webpack]`; const nodes = tsquery(ast, HAS_WITH_MODULE_FEDERATION_FROM_NX_REACT); if (nodes.length === 0) { return; @@ -219,7 +219,7 @@ function transformWithModuleFederationSSR( const configContents = tree.read(configPath, 'utf-8'); const ast = tsquery.ast(configContents); - const HAS_WITH_MODULE_FEDERATION_FROM_NX_REACT = `VariableDeclaration:has(Identifier[name=withModuleFederationForSSR]) > CallExpression:has(Identifier[name=require]) StringLiteral[value=${scope}/react/module-federation]`; + const HAS_WITH_MODULE_FEDERATION_FROM_NX_REACT = `VariableDeclaration:has(Identifier[name=withModuleFederationForSSR]) > CallExpression:has(Identifier[name=require]) StringLiteral[value=${scope}/module-federation/webpack]`; const nodes = tsquery(ast, HAS_WITH_MODULE_FEDERATION_FROM_NX_REACT); if (nodes.length === 0) { return; diff --git a/packages/rspack/src/generators/convert-webpack/lib/transform-esm.ts b/packages/rspack/src/generators/convert-webpack/lib/transform-esm.ts index 1036f90c3f723..99dd282ba5b4a 100644 --- a/packages/rspack/src/generators/convert-webpack/lib/transform-esm.ts +++ b/packages/rspack/src/generators/convert-webpack/lib/transform-esm.ts @@ -153,7 +153,7 @@ function transformWithModuleFederation( const configContents = tree.read(configPath, 'utf-8'); const ast = tsquery.ast(configContents); - const HAS_WITH_MODULE_FEDERATION_FROM_NX_REACT = `ImportDeclaration:has(Identifier[name=withModuleFederation]) > StringLiteral[value=${scope}/react/module-federation]`; + const HAS_WITH_MODULE_FEDERATION_FROM_NX_REACT = `ImportDeclaration:has(Identifier[name=withModuleFederation]) > StringLiteral[value=${scope}/module-federation/webpack]`; const nodes = tsquery(ast, HAS_WITH_MODULE_FEDERATION_FROM_NX_REACT); if (nodes.length === 0) { return; @@ -219,7 +219,7 @@ function transformWithModuleFederationSSR( const configContents = tree.read(configPath, 'utf-8'); const ast = tsquery.ast(configContents); - const HAS_WITH_MODULE_FEDERATION_FROM_NX_REACT = `ImportDeclaration:has(Identifier[name=withModuleFederationForSSR]) > StringLiteral[value=${scope}/react/module-federation]`; + const HAS_WITH_MODULE_FEDERATION_FROM_NX_REACT = `ImportDeclaration:has(Identifier[name=withModuleFederationForSSR]) > StringLiteral[value=${scope}/module-federation/webpack]`; const nodes = tsquery(ast, HAS_WITH_MODULE_FEDERATION_FROM_NX_REACT); if (nodes.length === 0) { return;