diff --git a/.changeset/steady-workers-remotes.md b/.changeset/steady-workers-remotes.md
new file mode 100644
index 00000000000..d37ee1ea5db
--- /dev/null
+++ b/.changeset/steady-workers-remotes.md
@@ -0,0 +1,5 @@
+---
+"@module-federation/enhanced": patch
+---
+
+Keep async entry runtime helpers available when cloning runtimes for web workers and other dynamic entrypoints.
diff --git a/.env b/.env
index 166ab9c8e68..e871d6f9876 100644
--- a/.env
+++ b/.env
@@ -1 +1,2 @@
NX_DEAMON=false
+NX_DAEMON=false
diff --git a/.github/workflows/e2e-runtime.yml b/.github/workflows/e2e-runtime.yml
index ec5652d8d48..9ebad69b2dc 100644
--- a/.github/workflows/e2e-runtime.yml
+++ b/.github/workflows/e2e-runtime.yml
@@ -62,4 +62,4 @@ jobs:
- name: E2E Test for Runtime Demo
if: steps.check-ci.outcome == 'success'
- run: npx kill-port --port 3005,3006,3007 && pnpm run app:runtime:dev & echo "done" && sleep 20 && npx nx run-many --target=test:e2e --projects=3005-runtime-host --parallel=1 && lsof -ti tcp:3005,3006,3007 | xargs kill
+ run: node tools/scripts/run-runtime-e2e.mjs --mode=dev
diff --git a/apps/runtime-demo/3005-runtime-host/cypress/e2e/app.cy.ts b/apps/runtime-demo/3005-runtime-host/cypress/e2e/app.cy.ts
index 4383ea93ec1..c7aa74fb9d1 100644
--- a/apps/runtime-demo/3005-runtime-host/cypress/e2e/app.cy.ts
+++ b/apps/runtime-demo/3005-runtime-host/cypress/e2e/app.cy.ts
@@ -77,4 +77,19 @@ describe('3005-runtime-host/', () => {
});
});
});
+
+ describe('web worker check', () => {
+ it('should display value returned from worker', () => {
+ cy.get('.worker-native-result').should('contain.text', '"answer": "1"');
+ cy.get('.worker-native-result').should(
+ 'contain.text',
+ '"federationKeys"',
+ );
+ cy.get('.worker-loader-result').should('contain.text', '"answer": "1"');
+ cy.get('.worker-loader-result').should(
+ 'contain.text',
+ '"federationKeys"',
+ );
+ });
+ });
});
diff --git a/apps/runtime-demo/3005-runtime-host/package.json b/apps/runtime-demo/3005-runtime-host/package.json
index 993cae30289..13af902dec8 100644
--- a/apps/runtime-demo/3005-runtime-host/package.json
+++ b/apps/runtime-demo/3005-runtime-host/package.json
@@ -2,16 +2,25 @@
"name": "runtime-host",
"private": true,
"version": "0.0.0",
+ "scripts": {
+ "build": "webpack --config webpack.config.js --mode production",
+ "build:development": "webpack --config webpack.config.js --mode development",
+ "serve": "webpack serve --config webpack.config.js --mode development --host 127.0.0.1 --port 3005 --allowed-hosts all",
+ "serve:production": "webpack serve --config webpack.config.js --mode production --host 127.0.0.1 --port 3005 --allowed-hosts all --no-hot"
+ },
"devDependencies": {
"@module-federation/core": "workspace:*",
+ "@module-federation/dts-plugin": "workspace:*",
+ "@module-federation/enhanced": "workspace:*",
"@module-federation/runtime": "workspace:*",
"@module-federation/typescript": "workspace:*",
- "@module-federation/enhanced": "workspace:*",
- "@module-federation/dts-plugin": "workspace:*",
"@pmmmwh/react-refresh-webpack-plugin": "0.5.15",
- "react-refresh": "0.14.2",
"@types/react": "18.3.11",
- "@types/react-dom": "18.3.0"
+ "@types/react-dom": "18.3.0",
+ "mini-css-extract-plugin": "2.9.2",
+ "react-refresh": "0.14.2",
+ "css-loader": "6.11.0",
+ "webpack-dev-server": "5.1.0"
},
"dependencies": {
"antd": "4.24.15",
diff --git a/apps/runtime-demo/3005-runtime-host/project.json b/apps/runtime-demo/3005-runtime-host/project.json
index 4453a83f674..edf63d2c86d 100644
--- a/apps/runtime-demo/3005-runtime-host/project.json
+++ b/apps/runtime-demo/3005-runtime-host/project.json
@@ -6,35 +6,21 @@
"tags": [],
"targets": {
"build": {
- "executor": "@nx/webpack:webpack",
- "outputs": ["{options.outputPath}"],
+ "executor": "nx:run-commands",
+ "outputs": ["{projectRoot}/dist"],
"defaultConfiguration": "production",
"options": {
- "compiler": "babel",
- "outputPath": "apps/runtime-demo/3005-runtime-host/dist",
- "index": "apps/runtime-demo/3005-runtime-host/src/index.html",
- "baseHref": "/",
- "main": "apps/runtime-demo/3005-runtime-host/src/index.ts",
- "tsConfig": "apps/runtime-demo/3005-runtime-host/tsconfig.app.json",
- "styles": [],
- "scripts": [],
- "webpackConfig": "apps/runtime-demo/3005-runtime-host/webpack.config.js",
- "babelUpwardRootMode": true
+ "command": "pnpm run build",
+ "cwd": "apps/runtime-demo/3005-runtime-host"
},
"configurations": {
"development": {
- "extractLicenses": false,
- "optimization": false,
- "sourceMap": true,
- "vendorChunk": true
+ "command": "pnpm run build:development",
+ "cwd": "apps/runtime-demo/3005-runtime-host"
},
"production": {
- "optimization": true,
- "outputHashing": "all",
- "sourceMap": false,
- "namedChunks": false,
- "extractLicenses": false,
- "vendorChunk": false
+ "command": "pnpm run build",
+ "cwd": "apps/runtime-demo/3005-runtime-host"
}
},
"dependsOn": [
@@ -45,21 +31,20 @@
]
},
"serve": {
- "executor": "@nx/webpack:dev-server",
+ "executor": "nx:run-commands",
"defaultConfiguration": "production",
"options": {
- "buildTarget": "3005-runtime-host:build",
- "hmr": true,
- "port": 3005,
- "devRemotes": ["3006-runtime-remote"]
+ "command": "pnpm run serve:production",
+ "cwd": "apps/runtime-demo/3005-runtime-host"
},
"configurations": {
"development": {
- "buildTarget": "3005-runtime-host:build:development"
+ "command": "pnpm run serve",
+ "cwd": "apps/runtime-demo/3005-runtime-host"
},
"production": {
- "buildTarget": "3005-runtime-host:build:production",
- "hmr": false
+ "command": "pnpm run serve:production",
+ "cwd": "apps/runtime-demo/3005-runtime-host"
}
},
"dependsOn": [
diff --git a/apps/runtime-demo/3005-runtime-host/src/Root.tsx b/apps/runtime-demo/3005-runtime-host/src/Root.tsx
index ede13ed7b31..9464a759881 100644
--- a/apps/runtime-demo/3005-runtime-host/src/Root.tsx
+++ b/apps/runtime-demo/3005-runtime-host/src/Root.tsx
@@ -5,6 +5,8 @@ import WebpackPng from './webpack.png';
import WebpackSvg from './webpack.svg';
import { WebpackPngRemote, WebpackSvgRemote } from './Remote1';
import Remote2 from './Remote2';
+import WorkerNativeDemo from './components/WorkerNativeDemo';
+import WorkerLoaderDemo from './components/WorkerLoaderDemo';
const Root = () => (
@@ -89,6 +91,40 @@ const Root = () => (
+
+
check workers
+
+
+
+ |
+ Test case |
+ Expected |
+ Actual |
+
+
+
+
+ ✅ |
+ Native new Worker(new URL(...)) |
+
+ Expected worker response: 1
+ |
+
+
+ |
+
+
+ ✅ |
+ worker-loader integration |
+
+ Expected worker response: 1
+ |
+
+
+ |
+
+
+
);
diff --git a/apps/runtime-demo/3005-runtime-host/src/components/WorkerLoaderDemo.tsx b/apps/runtime-demo/3005-runtime-host/src/components/WorkerLoaderDemo.tsx
new file mode 100644
index 00000000000..6206cdf7760
--- /dev/null
+++ b/apps/runtime-demo/3005-runtime-host/src/components/WorkerLoaderDemo.tsx
@@ -0,0 +1,47 @@
+import { useEffect, useState } from 'react';
+
+export function WorkerLoaderDemo() {
+ const [result, setResult] = useState(null);
+ const [error, setError] = useState(null);
+
+ useEffect(() => {
+ try {
+ const worker = new Worker(
+ new URL('../worker/loader-worker.js', import.meta.url),
+ {
+ name: 'mf-loader-worker',
+ },
+ );
+
+ worker.onmessage = (event) => {
+ setResult(event.data ?? null);
+ };
+
+ worker.onerror = (event) => {
+ setError((event as unknown as ErrorEvent).message ?? 'Worker error');
+ };
+
+ worker.postMessage({ value: 'foo' });
+
+ return () => {
+ worker.terminate();
+ };
+ } catch (err) {
+ setError((err as Error).message);
+ }
+
+ return undefined;
+ }, []);
+
+ return (
+
+
Expected worker response: 1
+
+ {result ? JSON.stringify(result, null, 2) : 'n/a'}
+
+ {error ?
Worker error: {error}
: null}
+
+ );
+}
+
+export default WorkerLoaderDemo;
diff --git a/apps/runtime-demo/3005-runtime-host/src/components/WorkerNativeDemo.tsx b/apps/runtime-demo/3005-runtime-host/src/components/WorkerNativeDemo.tsx
new file mode 100644
index 00000000000..22b1d381082
--- /dev/null
+++ b/apps/runtime-demo/3005-runtime-host/src/components/WorkerNativeDemo.tsx
@@ -0,0 +1,46 @@
+import { useEffect, useState } from 'react';
+
+export function WorkerNativeDemo() {
+ const [result, setResult] = useState(null);
+ const [error, setError] = useState(null);
+
+ useEffect(() => {
+ try {
+ const worker = new Worker(
+ new URL('../worker/native-worker.js', import.meta.url),
+ {
+ name: 'mf-native-worker',
+ },
+ );
+
+ worker.onmessage = (event) => {
+ setResult(event.data ?? null);
+ };
+
+ worker.onerror = (event) => {
+ setError((event as unknown as ErrorEvent).message ?? 'Worker error');
+ };
+
+ worker.postMessage({ value: 'foo' });
+
+ return () => {
+ worker.terminate();
+ };
+ } catch (err) {
+ setError((err as Error).message);
+ }
+
+ return undefined;
+ }, []);
+
+ return (
+
+
+ {result ? JSON.stringify(result, null, 2) : 'n/a'}
+
+ {error ?
Worker error: {error}
: null}
+
+ );
+}
+
+export default WorkerNativeDemo;
diff --git a/apps/runtime-demo/3005-runtime-host/src/worker/loader-worker.js b/apps/runtime-demo/3005-runtime-host/src/worker/loader-worker.js
new file mode 100644
index 00000000000..a02258fb43d
--- /dev/null
+++ b/apps/runtime-demo/3005-runtime-host/src/worker/loader-worker.js
@@ -0,0 +1,15 @@
+/* eslint-env worker */
+import { workerMap } from './map.js';
+
+self.onmessage = (event) => {
+ const value = event.data && event.data.value;
+ const federation =
+ typeof __webpack_require__ !== 'undefined'
+ ? __webpack_require__.federation || {}
+ : {};
+ const federationKeys = Object.keys(federation);
+ self.postMessage({
+ answer: workerMap[value] ?? null,
+ federationKeys,
+ });
+};
diff --git a/apps/runtime-demo/3005-runtime-host/src/worker/map.js b/apps/runtime-demo/3005-runtime-host/src/worker/map.js
new file mode 100644
index 00000000000..f9ab0ec2f3c
--- /dev/null
+++ b/apps/runtime-demo/3005-runtime-host/src/worker/map.js
@@ -0,0 +1,4 @@
+export const workerMap = {
+ foo: '1',
+ bar: '2',
+};
diff --git a/apps/runtime-demo/3005-runtime-host/src/worker/native-worker.js b/apps/runtime-demo/3005-runtime-host/src/worker/native-worker.js
new file mode 100644
index 00000000000..a02258fb43d
--- /dev/null
+++ b/apps/runtime-demo/3005-runtime-host/src/worker/native-worker.js
@@ -0,0 +1,15 @@
+/* eslint-env worker */
+import { workerMap } from './map.js';
+
+self.onmessage = (event) => {
+ const value = event.data && event.data.value;
+ const federation =
+ typeof __webpack_require__ !== 'undefined'
+ ? __webpack_require__.federation || {}
+ : {};
+ const federationKeys = Object.keys(federation);
+ self.postMessage({
+ answer: workerMap[value] ?? null,
+ federationKeys,
+ });
+};
diff --git a/apps/runtime-demo/3005-runtime-host/src/worker/worker.js b/apps/runtime-demo/3005-runtime-host/src/worker/worker.js
new file mode 100644
index 00000000000..69a165ec73e
--- /dev/null
+++ b/apps/runtime-demo/3005-runtime-host/src/worker/worker.js
@@ -0,0 +1,9 @@
+/* eslint-env worker */
+import { workerMap } from './map';
+
+self.onmessage = (event) => {
+ const value = event.data && event.data.value;
+ self.postMessage({
+ answer: workerMap[value] ?? null,
+ });
+};
diff --git a/apps/runtime-demo/3005-runtime-host/webpack.config.js b/apps/runtime-demo/3005-runtime-host/webpack.config.js
index 05b99f7e4b7..a562831cc54 100644
--- a/apps/runtime-demo/3005-runtime-host/webpack.config.js
+++ b/apps/runtime-demo/3005-runtime-host/webpack.config.js
@@ -1,108 +1,158 @@
const path = require('path');
-// const { registerPluginTSTranspiler } = require('nx/src/utils/nx-plugin.js');
-// registerPluginTSTranspiler();
+const HtmlWebpackPlugin = require('html-webpack-plugin');
+const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
+const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const {
ModuleFederationPlugin,
} = require('@module-federation/enhanced/webpack');
-const { composePlugins, withNx } = require('@nx/webpack');
-const { withReact } = require('@nx/react');
-module.exports = composePlugins(withNx(), withReact(), (config, context) => {
- config.watchOptions = {
- ignored: ['**/node_modules/**', '**/@mf-types/**', '**/dist/**'],
- };
+const DIST_PATH = path.resolve(__dirname, 'dist');
+const SRC_PATH = path.resolve(__dirname, 'src');
- // const ModuleFederationPlugin = webpack.container.ModuleFederationPlugin;
- config.plugins.push(
- new ModuleFederationPlugin({
- name: 'runtime_host',
- experiments: { asyncStartup: true },
- remotes: {
- // remote2: 'runtime_remote2@http://localhost:3007/remoteEntry.js',
- remote1: 'runtime_remote1@http://127.0.0.1:3006/mf-manifest.json',
- // remote1: `promise new Promise((resolve)=>{
- // const raw = 'runtime_remote1@http://127.0.0.1:3006/remoteEntry.js'
- // const [_, remoteUrlWithVersion] = raw.split('@')
- // const script = document.createElement('script')
- // script.src = remoteUrlWithVersion
- // script.onload = () => {
- // const proxy = {
- // get: (request) => window.runtime_remote1.get(request),
- // init: (arg) => {
- // try {
- // return window.runtime_remote1.init(arg)
- // } catch(e) {
- // console.log('runtime_remote1 container already initialized')
- // }
- // }
- // }
- // resolve(proxy)
- // }
- // document.head.appendChild(script);
- // })`,
- },
- // library: { type: 'var', name: 'runtime_remote' },
- filename: 'remoteEntry.js',
- exposes: {
- './Button': './src/Button.tsx',
- },
- dts: {
- tsConfigPath: path.resolve(__dirname, 'tsconfig.app.json'),
- },
- shareStrategy: 'loaded-first',
- shared: {
- lodash: {
- singleton: true,
- requiredVersion: '^4.0.0',
+module.exports = (_env = {}, argv = {}) => {
+ const mode = argv.mode || process.env.NODE_ENV || 'development';
+ const isDevelopment = mode === 'development';
+ const isWebpackServe = Boolean(
+ argv.env?.WEBPACK_SERVE ?? process.env.WEBPACK_SERVE === 'true',
+ );
+
+ return {
+ mode,
+ devtool: isDevelopment ? 'source-map' : false,
+ entry: path.join(SRC_PATH, 'index.ts'),
+ output: {
+ path: DIST_PATH,
+ filename: isDevelopment ? '[name].js' : '[name].[contenthash].js',
+ publicPath: 'auto',
+ clean: true,
+ scriptType: 'text/javascript',
+ },
+ resolve: {
+ extensions: ['.ts', '.tsx', '.js', '.jsx'],
+ },
+ module: {
+ rules: [
+ {
+ test: /\.[jt]sx?$/,
+ exclude: /node_modules/,
+ use: {
+ loader: require.resolve('swc-loader'),
+ options: {
+ swcrc: false,
+ sourceMaps: isDevelopment,
+ jsc: {
+ parser: {
+ syntax: 'typescript',
+ tsx: true,
+ },
+ transform: {
+ react: {
+ runtime: 'automatic',
+ development: isDevelopment,
+ refresh: isWebpackServe && isDevelopment,
+ },
+ },
+ target: 'es2017',
+ },
+ },
+ },
},
- antd: {
- singleton: true,
- requiredVersion: '^4.0.0',
+ {
+ test: /\.css$/i,
+ use: [
+ MiniCssExtractPlugin.loader,
+ {
+ loader: require.resolve('css-loader'),
+ options: {
+ importLoaders: 0,
+ },
+ },
+ ],
},
- react: {
- singleton: true,
- requiredVersion: '^18.2.0',
+ {
+ test: /\.(png|svg|jpe?g|gif)$/i,
+ type: 'asset/resource',
},
- 'react/': {
- singleton: true,
- requiredVersion: '^18.2.0',
+ ],
+ },
+ plugins: [
+ new HtmlWebpackPlugin({
+ template: path.join(SRC_PATH, 'index.html'),
+ }),
+ new MiniCssExtractPlugin({
+ filename: isDevelopment ? '[name].css' : '[name].[contenthash].css',
+ chunkFilename: isDevelopment ? '[id].css' : '[id].[contenthash].css',
+ }),
+ isWebpackServe && isDevelopment && new ReactRefreshWebpackPlugin(),
+ new ModuleFederationPlugin({
+ name: 'runtime_host',
+ experiments: { asyncStartup: true },
+ remotes: {
+ remote1: 'runtime_remote1@http://127.0.0.1:3006/mf-manifest.json',
},
- 'react-dom': {
- singleton: true,
- requiredVersion: '^18.2.0',
+ filename: 'remoteEntry.js',
+ exposes: {
+ './Button': './src/Button.tsx',
},
- 'react-dom/': {
- singleton: true,
- requiredVersion: '^18.2.0',
+ dts: {
+ tsConfigPath: path.resolve(__dirname, 'tsconfig.app.json'),
},
+ shareStrategy: 'loaded-first',
+ shared: {
+ lodash: {
+ singleton: true,
+ requiredVersion: '^4.0.0',
+ },
+ antd: {
+ singleton: true,
+ requiredVersion: '^4.0.0',
+ },
+ react: {
+ singleton: true,
+ requiredVersion: '^18.2.0',
+ },
+ 'react/': {
+ singleton: true,
+ requiredVersion: '^18.2.0',
+ },
+ 'react-dom': {
+ singleton: true,
+ requiredVersion: '^18.2.0',
+ },
+ 'react-dom/': {
+ singleton: true,
+ requiredVersion: '^18.2.0',
+ },
+ },
+ }),
+ ].filter(Boolean),
+ optimization: {
+ runtimeChunk: false,
+ minimize: false,
+ moduleIds: 'named',
+ },
+ performance: {
+ hints: false,
+ },
+ experiments: {
+ outputModule: false,
+ },
+ watchOptions: {
+ ignored: ['**/node_modules/**', '**/@mf-types/**', '**/dist/**'],
+ },
+ devServer: {
+ host: '127.0.0.1',
+ allowedHosts: 'all',
+ headers: {
+ 'Access-Control-Allow-Origin': '*',
},
- }),
- );
- if (!config.devServer) {
- config.devServer = {};
- }
- config.devServer.host = '127.0.0.1';
- config.plugins.forEach((p) => {
- if (p.constructor.name === 'ModuleFederationPlugin') {
- //Temporary workaround - https://github.com/nrwl/nx/issues/16983
- p._options.library = undefined;
- }
- });
-
- //Temporary workaround - https://github.com/nrwl/nx/issues/16983
- config.experiments = { outputModule: false };
-
- // Update the webpack config as needed here.
- // e.g. `config.plugins.push(new MyPlugin())`
- config.output = {
- ...config.output,
- scriptType: 'text/javascript',
- };
- config.optimization = {
- runtimeChunk: false,
- minimize: false,
- moduleIds: 'named',
+ port: 3005,
+ hot: isWebpackServe && isDevelopment,
+ historyApiFallback: true,
+ static: DIST_PATH,
+ devMiddleware: {
+ writeToDisk: true,
+ },
+ },
};
- // const mf = await withModuleFederation(defaultConfig);
- return config;
-});
+};
diff --git a/apps/runtime-demo/3006-runtime-remote/package.json b/apps/runtime-demo/3006-runtime-remote/package.json
index 405e720e45a..b4c7dd8b0e9 100644
--- a/apps/runtime-demo/3006-runtime-remote/package.json
+++ b/apps/runtime-demo/3006-runtime-remote/package.json
@@ -2,14 +2,23 @@
"name": "runtime-remote1",
"version": "0.0.1",
"private": true,
+ "scripts": {
+ "build": "webpack --config webpack.config.js --mode production",
+ "build:development": "webpack --config webpack.config.js --mode development",
+ "serve": "webpack serve --config webpack.config.js --mode development --host 127.0.0.1 --port 3006 --allowed-hosts all",
+ "serve:production": "webpack serve --config webpack.config.js --mode production --host 127.0.0.1 --port 3006 --allowed-hosts all --no-hot"
+ },
"devDependencies": {
"@module-federation/core": "workspace:*",
"@module-federation/enhanced": "workspace:*",
"@module-federation/typescript": "workspace:*",
"@pmmmwh/react-refresh-webpack-plugin": "0.5.15",
"react-refresh": "0.14.2",
+ "css-loader": "6.11.0",
+ "webpack-dev-server": "5.1.0",
"@types/react": "18.3.11",
- "@types/react-dom": "18.3.0"
+ "@types/react-dom": "18.3.0",
+ "mini-css-extract-plugin": "2.9.2"
},
"dependencies": {
"antd": "4.24.15",
diff --git a/apps/runtime-demo/3006-runtime-remote/project.json b/apps/runtime-demo/3006-runtime-remote/project.json
index 9ca44a376df..29666d4efe1 100644
--- a/apps/runtime-demo/3006-runtime-remote/project.json
+++ b/apps/runtime-demo/3006-runtime-remote/project.json
@@ -6,35 +6,21 @@
"tags": [],
"targets": {
"build": {
- "executor": "@nx/webpack:webpack",
- "outputs": ["{options.outputPath}"],
+ "executor": "nx:run-commands",
+ "outputs": ["{projectRoot}/dist"],
"defaultConfiguration": "production",
"options": {
- "compiler": "babel",
- "outputPath": "apps/runtime-demo/3006-runtime-remote/dist",
- "index": "apps/runtime-demo/3006-runtime-remote/src/index.html",
- "baseHref": "/",
- "main": "apps/runtime-demo/3006-runtime-remote/src/index.tsx",
- "tsConfig": "apps/runtime-demo/3006-runtime-remote/tsconfig.app.json",
- "styles": [],
- "scripts": [],
- "webpackConfig": "apps/runtime-demo/3006-runtime-remote/webpack.config.js",
- "babelUpwardRootMode": true
+ "command": "pnpm run build",
+ "cwd": "apps/runtime-demo/3006-runtime-remote"
},
"configurations": {
"development": {
- "extractLicenses": false,
- "optimization": false,
- "sourceMap": true,
- "vendorChunk": true
+ "command": "pnpm run build:development",
+ "cwd": "apps/runtime-demo/3006-runtime-remote"
},
"production": {
- "optimization": true,
- "outputHashing": "all",
- "sourceMap": false,
- "namedChunks": false,
- "extractLicenses": false,
- "vendorChunk": false
+ "command": "pnpm run build",
+ "cwd": "apps/runtime-demo/3006-runtime-remote"
}
},
"dependsOn": [
@@ -45,12 +31,11 @@
]
},
"serve": {
- "executor": "@nx/webpack:dev-server",
+ "executor": "nx:run-commands",
"defaultConfiguration": "production",
"options": {
- "buildTarget": "3006-runtime-remote:build",
- "hmr": true,
- "port": 3006
+ "command": "pnpm run serve:production",
+ "cwd": "apps/runtime-demo/3006-runtime-remote"
},
"dependsOn": [
{
@@ -60,11 +45,12 @@
],
"configurations": {
"development": {
- "buildTarget": "3006-runtime-remote:build:development"
+ "command": "pnpm run serve",
+ "cwd": "apps/runtime-demo/3006-runtime-remote"
},
"production": {
- "buildTarget": "3006-runtime-remote:build:production",
- "hmr": false
+ "command": "pnpm run serve:production",
+ "cwd": "apps/runtime-demo/3006-runtime-remote"
}
}
},
diff --git a/apps/runtime-demo/3006-runtime-remote/webpack.config.js b/apps/runtime-demo/3006-runtime-remote/webpack.config.js
index 29cde381cb3..6c3cc47b762 100644
--- a/apps/runtime-demo/3006-runtime-remote/webpack.config.js
+++ b/apps/runtime-demo/3006-runtime-remote/webpack.config.js
@@ -1,37 +1,93 @@
-// const { registerPluginTSTranspiler } = require('nx/src/utils/nx-plugin.js');
-// registerPluginTSTranspiler();
-
-const { composePlugins, withNx } = require('@nx/webpack');
-const { withReact } = require('@nx/react');
-
const path = require('path');
-// const { withModuleFederation } = require('@nx/react/module-federation');
+const HtmlWebpackPlugin = require('html-webpack-plugin');
+const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
+const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const {
ModuleFederationPlugin,
} = require('@module-federation/enhanced/webpack');
-const packageJson = require('./package.json');
process.env.FEDERATION_DEBUG = true;
-module.exports = composePlugins(
- withNx(),
- withReact(),
- async (config, context) => {
- config.watchOptions = {
- ignored: ['**/node_modules/**', '**/@mf-types/**'],
- };
- // const ModuleFederationPlugin = webpack.container.ModuleFederationPlugin;
- config.watchOptions = {
- ignored: ['**/dist/**'],
- };
- if (!config.devServer) {
- config.devServer = {};
- }
- config.devServer.host = '127.0.0.1';
- config.plugins.push(
+const DIST_PATH = path.resolve(__dirname, 'dist');
+const SRC_PATH = path.resolve(__dirname, 'src');
+
+module.exports = (_env = {}, argv = {}) => {
+ const mode = argv.mode || process.env.NODE_ENV || 'development';
+ const isDevelopment = mode === 'development';
+ const isWebpackServe = Boolean(
+ argv.env?.WEBPACK_SERVE ?? process.env.WEBPACK_SERVE === 'true',
+ );
+
+ return {
+ mode,
+ devtool: isDevelopment ? 'source-map' : false,
+ entry: path.join(SRC_PATH, 'index.tsx'),
+ output: {
+ path: DIST_PATH,
+ filename: isDevelopment ? '[name].js' : '[name].[contenthash].js',
+ publicPath: 'http://127.0.0.1:3006/',
+ clean: true,
+ scriptType: 'text/javascript',
+ },
+ resolve: {
+ extensions: ['.ts', '.tsx', '.js', '.jsx'],
+ },
+ module: {
+ rules: [
+ {
+ test: /\.[jt]sx?$/,
+ exclude: /node_modules/,
+ use: {
+ loader: require.resolve('swc-loader'),
+ options: {
+ swcrc: false,
+ sourceMaps: isDevelopment,
+ jsc: {
+ parser: {
+ syntax: 'typescript',
+ tsx: true,
+ },
+ transform: {
+ react: {
+ runtime: 'automatic',
+ development: isDevelopment,
+ refresh: isWebpackServe && isDevelopment,
+ },
+ },
+ target: 'es2017',
+ },
+ },
+ },
+ },
+ {
+ test: /\.css$/i,
+ use: [
+ MiniCssExtractPlugin.loader,
+ {
+ loader: require.resolve('css-loader'),
+ options: {
+ importLoaders: 0,
+ },
+ },
+ ],
+ },
+ {
+ test: /\.(png|svg|jpe?g|gif)$/i,
+ type: 'asset/resource',
+ },
+ ],
+ },
+ plugins: [
+ new HtmlWebpackPlugin({
+ template: path.join(SRC_PATH, 'index.html'),
+ }),
+ new MiniCssExtractPlugin({
+ filename: isDevelopment ? '[name].css' : '[name].[contenthash].css',
+ chunkFilename: isDevelopment ? '[id].css' : '[id].[contenthash].css',
+ }),
+ isWebpackServe && isDevelopment && new ReactRefreshWebpackPlugin(),
new ModuleFederationPlugin({
name: 'runtime_remote1',
- // library: { type: 'var', name: 'runtime_remote' },
filename: 'remoteEntry.js',
exposes: {
'./useCustomRemoteHook': './src/components/useCustomRemoteHook',
@@ -72,63 +128,31 @@ module.exports = composePlugins(
tsConfigPath: path.resolve(__dirname, 'tsconfig.app.json'),
},
}),
- );
- // config.externals={
- // 'react':'React',
- // 'react-dom':'ReactDom'
- // }
- config.optimization.runtimeChunk = false;
- config.plugins.forEach((p) => {
- if (p.constructor.name === 'ModuleFederationPlugin') {
- //Temporary workaround - https://github.com/nrwl/nx/issues/16983
- p._options.library = undefined;
- }
- });
-
- //Temporary workaround - https://github.com/nrwl/nx/issues/16983
- config.experiments = { outputModule: false };
-
- // Update the webpack config as needed here.
- // e.g. `config.plugins.push(new MyPlugin())`
- config.output = {
- ...config.output,
- publicPath: 'http://127.0.0.1:3006/',
- scriptType: 'text/javascript',
- };
- config.optimization = {
- // ...config.optimization,
+ ].filter(Boolean),
+ optimization: {
runtimeChunk: false,
minimize: false,
moduleIds: 'named',
- };
- // const mf = await withModuleFederation(defaultConfig);
- return config;
- /** @type {import('webpack').Configuration} */
- // const parsedConfig = mf(config, context);
-
- // parsedConfig.plugins.forEach((p) => {
- // if (p.constructor.name === 'ModuleFederationPlugin') {
- // //Temporary workaround - https://github.com/nrwl/nx/issues/16983
- // p._options.library = undefined;
- // }
- // });
-
- // parsedConfig.devServer = {
- // ...(parsedConfig.devServer || {}),
- // //Needs to resolve static files from the dist folder (@mf-types)
- // static: path.resolve(__dirname, '../../dist/apps/runtime-demo/remote'),
- // };
-
- // //Temporary workaround - https://github.com/nrwl/nx/issues/16983
- // parsedConfig.experiments = { outputModule: false };
-
- // // Update the webpack config as needed here.
- // // e.g. `config.plugins.push(new MyPlugin())`
- // parsedConfig.output = {
- // ...parsedConfig.output,
- // scriptType: 'text/javascript',
- // };
-
- // return parsedConfig;
- },
-);
+ },
+ performance: {
+ hints: false,
+ },
+ experiments: {
+ outputModule: false,
+ },
+ watchOptions: {
+ ignored: ['**/node_modules/**', '**/@mf-types/**', '**/dist/**'],
+ },
+ devServer: {
+ host: '127.0.0.1',
+ allowedHosts: 'all',
+ headers: {
+ 'Access-Control-Allow-Origin': '*',
+ },
+ port: 3006,
+ hot: isWebpackServe && isDevelopment,
+ historyApiFallback: true,
+ static: DIST_PATH,
+ },
+ };
+};
diff --git a/apps/runtime-demo/3007-runtime-remote/package.json b/apps/runtime-demo/3007-runtime-remote/package.json
index 747452c27a7..91a75aed6fc 100644
--- a/apps/runtime-demo/3007-runtime-remote/package.json
+++ b/apps/runtime-demo/3007-runtime-remote/package.json
@@ -2,14 +2,23 @@
"name": "runtime-remote2",
"version": "0.0.0",
"private": true,
+ "scripts": {
+ "build": "webpack --config webpack.config.js --mode production",
+ "build:development": "webpack --config webpack.config.js --mode development",
+ "serve": "webpack serve --config webpack.config.js --mode development --host 127.0.0.1 --port 3007 --allowed-hosts all --no-live-reload",
+ "serve:production": "webpack serve --config webpack.config.js --mode production --host 127.0.0.1 --port 3007 --allowed-hosts all --no-live-reload --no-hot"
+ },
"devDependencies": {
"@module-federation/core": "workspace:*",
"@module-federation/enhanced": "workspace:*",
"@module-federation/typescript": "workspace:*",
"@pmmmwh/react-refresh-webpack-plugin": "0.5.15",
"react-refresh": "0.14.2",
+ "css-loader": "6.11.0",
"@types/react": "18.3.11",
- "@types/react-dom": "18.3.0"
+ "@types/react-dom": "18.3.0",
+ "mini-css-extract-plugin": "2.9.2",
+ "webpack-dev-server": "5.1.0"
},
"dependencies": {
"antd": "4.24.15",
diff --git a/apps/runtime-demo/3007-runtime-remote/project.json b/apps/runtime-demo/3007-runtime-remote/project.json
index 31a6da2c311..c7c2d7263c3 100644
--- a/apps/runtime-demo/3007-runtime-remote/project.json
+++ b/apps/runtime-demo/3007-runtime-remote/project.json
@@ -6,35 +6,21 @@
"tags": [],
"targets": {
"build": {
- "executor": "@nx/webpack:webpack",
- "outputs": ["{options.outputPath}"],
+ "executor": "nx:run-commands",
+ "outputs": ["{projectRoot}/dist"],
"defaultConfiguration": "production",
"options": {
- "compiler": "babel",
- "outputPath": "apps/runtime-demo/3007-runtime-remote/dist",
- "index": "apps/runtime-demo/3007-runtime-remote/src/index.html",
- "baseHref": "/",
- "main": "apps/runtime-demo/3007-runtime-remote/src/index.tsx",
- "tsConfig": "apps/runtime-demo/3007-runtime-remote/tsconfig.app.json",
- "styles": [],
- "scripts": [],
- "webpackConfig": "apps/runtime-demo/3007-runtime-remote/webpack.config.js",
- "babelUpwardRootMode": true
+ "command": "pnpm run build",
+ "cwd": "apps/runtime-demo/3007-runtime-remote"
},
"configurations": {
"development": {
- "extractLicenses": false,
- "optimization": false,
- "sourceMap": true,
- "vendorChunk": true
+ "command": "pnpm run build:development",
+ "cwd": "apps/runtime-demo/3007-runtime-remote"
},
"production": {
- "optimization": true,
- "outputHashing": "all",
- "sourceMap": false,
- "namedChunks": false,
- "extractLicenses": false,
- "vendorChunk": false
+ "command": "pnpm run build",
+ "cwd": "apps/runtime-demo/3007-runtime-remote"
}
},
"dependsOn": [
@@ -45,12 +31,11 @@
]
},
"serve": {
- "executor": "@nx/webpack:dev-server",
+ "executor": "nx:run-commands",
"defaultConfiguration": "production",
"options": {
- "buildTarget": "3007-runtime-remote:build",
- "hmr": true,
- "port": 3007
+ "command": "pnpm run serve:production",
+ "cwd": "apps/runtime-demo/3007-runtime-remote"
},
"dependsOn": [
{
@@ -60,11 +45,12 @@
],
"configurations": {
"development": {
- "buildTarget": "3007-runtime-remote:build:development"
+ "command": "pnpm run serve",
+ "cwd": "apps/runtime-demo/3007-runtime-remote"
},
"production": {
- "buildTarget": "3007-runtime-remote:build:production",
- "hmr": false
+ "command": "pnpm run serve:production",
+ "cwd": "apps/runtime-demo/3007-runtime-remote"
}
}
},
diff --git a/apps/runtime-demo/3007-runtime-remote/webpack.config.js b/apps/runtime-demo/3007-runtime-remote/webpack.config.js
index a1d1739431a..7efb638fbb5 100644
--- a/apps/runtime-demo/3007-runtime-remote/webpack.config.js
+++ b/apps/runtime-demo/3007-runtime-remote/webpack.config.js
@@ -1,26 +1,91 @@
-// const { registerPluginTSTranspiler } = require('nx/src/utils/nx-plugin.js');
-// registerPluginTSTranspiler();
-
-const { composePlugins, withNx } = require('@nx/webpack');
-const { withReact } = require('@nx/react');
-
const path = require('path');
-// const { withModuleFederation } = require('@nx/react/module-federation');
+const HtmlWebpackPlugin = require('html-webpack-plugin');
+const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
+const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const {
ModuleFederationPlugin,
} = require('@module-federation/enhanced/webpack');
-module.exports = composePlugins(
- withNx(),
- withReact(),
- async (config, context) => {
- config.watchOptions = {
- ignored: ['**/node_modules/**', '**/@mf-types/**', '**/dist/**'],
- };
- config.plugins.push(
+const DIST_PATH = path.resolve(__dirname, 'dist');
+const SRC_PATH = path.resolve(__dirname, 'src');
+
+module.exports = (_env = {}, argv = {}) => {
+ const mode = argv.mode || process.env.NODE_ENV || 'development';
+ const isDevelopment = mode === 'development';
+ const isWebpackServe = Boolean(
+ argv.env?.WEBPACK_SERVE ?? process.env.WEBPACK_SERVE === 'true',
+ );
+
+ return {
+ mode,
+ devtool: isDevelopment ? 'source-map' : false,
+ entry: path.join(SRC_PATH, 'index.tsx'),
+ output: {
+ path: DIST_PATH,
+ filename: isDevelopment ? '[name].js' : '[name].[contenthash].js',
+ publicPath: 'http://127.0.0.1:3007/',
+ clean: true,
+ scriptType: 'text/javascript',
+ },
+ resolve: {
+ extensions: ['.ts', '.tsx', '.js', '.jsx'],
+ },
+ module: {
+ rules: [
+ {
+ test: /\.[jt]sx?$/,
+ exclude: /node_modules/,
+ use: {
+ loader: require.resolve('swc-loader'),
+ options: {
+ swcrc: false,
+ sourceMaps: isDevelopment,
+ jsc: {
+ parser: {
+ syntax: 'typescript',
+ tsx: true,
+ },
+ transform: {
+ react: {
+ runtime: 'automatic',
+ development: isDevelopment,
+ refresh: isWebpackServe && isDevelopment,
+ },
+ },
+ target: 'es2017',
+ },
+ },
+ },
+ },
+ {
+ test: /\.css$/i,
+ use: [
+ MiniCssExtractPlugin.loader,
+ {
+ loader: require.resolve('css-loader'),
+ options: {
+ importLoaders: 0,
+ },
+ },
+ ],
+ },
+ {
+ test: /\.(png|svg|jpe?g|gif)$/i,
+ type: 'asset/resource',
+ },
+ ],
+ },
+ plugins: [
+ new HtmlWebpackPlugin({
+ template: path.join(SRC_PATH, 'index.html'),
+ }),
+ new MiniCssExtractPlugin({
+ filename: isDevelopment ? '[name].css' : '[name].[contenthash].css',
+ chunkFilename: isDevelopment ? '[id].css' : '[id].[contenthash].css',
+ }),
+ isWebpackServe && isDevelopment && new ReactRefreshWebpackPlugin(),
new ModuleFederationPlugin({
name: 'runtime_remote2',
- // library: { type: 'var', name: 'runtime_remote' },
filename: 'remoteEntry.js',
exposes: {
'./ButtonOldAnt': './src/components/ButtonOldAnt',
@@ -56,35 +121,32 @@ module.exports = composePlugins(
disableLiveReload: true,
},
}),
- );
- if (!config.devServer) {
- config.devServer = {};
- }
- config.devServer.host = '127.0.0.1';
- config.optimization.runtimeChunk = false;
- config.plugins.forEach((p) => {
- if (p.constructor.name === 'ModuleFederationPlugin') {
- //Temporary workaround - https://github.com/nrwl/nx/issues/16983
- p._options.library = undefined;
- }
- });
-
- //Temporary workaround - https://github.com/nrwl/nx/issues/16983
- config.experiments = { outputModule: false };
-
- // Update the webpack config as needed here.
- // e.g. `config.plugins.push(new MyPlugin())`
- config.output = {
- ...config.output,
- publicPath: 'http://127.0.0.1:3007/',
- scriptType: 'text/javascript',
- };
- config.optimization = {
- ...config.optimization,
+ ].filter(Boolean),
+ optimization: {
runtimeChunk: false,
minimize: false,
- };
- // const mf = await withModuleFederation(defaultConfig);
- return config;
- },
-);
+ moduleIds: 'named',
+ },
+ performance: {
+ hints: false,
+ },
+ experiments: {
+ outputModule: false,
+ },
+ watchOptions: {
+ ignored: ['**/node_modules/**', '**/@mf-types/**', '**/dist/**'],
+ },
+ devServer: {
+ host: '127.0.0.1',
+ allowedHosts: 'all',
+ headers: {
+ 'Access-Control-Allow-Origin': '*',
+ },
+ port: 3007,
+ hot: isWebpackServe && isDevelopment,
+ liveReload: false,
+ historyApiFallback: true,
+ static: DIST_PATH,
+ },
+ };
+};
diff --git a/nx.json b/nx.json
index 4d62dbd7190..ec518e9c5b5 100644
--- a/nx.json
+++ b/nx.json
@@ -50,6 +50,14 @@
"cache": false
}
},
+ "tasksRunnerOptions": {
+ "default": {
+ "runner": "nx/tasks-runners/default",
+ "options": {
+ "useDaemonProcess": false
+ }
+ }
+ },
"namedInputs": {
"default": ["{projectRoot}/**/*", "sharedGlobals"],
"production": [
@@ -66,6 +74,9 @@
],
"sharedGlobals": ["{workspaceRoot}/babel.config.json"]
},
+ "tui": {
+ "enabled": false
+ },
"workspaceLayout": {
"appsDir": "apps",
"libsDir": "packages"
diff --git a/package.json b/package.json
index 5d25b332b76..9b0b5b822b6 100644
--- a/package.json
+++ b/package.json
@@ -25,7 +25,7 @@
"f": "nx format:write",
"enhanced:jest": "pnpm build && cd packages/enhanced && NODE_OPTIONS=--experimental-vm-modules npx jest test/ConfigTestCases.basictest.js test/unit",
"lint": "nx run-many --target=lint",
- "test": "nx run-many --target=test",
+ "test": "NX_TUI=false nx run-many --target=test --projects=tag:type:pkg --skip-nx-cache",
"build": "NX_TUI=false nx run-many --target=build --parallel=5 --projects=tag:type:pkg",
"build:pkg": "NX_TUI=false nx run-many --targets=build --projects=tag:type:pkg --skip-nx-cache",
"test:pkg": "NX_TUI=false nx run-many --targets=test --projects=tag:type:pkg --skip-nx-cache",
@@ -42,7 +42,7 @@
"app:next:build": "nx run-many --target=build --parallel=2 --configuration=production -p 3000-home,3001-shop,3002-checkout",
"app:next:prod": "nx run-many --target=serve --configuration=production -p 3000-home,3001-shop,3002-checkout",
"app:node:dev": "nx run-many --target=serve --parallel=10 --configuration=development -p node-host,node-local-remote,node-remote,node-dynamic-remote-new-version,node-dynamic-remote",
- "app:runtime:dev": "nx run-many --target=serve -p 3005-runtime-host,3006-runtime-remote,3007-runtime-remote",
+ "app:runtime:dev": "NX_DAEMON=false nx run-many --target=serve -p 3005-runtime-host,3006-runtime-remote,3007-runtime-remote",
"app:manifest:dev": "NX_TUI=false nx run-many --target=serve --configuration=development --parallel=100 -p modernjs,manifest-webpack-host,3009-webpack-provider,3010-rspack-provider,3011-rspack-manifest-provider,3012-rspack-js-entry-provider",
"app:manifest:prod": "NX_TUI=false nx run-many --target=serve --configuration=production --parallel=100 -p modernjs,manifest-webpack-host,3009-webpack-provider,3010-rspack-provider,3011-rspack-manifest-provider,3012-rspack-js-entry-provider",
"app:ts:dev": "nx run-many --target=serve -p react_ts_host,react_ts_nested_remote,react_ts_remote",
diff --git a/packages/enhanced/jest.config.ts b/packages/enhanced/jest.config.ts
index e9f78245ad8..a2c1baada04 100644
--- a/packages/enhanced/jest.config.ts
+++ b/packages/enhanced/jest.config.ts
@@ -1,8 +1,7 @@
/* eslint-disable */
-import { readFileSync, rmdirSync, existsSync } from 'fs';
+import { readFileSync, rmSync, existsSync } from 'fs';
import path from 'path';
import os from 'os';
-const rimraf = require('rimraf');
// Reading the SWC compilation config and remove the "exclude"
// for the test files to be compiled by SWC
@@ -10,7 +9,10 @@ const { exclude: _, ...swcJestConfig } = JSON.parse(
readFileSync(`${__dirname}/.swcrc`, 'utf-8'),
);
-rimraf.sync(__dirname + '/test/js');
+const transpiledDir = path.join(__dirname, 'test/js');
+if (existsSync(transpiledDir)) {
+ rmSync(transpiledDir, { recursive: true, force: true });
+}
// disable .swcrc look-up by SWC core because we're passing in swcJestConfig ourselves.
// If we do not disable this, SWC Core will read .swcrc and won't transform our test files due to "exclude"
@@ -23,13 +25,11 @@ if (swcJestConfig.swcrc === undefined) {
// jest needs EsModule Interop to find the default exported setup/teardown functions
// swcJestConfig.module.noInterop = false;
-const testMatch = [];
-
-if (process.env['TEST_TYPE'] === 'unit') {
- testMatch.push('/test/unit/**/*.test.ts');
-} else {
- testMatch.push('/test/*.basictest.js');
-}
+const testMatch = [
+ '/test/*.basictest.js',
+ '/test/unit/**/*.test.ts',
+ '/test/compiler-unit/**/*.test.ts',
+];
export default {
displayName: 'enhanced',
diff --git a/packages/enhanced/jest.embed.ts b/packages/enhanced/jest.embed.ts
index 4e09a7c2e17..7dcf0129a28 100644
--- a/packages/enhanced/jest.embed.ts
+++ b/packages/enhanced/jest.embed.ts
@@ -1,8 +1,7 @@
/* eslint-disable */
-import { readFileSync, rmdirSync, existsSync } from 'fs';
+import { readFileSync, rmSync, existsSync } from 'fs';
import path from 'path';
import os from 'os';
-const rimraf = require('rimraf');
// Reading the SWC compilation config and remove the "exclude"
// for the test files to be compiled by SWC
@@ -10,7 +9,10 @@ const { exclude: _, ...swcJestConfig } = JSON.parse(
readFileSync(`${__dirname}/.swcrc`, 'utf-8'),
);
-rimraf.sync(__dirname + '/test/js');
+const transpiledDir = path.join(__dirname, 'test/js');
+if (existsSync(transpiledDir)) {
+ rmSync(transpiledDir, { recursive: true, force: true });
+}
// disable .swcrc look-up by SWC core because we're passing in swcJestConfig ourselves.
// If we do not disable this, SWC Core will read .swcrc and won't transform our test files due to "exclude"
diff --git a/packages/enhanced/project.json b/packages/enhanced/project.json
index 4730f4dbe0d..d3d73607c2d 100644
--- a/packages/enhanced/project.json
+++ b/packages/enhanced/project.json
@@ -49,11 +49,7 @@
"parallel": false,
"commands": [
{
- "command": "TEST_TYPE=basic node --expose-gc --max-old-space-size=24576 --experimental-vm-modules --trace-deprecation ./node_modules/jest-cli/bin/jest --logHeapUsage --config packages/enhanced/jest.config.ts --silent",
- "forwardAllArgs": false
- },
- {
- "command": "TEST_TYPE=unit node --expose-gc --max-old-space-size=24576 --experimental-vm-modules --trace-deprecation ./node_modules/jest-cli/bin/jest --logHeapUsage --config packages/enhanced/jest.config.ts --silent",
+ "command": "node --expose-gc --max-old-space-size=24576 --experimental-vm-modules --trace-deprecation ./node_modules/jest-cli/bin/jest --logHeapUsage --config packages/enhanced/jest.config.ts --silent",
"forwardAllArgs": false
}
]
diff --git a/packages/enhanced/src/lib/container/runtime/FederationRuntimePlugin.ts b/packages/enhanced/src/lib/container/runtime/FederationRuntimePlugin.ts
index 81b82c64623..d85f34472e5 100644
--- a/packages/enhanced/src/lib/container/runtime/FederationRuntimePlugin.ts
+++ b/packages/enhanced/src/lib/container/runtime/FederationRuntimePlugin.ts
@@ -29,6 +29,10 @@ const ModuleDependency = require(
normalizeWebpackPath('webpack/lib/dependencies/ModuleDependency'),
) as typeof import('webpack/lib/dependencies/ModuleDependency');
+const WorkerDependency = require(
+ normalizeWebpackPath('webpack/lib/dependencies/WorkerDependency'),
+) as typeof import('webpack/lib/dependencies/WorkerDependency');
+
const { RuntimeGlobals, Template } = require(
normalizeWebpackPath('webpack'),
) as typeof import('webpack');
@@ -249,6 +253,83 @@ class FederationRuntimePlugin {
FederationRuntimeDependency,
new ModuleDependency.Template(),
);
+
+ const federationHooks =
+ FederationModulesPlugin.getCompilationHooks(compilation);
+ const processedWorkerBlocks = new WeakSet