diff --git a/.changeset/chatty-hornets-attend.md b/.changeset/chatty-hornets-attend.md
new file mode 100644
index 0000000000..86e34dfeee
--- /dev/null
+++ b/.changeset/chatty-hornets-attend.md
@@ -0,0 +1,6 @@
+---
+'@module-federation/nextjs-mf': minor
+'@module-federation/enhanced': minor
+---
+
+enable chunk hoisting when runtime is embedded
diff --git a/.changeset/kind-nails-roll.md b/.changeset/kind-nails-roll.md
new file mode 100644
index 0000000000..61bec70777
--- /dev/null
+++ b/.changeset/kind-nails-roll.md
@@ -0,0 +1,5 @@
+---
+'@module-federation/enhanced': minor
+---
+
+Embedded runtime and async entry startup
diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml
index 2888d723ef..19226d4369 100644
--- a/.github/workflows/build-and-test.yml
+++ b/.github/workflows/build-and-test.yml
@@ -2,7 +2,7 @@ name: Build Affected Packages
on:
pull_request:
- branches: [main]
+ branches: [main, '**']
push:
branches: [main]
@@ -62,9 +62,14 @@ jobs:
uses: ./.github/workflows/e2e-node.yml
secrets: inherit
- e2e-next:
+ e2e-next-dev:
+ needs: checkout-install
+ uses: ./.github/workflows/e2e-next-dev.yml
+ secrets: inherit
+
+ e2e-next-prod:
needs: checkout-install
- uses: ./.github/workflows/e2e-next.yml
+ uses: ./.github/workflows/e2e-next-prod.yml
secrets: inherit
e2e-modern-ssr:
diff --git a/.github/workflows/e2e-manifest.yml b/.github/workflows/e2e-manifest.yml
index 92313ed498..44a4bc6330 100644
--- a/.github/workflows/e2e-manifest.yml
+++ b/.github/workflows/e2e-manifest.yml
@@ -43,4 +43,4 @@ jobs:
- name: E2E Test for Manifest Demo
if: steps.check-ci.outcome == 'success'
- run: pnpm run app:manifest:dev & echo "done" && npx wait-on tcp:3009 && npx wait-on tcp:3012 && npx nx run-many --target=e2e --projects=manifest-webpack-host --parallel=1 && lsof -ti tcp:3013,3009,3010,3011,3012 | xargs kill
+ run: pnpm run app:manifest:dev & echo "done" && sleep 15 && npx wait-on tcp:3009 && npx wait-on tcp:3012 && npx nx run-many --target=e2e --projects=manifest-webpack-host --parallel=1 && lsof -ti tcp:3013,3009,3010,3011,3012 | xargs kill
diff --git a/.github/workflows/e2e-next-dev.yml b/.github/workflows/e2e-next-dev.yml
new file mode 100644
index 0000000000..ccce8bc377
--- /dev/null
+++ b/.github/workflows/e2e-next-dev.yml
@@ -0,0 +1,52 @@
+name: E2E Test for Next.js Dev
+
+on:
+ workflow_call:
+
+jobs:
+ e2e-next-dev:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout Repository
+ uses: actions/checkout@v3
+ with:
+ fetch-depth: 0
+
+ - name: Install Pnpm
+ run: corepack enable
+
+ - name: Setup Node.js 18
+ uses: actions/setup-node@v3
+ with:
+ node-version: '18'
+ cache: 'pnpm'
+
+ - name: Set Nx SHA
+ uses: nrwl/nx-set-shas@v3
+
+ - name: Set SKIP_DEVTOOLS_POSTINSTALL environment variable
+ run: echo "SKIP_DEVTOOLS_POSTINSTALL=true" >> $GITHUB_ENV
+
+ - name: Install Dependencies
+ run: pnpm install
+
+ - name: Install Cypress
+ run: npx cypress install
+
+ - name: Run Build for All
+ run: npx nx run-many --targets=build --projects=tag:type:pkg
+
+ - name: Run condition check script
+ id: check-ci
+ run: node tools/scripts/ci-is-affected.mjs --appName=3000-home
+
+ - name: E2E Test for Next.js Dev
+ if: steps.check-ci.outcome == 'success'
+ run: |
+ pnpm run app:next:dev > /dev/null 2>&1 &
+ sleep 1 &&
+ npx wait-on tcp:3001 &&
+ npx wait-on tcp:3002 &&
+ npx wait-on tcp:3000 &&
+ npx nx run-many --target=test:e2e --projects=3000-home,3001-shop,3002-checkout --parallel=1 &&
+ lsof -ti tcp:3000,3001,3002 | xargs kill
diff --git a/.github/workflows/e2e-next.yml b/.github/workflows/e2e-next-prod.yml
similarity index 74%
rename from .github/workflows/e2e-next.yml
rename to .github/workflows/e2e-next-prod.yml
index ccd9f10a3f..b43e74b9df 100644
--- a/.github/workflows/e2e-next.yml
+++ b/.github/workflows/e2e-next-prod.yml
@@ -1,11 +1,10 @@
-# .github/workflows/e2e-next-dev.yml
-name: E2E Test for Next.js Dev
+name: E2E Test for Next.js Prod
on:
workflow_call:
jobs:
- e2e-next:
+ e2e-next-prod:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
@@ -52,14 +51,3 @@ jobs:
npx wait-on tcp:3000 &&
npx nx run-many --target=test:e2e --projects=3000-home,3001-shop,3002-checkout --parallel=1 &&
lsof -ti tcp:3000,3001,3002 | xargs kill
-
- - name: E2E Test for Next.js Dev
- if: steps.check-ci.outcome == 'success'
- run: |
- pnpm run app:next:dev > /dev/null 2>&1 &
- sleep 1 &&
- npx wait-on tcp:3001 &&
- npx wait-on tcp:3002 &&
- npx wait-on tcp:3000 &&
- npx nx run-many --target=test:e2e --projects=3000-home,3001-shop,3002-checkout --parallel=1 &&
- lsof -ti tcp:3000,3001,3002 | xargs kill
diff --git a/.github/workflows/e2e-router.yml b/.github/workflows/e2e-router.yml
index 669089e074..5e7a5e2a28 100644
--- a/.github/workflows/e2e-router.yml
+++ b/.github/workflows/e2e-router.yml
@@ -43,4 +43,4 @@ jobs:
- name: E2E Test for Runtime Demo
if: steps.check-ci.outcome == 'success'
- run: npx kill-port --port 2000,2001,2002,2003,2004,2200,2100 && pnpm run app:router:dev & echo "done" && sleep 20 && npx nx run-many --target=test:e2e --projects=router-host-2000 --parallel=1 && lsof -ti tcp:2000,2001,2002,2003,2004,2200,2100 | xargs kill
+ run: npx kill-port --port 2000,2001,2002,2003,2004,2200,2100 && pnpm run app:router:dev & echo "done" && sleep 30 && npx nx run-many --target=test:e2e --projects=router-host-2000 --parallel=1 && lsof -ti tcp:2000,2001,2002,2003,2004,2200,2100 | xargs kill
diff --git a/.gitignore b/.gitignore
index 03dd21f086..516129cc94 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,8 +5,6 @@
/tmp
/out-tsc
/build
-**/@mf-types
-**/@mf-types/**
/docs
/.nx
# dependencies
@@ -51,6 +49,10 @@ migrations.json
packages/**/dist
apps/**/dist
+**/@mf-types
+**/@mf-types/**
+**/cypress/downloads
+
# test cases
!packages/enhanced/test/configCases/**/**/node_modules
packages/enhanced/test/js
@@ -58,10 +60,6 @@ packages/enhanced/test/js
**/.mf
**/.mf/**
-/apps/manifest-demo/**/@mf-types/
-/apps/manifest-demo/webpack-host/@mf-types/
-/apps/manifest-demo/3008-webpack-host/@mf-types/
-
# dts test cases
**/dist-test
**/dist-test/**
diff --git a/apps/3000-home/cypress/e2e/app.cy.ts b/apps/3000-home/cypress/e2e/app.cy.ts
index 92008de438..5dda8279f2 100644
--- a/apps/3000-home/cypress/e2e/app.cy.ts
+++ b/apps/3000-home/cypress/e2e/app.cy.ts
@@ -22,10 +22,12 @@ describe('3000-home/', () => {
it('should display welcome message', () => {
getH1().contains('This is SPA combined');
});
- it('Api endpoint works', () => {
- const urls = ['/api/test'];
- urls.forEach((url) => {
- cy.request(url); // This makes a GET request, not a full page visit
+ });
+
+ describe('API endpoint should return json', () => {
+ it('Query Endpoint', () => {
+ cy.request('/api/test').then((response) => {
+ expect(response.headers['content-type']).to.include('application/json');
});
});
});
diff --git a/apps/3000-home/package.json b/apps/3000-home/package.json
index 76b488a73b..8527afffc3 100644
--- a/apps/3000-home/package.json
+++ b/apps/3000-home/package.json
@@ -24,7 +24,8 @@
},
"devDependencies": {
"@module-federation/nextjs-mf": "workspace:*",
- "@module-federation/utilities": "workspace:*"
+ "@module-federation/utilities": "workspace:*",
+ "@module-federation/runtime": "workspace:*"
},
"scripts": {
"start": "next start",
diff --git a/apps/3000-home/pages/_app.tsx b/apps/3000-home/pages/_app.tsx
index cb9044faa3..533db175ab 100644
--- a/apps/3000-home/pages/_app.tsx
+++ b/apps/3000-home/pages/_app.tsx
@@ -1,5 +1,7 @@
import * as React from 'react';
import { useState } from 'react';
+import { init } from '@module-federation/runtime';
+console.log('logging init', typeof init);
import App from 'next/app';
import { Layout, version, ConfigProvider } from 'antd';
import { StyleProvider } from '@ant-design/cssinjs';
diff --git a/apps/manifest-demo/webpack-host/src/index.ts b/apps/manifest-demo/webpack-host/src/index.ts
deleted file mode 100644
index b93c7a0268..0000000000
--- a/apps/manifest-demo/webpack-host/src/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-import('./bootstrap');
diff --git a/apps/manifest-demo/webpack-host/src/index.tsx b/apps/manifest-demo/webpack-host/src/index.tsx
new file mode 100644
index 0000000000..29dcae9d86
--- /dev/null
+++ b/apps/manifest-demo/webpack-host/src/index.tsx
@@ -0,0 +1,51 @@
+// import('./bootstrap');
+import React, { StrictMode, lazy } from 'react';
+import { init } from '@module-federation/runtime';
+import * as ReactDOM from 'react-dom/client';
+import {
+ createBrowserRouter,
+ createRoutesFromElements,
+ Route,
+ RouterProvider,
+} from 'react-router-dom';
+import App from './App';
+import Root from './Root';
+import customPlugin from './runtimePlugin';
+
+const router = createBrowserRouter([
+ {
+ path: '/',
+ element: ,
+ children: [
+ {
+ path: 'basic',
+ element: ,
+ },
+ {
+ path: 'preload',
+ Component: lazy(() => import('./Preload')),
+ },
+ ],
+ },
+]);
+
+init({
+ name: 'manifest_host',
+ remotes: [
+ {
+ name: 'rspack_provider',
+ alias: 'dynamic-remote',
+ entry: 'http://localhost:3010/mf-manifest.json',
+ },
+ ],
+ plugins: [customPlugin()],
+});
+
+const root = ReactDOM.createRoot(
+ document.getElementById('root') as HTMLElement,
+);
+root.render(
+
+
+ ,
+);
diff --git a/apps/manifest-demo/webpack-host/webpack.config.js b/apps/manifest-demo/webpack-host/webpack.config.js
index d4d83b5fa6..161ed08ff5 100644
--- a/apps/manifest-demo/webpack-host/webpack.config.js
+++ b/apps/manifest-demo/webpack-host/webpack.config.js
@@ -33,6 +33,7 @@ module.exports = composePlugins(withNx(), withReact(), (config, context) => {
'react-dom': {},
'react-dom/': {},
},
+ embedRuntime: true,
runtimePlugins: [path.join(__dirname, './runtimePlugin.ts')],
}),
);
@@ -46,6 +47,7 @@ module.exports = composePlugins(withNx(), withReact(), (config, context) => {
if (config.devServer) {
config.devServer.client.overlay = false;
}
+ config.entry = './src/index.tsx';
//Temporary workaround - https://github.com/nrwl/nx/issues/16983
config.experiments = { outputModule: false };
@@ -54,8 +56,10 @@ module.exports = composePlugins(withNx(), withReact(), (config, context) => {
scriptType: 'text/javascript',
};
config.optimization = {
- runtimeChunk: false,
+ runtimeChunk: 'single',
minimize: false,
+ moduleIds: 'named',
+ chunkIds: 'named',
};
config.output.publicPath = 'http://localhost:3013/';
return config;
diff --git a/apps/modernjs-ssr/dynamic-nested-remote/@mf-types/dynamic_remote/Image.d.ts b/apps/modernjs-ssr/dynamic-nested-remote/@mf-types/dynamic_remote/Image.d.ts
index a63e90edef..d4a0c1006a 100644
--- a/apps/modernjs-ssr/dynamic-nested-remote/@mf-types/dynamic_remote/Image.d.ts
+++ b/apps/modernjs-ssr/dynamic-nested-remote/@mf-types/dynamic_remote/Image.d.ts
@@ -1,2 +1,2 @@
-export * from './compiled-types/Image';
-export { default } from './compiled-types/Image';
\ No newline at end of file
+export * from './compiled-types/src/components/Image';
+export { default } from './compiled-types/src/components/Image';
\ No newline at end of file
diff --git a/apps/modernjs-ssr/dynamic-nested-remote/@mf-types/dynamic_remote/compiled-types/Image.d.ts b/apps/modernjs-ssr/dynamic-nested-remote/@mf-types/dynamic_remote/compiled-types/Image.d.ts
deleted file mode 100644
index e51e05fa50..0000000000
--- a/apps/modernjs-ssr/dynamic-nested-remote/@mf-types/dynamic_remote/compiled-types/Image.d.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-declare const _default: ({ text }: {
- text: string;
-}) => JSX.Element;
-export default _default;
diff --git a/apps/modernjs-ssr/host/cypress/downloads/downloads.html b/apps/modernjs-ssr/host/cypress/downloads/downloads.html
new file mode 100644
index 0000000000..18d3040b46
--- /dev/null
+++ b/apps/modernjs-ssr/host/cypress/downloads/downloads.html
@@ -0,0 +1 @@
+Cr24
diff --git a/apps/runtime-demo/3005-runtime-host/src/Remote1.tsx b/apps/runtime-demo/3005-runtime-host/src/Remote1.tsx
index 5939167be4..ed82d67d21 100644
--- a/apps/runtime-demo/3005-runtime-host/src/Remote1.tsx
+++ b/apps/runtime-demo/3005-runtime-host/src/Remote1.tsx
@@ -1,22 +1,15 @@
import React, { Suspense, lazy } from 'react';
+import { loadRemote } from '@module-federation/runtime';
-export const WebpackSvgRemote = function () {
- const WebpackSvgRemote = lazy(() => import('remote1/WebpackSvg'));
- return (
-
-
-
- );
-};
+export const WebpackSvgRemote = React.lazy(async () => {
+ const WebpackSvgRemote = await loadRemote('remote1/WebpackSvg');
+ return WebpackSvgRemote;
+});
-export const WebpackPngRemote = function () {
- const WebpackPngRemote = lazy(() => import('remote1/WebpackPng'));
- return (
-
-
-
- );
-};
+export const WebpackPngRemote = React.lazy(async () => {
+ const WebpackPngRemote = await loadRemote('remote1/WebpackPng');
+ return WebpackPngRemote;
+});
function Remote1() {
return (
diff --git a/apps/runtime-demo/3005-runtime-host/src/Root.tsx b/apps/runtime-demo/3005-runtime-host/src/Root.tsx
index ede13ed7b3..5de10fb721 100644
--- a/apps/runtime-demo/3005-runtime-host/src/Root.tsx
+++ b/apps/runtime-demo/3005-runtime-host/src/Root.tsx
@@ -1,5 +1,5 @@
import React, { Suspense, lazy } from 'react';
-import TestRemoteHook from './test-remote-hook';
+// import TestRemoteHook from './test-remote-hook';
import LocalBtn from './components/ButtonOldAnt';
import WebpackPng from './webpack.png';
import WebpackSvg from './webpack.svg';
@@ -31,9 +31,7 @@ const Root = () => (
-
-
- |
+ {/* */} |
✅ |
diff --git a/apps/runtime-demo/3005-runtime-host/src/bootstrap.tsx b/apps/runtime-demo/3005-runtime-host/src/bootstrap.tsx
index 3f87d871a1..39d18db75b 100644
--- a/apps/runtime-demo/3005-runtime-host/src/bootstrap.tsx
+++ b/apps/runtime-demo/3005-runtime-host/src/bootstrap.tsx
@@ -14,6 +14,11 @@ init({
alias: 'dynamic-remote',
entry: 'http://127.0.0.1:3007/mf-manifest.json',
},
+ {
+ name: 'runtime_remote1',
+ alias: 'remote1',
+ entry: 'http://127.0.0.1:3006/mf-manifest.json',
+ },
],
});
diff --git a/apps/runtime-demo/3005-runtime-host/src/index.ts b/apps/runtime-demo/3005-runtime-host/src/index.ts
index ca109b9585..51ffb285cf 100644
--- a/apps/runtime-demo/3005-runtime-host/src/index.ts
+++ b/apps/runtime-demo/3005-runtime-host/src/index.ts
@@ -6,4 +6,4 @@ import customPlugin from './runtimePlugin';
registerGlobalPlugins([customPlugin()]);
-import('./bootstrap');
+require('./bootstrap');
diff --git a/apps/runtime-demo/3005-runtime-host/src/test-remote-hook.tsx b/apps/runtime-demo/3005-runtime-host/src/test-remote-hook.tsx
index 47dd0a35bf..30d47f50ec 100644
--- a/apps/runtime-demo/3005-runtime-host/src/test-remote-hook.tsx
+++ b/apps/runtime-demo/3005-runtime-host/src/test-remote-hook.tsx
@@ -1,38 +1,38 @@
-import useCustomRemoteHook from 'remote1/useCustomRemoteHook';
+// import useCustomRemoteHook from 'remote1/useCustomRemoteHook';
-// function RemoteHookText() {
-// // @ts-ignore ignore
-// const RemoteText = React.lazy(async () => {
-// //@ts-ignore
-// const useCustomRemoteHook = await loadRemote('app2/useCustomRemoteHook') as ()=>string;
-// console.log(111,useCustomRemoteHook)
-// const text = useCustomRemoteHook.default();
-// console.log(23424,text)
-// return text;
-// });
-// return (
-//
-// {RemoteText}
-//
-// );
-// }
+// // function RemoteHookText() {
+// // // @ts-ignore ignore
+// // const RemoteText = React.lazy(async () => {
+// // //@ts-ignore
+// // const useCustomRemoteHook = await loadRemote('app2/useCustomRemoteHook') as ()=>string;
+// // console.log(111,useCustomRemoteHook)
+// // const text = useCustomRemoteHook.default();
+// // console.log(23424,text)
+// // return text;
+// // });
+// // return (
+// //
+// // {RemoteText}
+// //
+// // );
+// // }
-const TestRemoteHook = () => {
- const text = useCustomRemoteHook();
+// const TestRemoteHook = () => {
+// const text = useCustomRemoteHook();
- return (
- <>
-
- Page with custom remote hook. You must see text in red box below:
-
- {text}
-
-
- >
- );
-};
+// return (
+// <>
+//
+// Page with custom remote hook. You must see text in red box below:
+//
+// {text}
+//
+//
+// >
+// );
+// };
-export default TestRemoteHook;
+// export default TestRemoteHook;
diff --git a/apps/runtime-demo/3005-runtime-host/webpack.config.js b/apps/runtime-demo/3005-runtime-host/webpack.config.js
index 795fa1994d..e99788d656 100644
--- a/apps/runtime-demo/3005-runtime-host/webpack.config.js
+++ b/apps/runtime-demo/3005-runtime-host/webpack.config.js
@@ -15,30 +15,31 @@ module.exports = composePlugins(withNx(), withReact(), (config, context) => {
config.plugins.push(
new ModuleFederationPlugin({
name: 'runtime_host',
- 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);
- // })`,
- },
+ embedRuntime: 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: {
diff --git a/apps/runtime-demo/3006-runtime-remote/project.json b/apps/runtime-demo/3006-runtime-remote/project.json
index ef779f8c35..4bb502ab58 100644
--- a/apps/runtime-demo/3006-runtime-remote/project.json
+++ b/apps/runtime-demo/3006-runtime-remote/project.json
@@ -13,7 +13,7 @@
"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.ts",
+ "main": "apps/runtime-demo/3006-runtime-remote/src/index.tsx",
"tsConfig": "apps/runtime-demo/3006-runtime-remote/tsconfig.app.json",
"styles": [],
"scripts": [],
diff --git a/apps/runtime-demo/3006-runtime-remote/src/index.ts b/apps/runtime-demo/3006-runtime-remote/src/index.ts
deleted file mode 100644
index b93c7a0268..0000000000
--- a/apps/runtime-demo/3006-runtime-remote/src/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-import('./bootstrap');
diff --git a/apps/runtime-demo/3006-runtime-remote/src/bootstrap.tsx b/apps/runtime-demo/3006-runtime-remote/src/index.tsx
similarity index 100%
rename from apps/runtime-demo/3006-runtime-remote/src/bootstrap.tsx
rename to apps/runtime-demo/3006-runtime-remote/src/index.tsx
diff --git a/apps/runtime-demo/3006-runtime-remote/webpack.config.js b/apps/runtime-demo/3006-runtime-remote/webpack.config.js
index ff856b0437..3409c37fea 100644
--- a/apps/runtime-demo/3006-runtime-remote/webpack.config.js
+++ b/apps/runtime-demo/3006-runtime-remote/webpack.config.js
@@ -93,7 +93,7 @@ module.exports = composePlugins(
scriptType: 'text/javascript',
};
config.optimization = {
- ...config.optimization,
+ // ...config.optimization,
runtimeChunk: false,
minimize: false,
};
diff --git a/apps/runtime-demo/3007-runtime-remote/project.json b/apps/runtime-demo/3007-runtime-remote/project.json
index 27e80e17ae..48d0a429db 100644
--- a/apps/runtime-demo/3007-runtime-remote/project.json
+++ b/apps/runtime-demo/3007-runtime-remote/project.json
@@ -13,7 +13,7 @@
"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.ts",
+ "main": "apps/runtime-demo/3007-runtime-remote/src/index.tsx",
"tsConfig": "apps/runtime-demo/3007-runtime-remote/tsconfig.app.json",
"styles": [],
"scripts": [],
diff --git a/apps/runtime-demo/3007-runtime-remote/src/index.ts b/apps/runtime-demo/3007-runtime-remote/src/index.ts
deleted file mode 100644
index b93c7a0268..0000000000
--- a/apps/runtime-demo/3007-runtime-remote/src/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-import('./bootstrap');
diff --git a/apps/runtime-demo/3007-runtime-remote/src/bootstrap.tsx b/apps/runtime-demo/3007-runtime-remote/src/index.tsx
similarity index 100%
rename from apps/runtime-demo/3007-runtime-remote/src/bootstrap.tsx
rename to apps/runtime-demo/3007-runtime-remote/src/index.tsx
diff --git a/package.json b/package.json
index 07499f7b67..c1e74fedc6 100644
--- a/package.json
+++ b/package.json
@@ -7,10 +7,10 @@
},
"packageManager": "pnpm@8.11.0",
"private": true,
- "description": "Module Federation helper for NextJS",
+ "description": "Module Federation v2",
"main": "src/index.js",
"types": "src/index.d.ts",
- "repository": "https://github.com/module-federation/nextjs-mf",
+ "repository": "https://github.com/module-federation/core",
"author": "Zack Jackson ",
"contributors": [
"Pavel Chertorogov, nodkz (www.ps.kz)",
@@ -38,7 +38,7 @@
"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:router:dev": "kill-port 2000 2200 2100 2001 2002 2003 && nx run-many --target=serve --parallel=10 --projects='router-*'",
+ "app:router:dev": "nx run-many --target=serve --parallel=10 --projects='router-*'",
"app:manifest:dev": "kill-port 3009 3010 3011 3012 3013 && nx run-many --target=serve --parallel=100 -p 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",
"app:modern:dev": "nx run-many --target=serve --parallel=10 --configuration=development -p modernjs-ssr-dynamic-nested-remote,modernjs-ssr-dynamic-remote,modernjs-ssr-dynamic-remote-new-version,modernjs-ssr-host,modernjs-ssr-nested-remote,modernjs-ssr-remote,modernjs-ssr-remote-new-version",
diff --git a/packages/enhanced/package.json b/packages/enhanced/package.json
index 51c492f3f0..e1505f2c10 100644
--- a/packages/enhanced/package.json
+++ b/packages/enhanced/package.json
@@ -68,7 +68,8 @@
},
"devDependencies": {
"@module-federation/webpack-bundler-runtime": "workspace:*",
- "@types/btoa": "^1.2.5"
+ "@types/btoa": "^1.2.5",
+ "@types/enhanced-resolve": "^5.0.0"
},
"dependencies": {
"@module-federation/sdk": "workspace:*",
diff --git a/packages/enhanced/src/lib/container/HoistContainerReferencesPlugin.ts b/packages/enhanced/src/lib/container/HoistContainerReferencesPlugin.ts
index 4ee2aa7834..a3f9178d01 100644
--- a/packages/enhanced/src/lib/container/HoistContainerReferencesPlugin.ts
+++ b/packages/enhanced/src/lib/container/HoistContainerReferencesPlugin.ts
@@ -3,30 +3,114 @@ import type {
Compilation,
Chunk,
WebpackPluginInstance,
+ Module,
+ NormalModule as NormalModuleType,
} from 'webpack';
+import { normalizeWebpackPath } from '@module-federation/sdk/normalize-webpack-path';
+import type { RuntimeSpec } from 'webpack/lib/util/runtime';
+import type ExportsInfo from 'webpack/lib/ExportsInfo';
import ContainerEntryModule from './ContainerEntryModule';
+const { NormalModule, AsyncDependenciesBlock } = require(
+ normalizeWebpackPath('webpack'),
+) as typeof import('webpack');
+const ConcatenatedModule = require(
+ normalizeWebpackPath('webpack/lib/optimize/ConcatenatedModule'),
+) as typeof import('webpack/lib/optimize/ConcatenatedModule');
+
+const PLUGIN_NAME = 'HoistContainerReferences';
+
/**
* This class is used to hoist container references in the code.
* @constructor
*/
export class HoistContainerReferences implements WebpackPluginInstance {
- private containerName?: string | undefined;
+ private readonly containerName: string;
+ private readonly entryFilePath?: string;
+ private readonly bundlerRuntimeDep?: string;
+ private readonly explanation: string;
- constructor(name?: string | undefined) {
- this.containerName = name;
+ constructor(
+ name?: string,
+ entryFilePath?: string,
+ bundlerRuntimeDep?: string,
+ ) {
+ this.containerName = name || 'no known chunk name';
+ this.entryFilePath = entryFilePath;
+ this.bundlerRuntimeDep = bundlerRuntimeDep;
+ this.explanation =
+ 'Bundler runtime path module is required for proper functioning';
}
apply(compiler: Compiler): void {
compiler.hooks.thisCompilation.tap(
- 'HoistContainerReferences',
+ PLUGIN_NAME,
(compilation: Compilation) => {
- compilation.hooks.afterOptimizeChunks.tap(
- 'HoistContainerReferences',
+ const logger = compilation.getLogger(PLUGIN_NAME);
+ const { chunkGraph, moduleGraph } = compilation;
+
+ // Hook into the optimizeChunks phase
+ compilation.hooks.optimizeChunks.tap(
+ {
+ name: PLUGIN_NAME,
+ // advanced stage is where SplitChunksPlugin runs.
+ stage: 11, // advanced + 1
+ },
(chunks: Iterable) => {
- for (const chunk of chunks) {
- if (this.chunkContainsContainerEntryModule(chunk, compilation)) {
- this.hoistModulesInChunk(chunk, compilation);
+ const runtimeChunks = this.getRuntimeChunks(compilation);
+ this.hoistModulesInChunks(
+ compilation,
+ runtimeChunks,
+ chunks,
+ logger,
+ );
+ },
+ );
+
+ // Hook into the optimizeDependencies phase
+ compilation.hooks.optimizeDependencies.tap(
+ {
+ name: PLUGIN_NAME,
+ // basic optimization stage - it runs first
+ stage: -10,
+ },
+ (modules: Iterable) => {
+ if (this.entryFilePath) {
+ let runtime: RuntimeSpec | undefined;
+ for (const [name, { options }] of compilation.entries) {
+ runtime = compiler.webpack.util.runtime.mergeRuntimeOwned(
+ runtime,
+ compiler.webpack.util.runtime.getEntryRuntime(
+ compilation,
+ name,
+ options,
+ ),
+ );
+ }
+ for (const module of modules) {
+ if (
+ module instanceof NormalModule &&
+ module.resource === this.bundlerRuntimeDep
+ ) {
+ const allRefs = this.getAllReferencedModules(
+ compilation,
+ module,
+ 'initial',
+ );
+ for (const module of allRefs) {
+ const exportsInfo: ExportsInfo =
+ moduleGraph.getExportsInfo(module);
+ // Since i dont use the import federation var, tree shake will eliminate it.
+ // also because currently the runtime is copied into all runtime chunks
+ // some might not have the runtime import in the tree to begin with
+ exportsInfo.setUsedInUnknownWay(runtime);
+ moduleGraph.addExtraReason(module, this.explanation);
+ if (module.factoryMeta === undefined) {
+ module.factoryMeta = {};
+ }
+ module.factoryMeta.sideEffectFree = false;
+ }
+ }
}
}
},
@@ -35,46 +119,172 @@ export class HoistContainerReferences implements WebpackPluginInstance {
);
}
- private chunkContainsContainerEntryModule(
- chunk: Chunk,
+ // Helper method to collect all referenced modules recursively
+ private getAllReferencedModules(
compilation: Compilation,
- ): boolean {
- for (const module of compilation.chunkGraph.getChunkModulesIterable(
- chunk,
- )) {
- if (module instanceof ContainerEntryModule) {
- return true;
+ module: Module,
+ type?: 'all' | 'initial',
+ ): Set {
+ const collectedModules = new Set([module]);
+ const stack = [module];
+
+ while (stack.length > 0) {
+ const currentModule = stack.pop();
+ if (!currentModule) continue;
+ const mgm = compilation.moduleGraph._getModuleGraphModule(currentModule);
+ if (mgm && mgm.outgoingConnections) {
+ for (const connection of mgm.outgoingConnections) {
+ if (type === 'initial') {
+ const parentBlock = compilation.moduleGraph.getParentBlock(
+ connection.dependency,
+ );
+ if (parentBlock instanceof AsyncDependenciesBlock) {
+ continue;
+ }
+ }
+ if (connection.module && !collectedModules.has(connection.module)) {
+ collectedModules.add(connection.module);
+ stack.push(connection.module);
+ }
+ }
+ }
+ }
+
+ return collectedModules;
+ }
+
+ // Helper method to find a specific module in a chunk
+ private findModule(
+ compilation: Compilation,
+ chunk: Chunk,
+ entryFilePath: string,
+ ): Module | null {
+ const { chunkGraph } = compilation;
+ let module: Module | null = null;
+ for (const mod of chunkGraph.getChunkEntryModulesIterable(chunk)) {
+ if (mod instanceof NormalModule && mod.resource === entryFilePath) {
+ module = mod;
+ break;
+ }
+
+ if (mod instanceof ConcatenatedModule) {
+ for (const m of mod.modules) {
+ if (m instanceof NormalModule && m.resource === entryFilePath) {
+ module = mod;
+ break;
+ }
+ }
}
}
- return false;
+ return module;
}
- private hoistModulesInChunk(chunk: Chunk, compilation: Compilation): void {
- const chunkGraph = compilation.chunkGraph;
- const runtimeChunks = this.getRuntimeChunks(chunk, compilation);
-
- for (const module of chunkGraph.getChunkModulesIterable(chunk)) {
- if (
- !chunk.hasRuntime() &&
- (!this.containerName ||
- (chunk.name !== this.containerName &&
- chunk.name !== this.containerName + '_partial'))
- ) {
- chunkGraph.disconnectChunkAndModule(chunk, module);
+ // Method to hoist modules in chunks
+ private hoistModulesInChunks(
+ compilation: Compilation,
+ runtimeChunks: Set,
+ chunks: Iterable,
+ logger: ReturnType,
+ ): void {
+ const { chunkGraph, moduleGraph } = compilation;
+ // when runtimeChunk: single is set - ContainerPlugin will create a "partial" chunk we can use to
+ // move modules into the runtime chunk
+ const partialChunk = this.containerName
+ ? compilation.namedChunks.get(this.containerName)
+ : undefined;
+ let runtimeModule;
+ if (!partialChunk) {
+ for (const chunk of chunks) {
+ if (
+ chunkGraph.getNumberOfEntryModules(chunk) > 0 &&
+ this.entryFilePath
+ ) {
+ runtimeModule = this.findModule(
+ compilation,
+ chunk,
+ this.entryFilePath,
+ );
+
+ if (runtimeModule) break;
+ }
}
+ } else {
+ const entryModules =
+ chunkGraph.getChunkEntryModulesIterable(partialChunk);
+ runtimeModule = entryModules
+ ? Array.from(entryModules).find(
+ (module) => module instanceof ContainerEntryModule,
+ )
+ : undefined;
+ }
- for (const runtimeChunk of runtimeChunks) {
- if (chunkGraph.isModuleInChunk(module, runtimeChunk)) continue;
- chunkGraph.connectChunkAndModule(runtimeChunk, module);
+ if (!runtimeModule) {
+ logger.error(
+ '[Federation HoistContainerReferences] unable to find runtime module:',
+ this.entryFilePath,
+ );
+ return;
+ }
+
+ const allReferencedModules = this.getAllReferencedModules(
+ compilation,
+ runtimeModule,
+ 'initial',
+ );
+
+ // If single runtime chunk, copy the remoteEntry into the runtime chunk to allow for embed container
+ // this will not work well if there multiple runtime chunks from entrypoints (like next)
+ // need better solution to multi runtime chunk hoisting
+ if (partialChunk) {
+ for (const module of chunkGraph.getChunkModulesIterable(partialChunk)) {
+ allReferencedModules.add(module);
}
}
+
+ for (const chunk of runtimeChunks) {
+ for (const module of allReferencedModules) {
+ if (!chunkGraph.isModuleInChunk(module, chunk)) {
+ chunkGraph.connectChunkAndModule(chunk, module);
+ }
+ }
+ }
+
+ // Set used exports for the runtime module
+ this.cleanUpChunks(compilation, allReferencedModules);
}
- private getRuntimeChunks(chunk: Chunk, compilation: Compilation): Chunk[] {
- const runtimeChunks = [];
- for (const c of compilation.chunks) {
- if (c.hasRuntime() && c !== chunk) {
- runtimeChunks.push(c);
+ // Method to clean up chunks by disconnecting unused modules
+ private cleanUpChunks(compilation: Compilation, modules: Set): void {
+ const { chunkGraph } = compilation;
+ for (const module of modules) {
+ for (const chunk of chunkGraph.getModuleChunks(module)) {
+ if (!chunk.hasRuntime()) {
+ chunkGraph.disconnectChunkAndModule(chunk, module);
+ if (
+ chunkGraph.getNumberOfChunkModules(chunk) === 0 &&
+ chunkGraph.getNumberOfEntryModules(chunk) === 0
+ ) {
+ chunkGraph.disconnectChunk(chunk);
+ compilation.chunks.delete(chunk);
+ if (chunk.name) {
+ compilation.namedChunks.delete(chunk.name);
+ }
+ }
+ }
+ }
+ }
+ modules.clear();
+ }
+
+ // Helper method to get runtime chunks from the compilation
+ private getRuntimeChunks(compilation: Compilation): Set {
+ const runtimeChunks = new Set();
+ const entries = compilation.entrypoints;
+
+ for (const entrypoint of entries.values()) {
+ const runtimeChunk = entrypoint.getRuntimeChunk();
+ if (runtimeChunk) {
+ runtimeChunks.add(runtimeChunk);
}
}
return runtimeChunks;
diff --git a/packages/enhanced/src/lib/container/ModuleFederationPlugin.ts b/packages/enhanced/src/lib/container/ModuleFederationPlugin.ts
index 2505833d25..a143f3aef2 100644
--- a/packages/enhanced/src/lib/container/ModuleFederationPlugin.ts
+++ b/packages/enhanced/src/lib/container/ModuleFederationPlugin.ts
@@ -19,6 +19,7 @@ import ContainerReferencePlugin from './ContainerReferencePlugin';
import FederationRuntimePlugin from './runtime/FederationRuntimePlugin';
import { RemoteEntryPlugin } from './runtime/RemoteEntryPlugin';
import { ExternalsType } from 'webpack/declarations/WebpackOptions';
+import StartupChunkDependenciesPlugin from '../startup/MfStartupChunkDependenciesPlugin';
const isValidExternalsType = require(
normalizeWebpackPath(
@@ -63,10 +64,18 @@ class ModuleFederationPlugin implements WebpackPluginInstance {
compiler,
);
}
+ if (options.embedRuntime) {
+ new StartupChunkDependenciesPlugin({
+ asyncChunkLoading: true,
+ }).apply(compiler);
+ }
+
if (options.dts !== false) {
new DtsPlugin(options).apply(compiler);
}
+
new FederationRuntimePlugin(options).apply(compiler);
+
const library = options.library || { type: 'var', name: options.name };
const remoteType =
options.remoteType ||
diff --git a/packages/enhanced/src/lib/container/RemoteRuntimeModule.ts b/packages/enhanced/src/lib/container/RemoteRuntimeModule.ts
index 635c845c83..14005344c1 100644
--- a/packages/enhanced/src/lib/container/RemoteRuntimeModule.ts
+++ b/packages/enhanced/src/lib/container/RemoteRuntimeModule.ts
@@ -33,6 +33,17 @@ class RemoteRuntimeModule extends RuntimeModule {
const chunkToRemotesMapping: Record = {};
const idToExternalAndNameMapping: Record = {};
const idToRemoteMap: RemotesOptions['idToRemoteMap'] = {};
+ // let chunkReferences: Set = new Set();
+
+ // if (this.chunk && chunkGraph) {
+ // const requirements = chunkGraph.getTreeRuntimeRequirements(this.chunk);
+ // if (requirements.has('federation-entry-startup')) {
+ // chunkReferences = this.chunk.getAllReferencedChunks();
+ // } else {
+ // // remote entry doesnt need federation startup, can have async chunk map only
+ // chunkReferences = this.chunk.getAllAsyncChunks();
+ // }
+ // }
const allChunks = [
...Array.from(this.chunk?.getAllReferencedChunks() || []),
diff --git a/packages/enhanced/src/lib/container/runtime/ChildCompilationRuntimePlugin.ts b/packages/enhanced/src/lib/container/runtime/ChildCompilationRuntimePlugin.ts
new file mode 100644
index 0000000000..215ea9d9ef
--- /dev/null
+++ b/packages/enhanced/src/lib/container/runtime/ChildCompilationRuntimePlugin.ts
@@ -0,0 +1,310 @@
+// This stores the previous child compilation based solution
+// it is not currently used
+
+import { normalizeWebpackPath } from '@module-federation/sdk/normalize-webpack-path';
+import type { Compiler, Compilation, Chunk, Module, ChunkGraph } from 'webpack';
+import { getFederationGlobalScope } from './utils';
+import fs from 'fs';
+import path from 'path';
+import { ConcatSource } from 'webpack-sources';
+import { transformSync } from '@swc/core';
+
+const { RuntimeModule, Template, RuntimeGlobals } = require(
+ normalizeWebpackPath('webpack'),
+) as typeof import('webpack');
+
+const onceForCompilationMap = new WeakMap();
+const federationGlobal = getFederationGlobalScope(RuntimeGlobals);
+
+class RuntimeModuleChunkPlugin {
+ apply(compiler: Compiler): void {
+ compiler.hooks.thisCompilation.tap(
+ 'ModuleChunkFormatPlugin',
+ (compilation: Compilation) => {
+ compilation.hooks.optimizeModuleIds.tap(
+ 'ModuleChunkFormatPlugin',
+ (modules: Iterable) => {
+ for (const module of modules) {
+ const moduleId = compilation.chunkGraph.getModuleId(module);
+ if (typeof moduleId === 'string') {
+ compilation.chunkGraph.setModuleId(
+ module,
+ `(embed)${moduleId}`,
+ );
+ } else {
+ compilation.chunkGraph.setModuleId(module, `1000${moduleId}`);
+ }
+ }
+ },
+ );
+
+ const hooks =
+ compiler.webpack.javascript.JavascriptModulesPlugin.getCompilationHooks(
+ compilation,
+ );
+
+ hooks.renderChunk.tap(
+ 'ModuleChunkFormatPlugin',
+ (
+ modules: any,
+ renderContext: { chunk: Chunk; chunkGraph: ChunkGraph },
+ ) => {
+ const { chunk, chunkGraph } = renderContext;
+
+ const source = new ConcatSource();
+ source.add('var federation = ');
+ source.add(modules);
+ source.add('\n');
+ const entries = Array.from(
+ chunkGraph.getChunkEntryModulesWithChunkGroupIterable(chunk),
+ );
+ for (let i = 0; i < entries.length; i++) {
+ const [module, entrypoint] = entries[i];
+ const final = i + 1 === entries.length;
+ const moduleId = chunkGraph.getModuleId(module);
+ source.add('\n');
+ if (final) {
+ source.add('for (var mod in federation) {\n');
+ source.add(
+ `${RuntimeGlobals.moduleFactories}[mod] = federation[mod];\n`,
+ );
+ source.add('}\n');
+ source.add('federation = ');
+ }
+ source.add(
+ `${RuntimeGlobals.require}(${typeof moduleId === 'number' ? moduleId : JSON.stringify(moduleId)});\n`,
+ );
+ }
+ return source;
+ },
+ );
+ },
+ );
+ }
+}
+
+class CustomRuntimePlugin {
+ private entryModule?: string | number;
+ private bundlerRuntimePath: string;
+ private tempDir: string;
+
+ constructor(path: string, tempDir: string) {
+ this.bundlerRuntimePath = path.replace('cjs', 'esm');
+ this.tempDir = tempDir;
+ }
+
+ apply(compiler: Compiler): void {
+ compiler.hooks.make.tapAsync(
+ 'CustomRuntimePlugin',
+ (compilation: Compilation, callback: (err?: Error) => void) => {
+ if (onceForCompilationMap.has(compilation)) return callback();
+ onceForCompilationMap.set(compilation, null);
+ const target = compilation.options.target || 'default';
+ const outputPath = path.join(
+ this.tempDir,
+ `${target}-custom-runtime-bundle.js`,
+ );
+
+ if (fs.existsSync(outputPath)) {
+ const source = fs.readFileSync(outputPath, 'utf-8');
+ onceForCompilationMap.set(compiler, source);
+ return callback();
+ }
+
+ if (onceForCompilationMap.has(compiler)) return callback();
+ onceForCompilationMap.set(compiler, null);
+
+ const childCompiler = compilation.createChildCompiler(
+ 'EmbedFederationRuntimeCompiler',
+ {
+ filename: '[name].js',
+ library: {
+ type: 'var',
+ name: 'federation',
+ export: 'default',
+ },
+ },
+ [
+ new compiler.webpack.EntryPlugin(
+ compiler.context,
+ this.bundlerRuntimePath,
+ {
+ name: 'custom-runtime-bundle',
+ runtime: 'other',
+ },
+ ),
+ new compiler.webpack.library.EnableLibraryPlugin('var'),
+ new RuntimeModuleChunkPlugin(),
+ ],
+ );
+
+ childCompiler.context = compiler.context;
+ childCompiler.options.devtool = undefined;
+ childCompiler.options.optimization.splitChunks = false;
+ childCompiler.options.optimization.removeAvailableModules = true;
+ console.log('Creating child compiler for', this.bundlerRuntimePath);
+
+ childCompiler.hooks.thisCompilation.tap(
+ this.constructor.name,
+ (childCompilation) => {
+ childCompilation.hooks.processAssets.tap(
+ this.constructor.name,
+ () => {
+ const source =
+ childCompilation.assets['custom-runtime-bundle.js'] &&
+ (childCompilation.assets[
+ 'custom-runtime-bundle.js'
+ ].source() as string);
+
+ const entry = childCompilation.entrypoints.get(
+ 'custom-runtime-bundle',
+ );
+ const entryChunk = entry?.getEntrypointChunk();
+
+ if (entryChunk) {
+ const entryModule = Array.from(
+ childCompilation.chunkGraph.getChunkEntryModulesIterable(
+ entryChunk,
+ ),
+ )[0];
+ this.entryModule =
+ childCompilation.chunkGraph.getModuleId(entryModule);
+ }
+
+ onceForCompilationMap.set(compilation, source);
+ onceForCompilationMap.set(compiler, source);
+ fs.writeFileSync(outputPath, source);
+ console.log('got compilation asset');
+ childCompilation.chunks.forEach((chunk) => {
+ chunk.files.forEach((file) => {
+ childCompilation.deleteAsset(file);
+ });
+ });
+ },
+ );
+ },
+ );
+ childCompiler.runAsChild(
+ (
+ err?: Error | null,
+ entries?: Chunk[],
+ childCompilation?: Compilation,
+ ) => {
+ if (err) {
+ return callback(err);
+ }
+
+ if (!childCompilation) {
+ console.warn(
+ 'Embed Federation Runtime: Child compilation is undefined',
+ );
+ return callback();
+ }
+
+ if (childCompilation.errors.length) {
+ return callback(childCompilation.errors[0]);
+ }
+
+ console.log('Code built successfully');
+
+ callback();
+ },
+ );
+ },
+ );
+
+ compiler.hooks.thisCompilation.tap(
+ 'CustomRuntimePlugin',
+ (compilation: Compilation) => {
+ const handler = (chunk: Chunk, runtimeRequirements: Set) => {
+ if (chunk.id === 'build time chunk') {
+ return;
+ }
+ if (runtimeRequirements.has('embeddedFederationRuntime')) return;
+ if (!runtimeRequirements.has(federationGlobal)) {
+ return;
+ }
+ const bundledCode = onceForCompilationMap.get(compilation);
+ if (!bundledCode) return;
+ runtimeRequirements.add('embeddedFederationRuntime');
+ const runtimeModule = new CustomRuntimeModule(
+ bundledCode,
+ this.entryModule,
+ );
+
+ compilation.addRuntimeModule(chunk, runtimeModule);
+ console.log(`Custom runtime module added to chunk: ${chunk.name}`);
+ };
+ compilation.hooks.runtimeRequirementInTree
+ .for(federationGlobal)
+ .tap('CustomRuntimePlugin', handler);
+ },
+ );
+ }
+}
+
+class CustomRuntimeModule extends RuntimeModule {
+ private bundledCode: string | null = null;
+ private entryModuleId: string | number | undefined;
+
+ constructor(
+ private readonly entryPath: string,
+ entryModuleId: string | number | undefined,
+ ) {
+ super('CustomRuntimeModule', RuntimeModule.STAGE_BASIC);
+ this.entryPath = entryPath;
+ this.entryModuleId = entryModuleId;
+ }
+
+ override identifier() {
+ return 'webpack/runtime/embed/federation';
+ }
+
+ override generate(): string {
+ const runtimeModule = this.entryPath;
+ const { code: transformedCode } = transformSync(
+ this.entryPath.replace('var federation;', 'var federation = '),
+ {
+ jsc: {
+ parser: {
+ syntax: 'ecmascript',
+ jsx: false,
+ },
+ target: 'es2022',
+ minify: {
+ compress: {
+ unused: true,
+ dead_code: true,
+ drop_debugger: true,
+ },
+ mangle: false,
+ format: {
+ comments: false,
+ },
+ },
+ },
+ },
+ );
+
+ return Template.asString([
+ runtimeModule,
+ transformedCode,
+ `for (var mod in federation) {
+ ${Template.indent(`${RuntimeGlobals.moduleFactories}[mod] = federation[mod];`)}
+ }`,
+ `federation = ${RuntimeGlobals.require}(${JSON.stringify(this.entryModuleId)});`,
+ `federation = ${RuntimeGlobals.compatGetDefaultExport}(federation)();`,
+ `var prevFederation = ${federationGlobal}`,
+ `${federationGlobal} = {}`,
+ `for (var key in federation) {`,
+ Template.indent(`${federationGlobal}[key] = federation[key];`),
+ `}`,
+ `for (var key in prevFederation) {`,
+ Template.indent(`${federationGlobal}[key] = prevFederation[key];`),
+ `}`,
+ 'federation = undefined;',
+ ]);
+ }
+}
+
+export { CustomRuntimePlugin, CustomRuntimeModule, RuntimeModuleChunkPlugin };
diff --git a/packages/enhanced/src/lib/container/runtime/EmbedFederationRuntimeModule.ts b/packages/enhanced/src/lib/container/runtime/EmbedFederationRuntimeModule.ts
new file mode 100644
index 0000000000..8f5d83b1f0
--- /dev/null
+++ b/packages/enhanced/src/lib/container/runtime/EmbedFederationRuntimeModule.ts
@@ -0,0 +1,96 @@
+import { normalizeWebpackPath } from '@module-federation/sdk/normalize-webpack-path';
+import { getFederationGlobalScope } from './utils';
+import type { Chunk, Module } from 'webpack';
+
+const { RuntimeModule, NormalModule, Template, RuntimeGlobals } = require(
+ normalizeWebpackPath('webpack'),
+) as typeof import('webpack');
+const ConcatenatedModule = require(
+ normalizeWebpackPath('webpack/lib/optimize/ConcatenatedModule'),
+) as typeof import('webpack/lib/optimize/ConcatenatedModule');
+
+const federationGlobal = getFederationGlobalScope(RuntimeGlobals);
+
+class EmbedFederationRuntimeModule extends RuntimeModule {
+ private bundlerRuntimePath: string;
+
+ constructor(bundlerRuntimePath: string) {
+ super('EmbedFederationRuntimeModule', RuntimeModule.STAGE_ATTACH);
+ this.bundlerRuntimePath = bundlerRuntimePath;
+ }
+
+ override identifier() {
+ return 'webpack/runtime/embed/federation';
+ }
+
+ override generate(): string | null {
+ const { compilation, chunk, chunkGraph, bundlerRuntimePath } = this;
+ if (!chunk || !chunkGraph || !compilation) {
+ return null;
+ }
+
+ const found = this.findModule(chunk, bundlerRuntimePath);
+ if (!found) return null;
+
+ const initRuntimeModuleGetter = compilation.runtimeTemplate.moduleRaw({
+ module: found,
+ chunkGraph,
+ request: this.bundlerRuntimePath,
+ weak: false,
+ runtimeRequirements: new Set(),
+ });
+
+ const exportExpr = compilation.runtimeTemplate.exportFromImport({
+ moduleGraph: compilation.moduleGraph,
+ module: found,
+ request: this.bundlerRuntimePath,
+ exportName: ['default'],
+ originModule: found,
+ asiSafe: true,
+ isCall: false,
+ callContext: false,
+ defaultInterop: true,
+ importVar: 'federation',
+ initFragments: [],
+ runtime: chunk.runtime,
+ runtimeRequirements: new Set(),
+ });
+
+ return Template.asString([
+ `var federation = ${initRuntimeModuleGetter};`,
+ `federation = ${exportExpr}`,
+ `var prevFederation = ${federationGlobal};`,
+ `${federationGlobal} = {};`,
+ `for (var key in federation) {`,
+ Template.indent(`${federationGlobal}[key] = federation[key];`),
+ `}`,
+ `for (var key in prevFederation) {`,
+ Template.indent(`${federationGlobal}[key] = prevFederation[key];`),
+ `}`,
+ 'federation = undefined;',
+ ]);
+ }
+
+ private findModule(chunk: Chunk, bundlerRuntimePath: string): Module | null {
+ const { chunkGraph, compilation } = this;
+ if (!chunk || !chunkGraph || !compilation) {
+ return null;
+ }
+ for (const mod of chunkGraph.getChunkModulesIterable(chunk)) {
+ if (mod instanceof NormalModule && mod.resource === bundlerRuntimePath) {
+ return mod;
+ }
+
+ if (mod instanceof ConcatenatedModule) {
+ for (const m of mod.modules) {
+ if (m instanceof NormalModule && m.resource === bundlerRuntimePath) {
+ return mod;
+ }
+ }
+ }
+ }
+ return null;
+ }
+}
+
+export default EmbedFederationRuntimeModule;
diff --git a/packages/enhanced/src/lib/container/runtime/EmbedFederationRuntimePlugin.ts b/packages/enhanced/src/lib/container/runtime/EmbedFederationRuntimePlugin.ts
new file mode 100644
index 0000000000..5a5c0ce0af
--- /dev/null
+++ b/packages/enhanced/src/lib/container/runtime/EmbedFederationRuntimePlugin.ts
@@ -0,0 +1,49 @@
+import { normalizeWebpackPath } from '@module-federation/sdk/normalize-webpack-path';
+import EmbedFederationRuntimeModule from './EmbedFederationRuntimeModule';
+const { RuntimeGlobals } = require(
+ normalizeWebpackPath('webpack'),
+) as typeof import('webpack');
+import type { Compiler, Compilation, Chunk, Module, ChunkGraph } from 'webpack';
+import { getFederationGlobalScope } from './utils';
+const EntryDependency = require(
+ normalizeWebpackPath('webpack/lib/dependencies/EntryDependency'),
+) as typeof import('webpack/lib/dependencies/EntryDependency');
+
+const federationGlobal = getFederationGlobalScope(RuntimeGlobals);
+
+class EmbedFederationRuntimePlugin {
+ private bundlerRuntimePath: string;
+
+ constructor(path: string) {
+ this.bundlerRuntimePath = path;
+ }
+
+ apply(compiler: Compiler): void {
+ compiler.hooks.thisCompilation.tap(
+ 'EmbedFederationRuntimePlugin',
+ (compilation: Compilation) => {
+ const handler = (chunk: Chunk, runtimeRequirements: Set) => {
+ if (chunk.id === 'build time chunk') {
+ return;
+ }
+ if (runtimeRequirements.has('embeddedFederationRuntime')) return;
+ if (!runtimeRequirements.has(federationGlobal)) {
+ return;
+ }
+
+ runtimeRequirements.add('embeddedFederationRuntime');
+ const runtimeModule = new EmbedFederationRuntimeModule(
+ this.bundlerRuntimePath,
+ );
+
+ compilation.addRuntimeModule(chunk, runtimeModule);
+ };
+ compilation.hooks.runtimeRequirementInTree
+ .for(federationGlobal)
+ .tap('EmbedFederationRuntimePlugin', handler);
+ },
+ );
+ }
+}
+
+export default EmbedFederationRuntimePlugin;
diff --git a/packages/enhanced/src/lib/container/runtime/FederationRuntimeModule.ts b/packages/enhanced/src/lib/container/runtime/FederationRuntimeModule.ts
index 45d92eecb4..abd0e63e7b 100644
--- a/packages/enhanced/src/lib/container/runtime/FederationRuntimeModule.ts
+++ b/packages/enhanced/src/lib/container/runtime/FederationRuntimeModule.ts
@@ -14,12 +14,12 @@ const { RuntimeModule, RuntimeGlobals, Template } = require(
) as typeof import('webpack');
class FederationRuntimeModule extends RuntimeModule {
- runtimeRequirements: Set;
+ runtimeRequirements: ReadonlySet;
containerName: string;
initOptionsWithoutShared: NormalizedRuntimeInitOptionsWithOutShared;
constructor(
- runtimeRequirements: Set,
+ runtimeRequirements: ReadonlySet,
containerName: string,
initOptionsWithoutShared: NormalizedRuntimeInitOptionsWithOutShared,
) {
diff --git a/packages/enhanced/src/lib/container/runtime/FederationRuntimePlugin.ts b/packages/enhanced/src/lib/container/runtime/FederationRuntimePlugin.ts
index 5aea3f17c9..140b90ade1 100644
--- a/packages/enhanced/src/lib/container/runtime/FederationRuntimePlugin.ts
+++ b/packages/enhanced/src/lib/container/runtime/FederationRuntimePlugin.ts
@@ -1,6 +1,12 @@
-import type { Compiler, WebpackPluginInstance } from 'webpack';
+import type {
+ Compiler,
+ WebpackPluginInstance,
+ Compilation,
+ Chunk,
+} from 'webpack';
import { normalizeWebpackPath } from '@module-federation/sdk/normalize-webpack-path';
import FederationRuntimeModule from './FederationRuntimeModule';
+import type { moduleFederationPlugin } from '@module-federation/sdk';
import {
getFederationGlobalScope,
normalizeRuntimeInitOptionsWithOutShared,
@@ -11,7 +17,9 @@ import {
import fs from 'fs';
import path from 'path';
import { TEMP_DIR } from '../constant';
-import type { moduleFederationPlugin } from '@module-federation/sdk';
+import EmbedFederationRuntimePlugin from './EmbedFederationRuntimePlugin';
+import ContainerEntryModule from '../ContainerEntryModule';
+import HoistContainerReferences from '../HoistContainerReferencesPlugin';
import pBtoa from 'btoa';
const { RuntimeGlobals, Template } = require(
@@ -32,6 +40,12 @@ const BundlerRuntimePath = require.resolve(
const RuntimePath = require.resolve('@module-federation/runtime', {
paths: [RuntimeToolsPath],
});
+const EmbeddedRuntimePath = require.resolve(
+ '@module-federation/runtime/embedded',
+ {
+ paths: [RuntimeToolsPath],
+ },
+);
const federationGlobal = getFederationGlobalScope(RuntimeGlobals);
@@ -46,7 +60,11 @@ class FederationRuntimePlugin {
this.bundlerRuntimePath = BundlerRuntimePath;
}
- static getTemplate(runtimePlugins: string[], bundlerRuntimePath?: string) {
+ static getTemplate(
+ runtimePlugins: string[],
+ bundlerRuntimePath?: string,
+ embedRuntime: boolean = false,
+ ) {
// internal runtime plugin
const normalizedBundlerRuntimePath = normalizeToPosixPath(
bundlerRuntimePath || BundlerRuntimePath,
@@ -69,17 +87,25 @@ class FederationRuntimePlugin {
});
}
+ const embedRuntimeLines = Template.asString([
+ `if(!${federationGlobal}.runtime){`,
+ Template.indent([
+ `var prevFederation = ${federationGlobal};`,
+ `${federationGlobal} = {}`,
+ `for(var key in federation){`,
+ Template.indent([`${federationGlobal}[key] = federation[key];`]),
+ '}',
+ `for(var key in prevFederation){`,
+ Template.indent([`${federationGlobal}[key] = prevFederation[key];`]),
+ '}',
+ ]),
+ '}',
+ ]);
+
return Template.asString([
`import federation from '${normalizedBundlerRuntimePath}';`,
runtimePluginTemplates,
- `var prevFederation = ${federationGlobal};`,
- `${federationGlobal} = {}`,
- `for(var key in federation){`,
- Template.indent([`${federationGlobal}[key] = federation[key];`]),
- '}',
- `for(var key in prevFederation){`,
- Template.indent([`${federationGlobal}[key] = prevFederation[key];`]),
- '}',
+ embedRuntimeLines,
`if(!${federationGlobal}.instance){`,
Template.indent([
runtimePluginNames.length
@@ -113,11 +139,13 @@ class FederationRuntimePlugin {
containerName: string,
runtimePlugins: string[],
bundlerRuntimePath?: string,
+ embedRuntime: boolean = false,
) {
const hash = createHash(
`${containerName} ${FederationRuntimePlugin.getTemplate(
runtimePlugins,
bundlerRuntimePath,
+ embedRuntime,
)}`,
);
return path.join(TEMP_DIR, `entry.${hash}.js`);
@@ -137,6 +165,7 @@ class FederationRuntimePlugin {
this.options.name!,
this.options.runtimePlugins!,
this.bundlerRuntimePath,
+ this.options.embedRuntime,
);
} else {
this.entryFilePath = `data:text/javascript;charset=utf-8;base64,${pBtoa(
@@ -163,6 +192,7 @@ class FederationRuntimePlugin {
FederationRuntimePlugin.getTemplate(
this.options.runtimePlugins!,
this.bundlerRuntimePath,
+ this.options.embedRuntime,
),
);
}
@@ -205,37 +235,72 @@ class FederationRuntimePlugin {
compiler.hooks.thisCompilation.tap(
this.constructor.name,
- (compilation, { normalModuleFactory }) => {
+ (compilation: Compilation, { normalModuleFactory }) => {
+ const isEnabledForChunk = (chunk: Chunk): boolean => {
+ const [entryModule] =
+ compilation.chunkGraph.getChunkEntryModulesIterable(chunk) || [];
+ return entryModule instanceof ContainerEntryModule;
+ };
+ const handler = (chunk: Chunk, runtimeRequirements: Set) => {
+ if (runtimeRequirements.has(federationGlobal)) return;
+ runtimeRequirements.add(federationGlobal);
+ runtimeRequirements.add(RuntimeGlobals.interceptModuleExecution);
+ runtimeRequirements.add(RuntimeGlobals.moduleCache);
+ runtimeRequirements.add(RuntimeGlobals.compatGetDefaultExport);
+
+ compilation.addRuntimeModule(
+ chunk,
+ new FederationRuntimeModule(
+ runtimeRequirements,
+ name,
+ initOptionsWithoutShared,
+ ),
+ );
+ };
+
compilation.hooks.additionalTreeRuntimeRequirements.tap(
this.constructor.name,
- (chunk, runtimeRequirements) => {
- if (runtimeRequirements.has(federationGlobal)) {
+ (chunk: Chunk, runtimeRequirements: Set) => {
+ if (!chunk.hasRuntime()) return;
+ if (runtimeRequirements.has(RuntimeGlobals.initializeSharing))
return;
- }
- runtimeRequirements.add(RuntimeGlobals.interceptModuleExecution);
- runtimeRequirements.add(RuntimeGlobals.moduleCache);
- runtimeRequirements.add(RuntimeGlobals.compatGetDefaultExport);
- runtimeRequirements.add(federationGlobal);
- compilation.addRuntimeModule(
- chunk,
- new FederationRuntimeModule(
- runtimeRequirements,
- name,
- initOptionsWithoutShared,
- ),
- );
+ if (runtimeRequirements.has(RuntimeGlobals.currentRemoteGetScope))
+ return;
+ if (runtimeRequirements.has(RuntimeGlobals.shareScopeMap)) return;
+ if (runtimeRequirements.has(federationGlobal)) return;
+ handler(chunk, runtimeRequirements);
},
);
+
+ // if federation runtime requirements exist
+ // attach runtime module to the chunk
+ compilation.hooks.runtimeRequirementInTree
+ .for(RuntimeGlobals.initializeSharing)
+ .tap(this.constructor.name, handler);
+ compilation.hooks.runtimeRequirementInTree
+ .for(RuntimeGlobals.currentRemoteGetScope)
+ .tap(this.constructor.name, handler);
+ compilation.hooks.runtimeRequirementInTree
+ .for(RuntimeGlobals.shareScopeMap)
+ .tap(this.constructor.name, handler);
+ compilation.hooks.runtimeRequirementInTree
+ .for(federationGlobal)
+ .tap(this.constructor.name, handler);
},
);
}
setRuntimeAlias(compiler: Compiler) {
- let runtimePath = RuntimePath;
+ let runtimePath = this.options?.embedRuntime
+ ? EmbeddedRuntimePath
+ : RuntimePath;
if (this.options?.implementation) {
- runtimePath = require.resolve('@module-federation/runtime', {
- paths: [this.options.implementation],
- });
+ runtimePath = require.resolve(
+ `@module-federation/runtime${this.options?.embedRuntime ? '/embedded' : ''}`,
+ {
+ paths: [this.options.implementation],
+ },
+ );
}
if (Array.isArray(compiler.options.resolve.alias)) {
return;
@@ -281,7 +346,6 @@ class FederationRuntimePlugin {
);
if (useContainerPlugin && !this.options) {
- // @ts-ignore
this.options = useContainerPlugin._options;
}
@@ -292,7 +356,7 @@ class FederationRuntimePlugin {
};
}
if (this.options && !this.options?.name) {
- // the instance may get the same one if the name is the same https://github.com/module-federation/core/blob/main/packages/runtime/src/index.ts#L18
+ //! the instance may get the same one if the name is the same https://github.com/module-federation/core/blob/main/packages/runtime/src/index.ts#L18
this.options.name =
compiler.options.output.uniqueName || `container_${Date.now()}`;
}
@@ -305,7 +369,33 @@ class FederationRuntimePlugin {
},
);
}
+ if (this.options?.embedRuntime) {
+ this.bundlerRuntimePath = this.bundlerRuntimePath.replace(
+ '.cjs.js',
+ '.esm.js',
+ );
+ new EmbedFederationRuntimePlugin(this.bundlerRuntimePath).apply(compiler);
+
+ new HoistContainerReferences(
+ this.options.name ? this.options.name + '_partial' : undefined,
+ // hoist all modules of federation entry
+ this.getFilePath(),
+ this.bundlerRuntimePath,
+ ).apply(compiler);
+
+ new compiler.webpack.NormalModuleReplacementPlugin(
+ /@module-federation\/runtime/,
+ (resolveData) => {
+ if (/webpack-bundler-runtime/.test(resolveData.contextInfo.issuer)) {
+ resolveData.request = RuntimePath.replace('cjs', 'esm');
+ if (resolveData.createData) {
+ resolveData.createData.request = resolveData.request;
+ }
+ }
+ },
+ ).apply(compiler);
+ }
this.prependEntry(compiler);
this.injectRuntime(compiler);
this.setRuntimeAlias(compiler);
diff --git a/packages/enhanced/src/lib/sharing/ConsumeSharedRuntimeModule.ts b/packages/enhanced/src/lib/sharing/ConsumeSharedRuntimeModule.ts
index e719523c5a..0ed0842722 100644
--- a/packages/enhanced/src/lib/sharing/ConsumeSharedRuntimeModule.ts
+++ b/packages/enhanced/src/lib/sharing/ConsumeSharedRuntimeModule.ts
@@ -92,6 +92,13 @@ class ConsumeSharedRuntimeModule extends RuntimeModule {
moduleIdToSourceMapping.set(id, sharedInfoAndHandlerStr);
}
};
+ // const chunkReferences = this._runtimeRequirements.has(
+ // 'federation-entry-startup',
+ // )
+ // ? this.chunk?.getAllReferencedChunks()
+ // : this.chunk?.getAllAsyncChunks();
+ //
+ // const allChunks = chunkReferences || [];
const allChunks = [...(this.chunk?.getAllReferencedChunks() || [])];
for (const chunk of allChunks) {
const modules = chunkGraph.getChunkModulesIterableBySourceType(
diff --git a/packages/enhanced/src/lib/sharing/ProvideSharedPlugin.ts b/packages/enhanced/src/lib/sharing/ProvideSharedPlugin.ts
index 5b1030628b..e66ebae2fe 100644
--- a/packages/enhanced/src/lib/sharing/ProvideSharedPlugin.ts
+++ b/packages/enhanced/src/lib/sharing/ProvideSharedPlugin.ts
@@ -268,7 +268,7 @@ class ProvideSharedPlugin {
compilation.dependencyFactories.set(
ProvideSharedDependency,
- // @ts-ignore
+ //@ts-ignore
new ProvideSharedModuleFactory(),
);
},
diff --git a/packages/enhanced/src/lib/startup/MfStartupChunkDependenciesPlugin.ts b/packages/enhanced/src/lib/startup/MfStartupChunkDependenciesPlugin.ts
new file mode 100644
index 0000000000..2dd6c8295d
--- /dev/null
+++ b/packages/enhanced/src/lib/startup/MfStartupChunkDependenciesPlugin.ts
@@ -0,0 +1,148 @@
+'use strict';
+
+import { normalizeWebpackPath } from '@module-federation/sdk/normalize-webpack-path';
+import { generateEntryStartup } from './StartupHelpers';
+import type { Compiler, Chunk } from 'webpack';
+import ContainerEntryModule from '../container/ContainerEntryModule';
+
+const { RuntimeGlobals } = require(
+ normalizeWebpackPath('webpack'),
+) as typeof import('webpack');
+
+const StartupEntrypointRuntimeModule = require(
+ normalizeWebpackPath('webpack/lib/runtime/StartupEntrypointRuntimeModule'),
+) as typeof import('webpack/lib/runtime/StartupEntrypointRuntimeModule');
+const ConcatenatedModule = require(
+ normalizeWebpackPath('webpack/lib/optimize/ConcatenatedModule'),
+) as typeof import('webpack/lib/optimize/ConcatenatedModule');
+
+interface Options {
+ asyncChunkLoading?: boolean;
+}
+
+class StartupChunkDependenciesPlugin {
+ asyncChunkLoading: boolean;
+
+ constructor(options: Options) {
+ this.asyncChunkLoading = options.asyncChunkLoading ?? true;
+ }
+
+ private isEnabledForChunk(chunk: Chunk, compilation: any): boolean {
+ if (chunk.id === 'build time chunk') return false;
+ const [finalEntry] =
+ compilation.chunkGraph.getChunkEntryModulesIterable(chunk) || [];
+ return !(finalEntry instanceof ContainerEntryModule);
+ }
+
+ apply(compiler: Compiler): void {
+ compiler.hooks.thisCompilation.tap(
+ 'MfStartupChunkDependenciesPlugin',
+ (compilation) => {
+ const isEnabledForChunk = (chunk: Chunk) =>
+ this.isEnabledForChunk(chunk, compilation);
+
+ compilation.hooks.additionalTreeRuntimeRequirements.tap(
+ 'StartupChunkDependenciesPlugin',
+ (chunk, set, { chunkGraph }) => {
+ if (!isEnabledForChunk(chunk)) return;
+ if (chunk.hasRuntime()) {
+ set.add(RuntimeGlobals.startupEntrypoint);
+ set.add(RuntimeGlobals.ensureChunk);
+ set.add(RuntimeGlobals.ensureChunkIncludeEntries);
+ }
+ },
+ );
+
+ compilation.hooks.additionalChunkRuntimeRequirements.tap(
+ 'MfStartupChunkDependenciesPlugin',
+ (chunk, set, { chunkGraph }) => {
+ if (!isEnabledForChunk(chunk)) return;
+ if (chunkGraph.getNumberOfEntryModules(chunk) === 0) return;
+ set.add('federation-entry-startup');
+ },
+ );
+
+ compilation.hooks.runtimeRequirementInTree
+ .for(RuntimeGlobals.startupEntrypoint)
+ .tap(
+ 'StartupChunkDependenciesPlugin',
+ (chunk, set, { chunkGraph }) => {
+ if (!isEnabledForChunk(chunk)) return;
+ set.add(RuntimeGlobals.require);
+ set.add(RuntimeGlobals.ensureChunk);
+ set.add(RuntimeGlobals.ensureChunkIncludeEntries);
+ compilation.addRuntimeModule(
+ chunk,
+ new StartupEntrypointRuntimeModule(this.asyncChunkLoading),
+ );
+ },
+ );
+
+ const { renderStartup } =
+ compiler.webpack.javascript.JavascriptModulesPlugin.getCompilationHooks(
+ compilation,
+ );
+
+ renderStartup.tap(
+ 'MfStartupChunkDependenciesPlugin',
+ (startupSource, lastInlinedModule, renderContext) => {
+ const { chunk, chunkGraph, runtimeTemplate } = renderContext;
+
+ if (!isEnabledForChunk(chunk)) {
+ return startupSource;
+ }
+
+ let federationRuntimeModule: any = null;
+
+ const isFederationModule = (module: any) =>
+ module.context?.endsWith('.federation');
+
+ for (const module of chunkGraph.getChunkEntryModulesIterable(
+ chunk,
+ )) {
+ if (isFederationModule(module)) {
+ federationRuntimeModule = module;
+ break;
+ }
+
+ if (module && '_modules' in module) {
+ for (const concatModule of (
+ module as InstanceType
+ )._modules) {
+ if (isFederationModule(concatModule)) {
+ federationRuntimeModule = module;
+ break;
+ }
+ }
+ }
+ }
+
+ if (!federationRuntimeModule) {
+ return startupSource;
+ }
+
+ const federationModuleId = chunkGraph.getModuleId(
+ federationRuntimeModule,
+ );
+ const entryModules = Array.from(
+ chunkGraph.getChunkEntryModulesWithChunkGroupIterable(chunk),
+ );
+
+ return new compiler.webpack.sources.ConcatSource(
+ `${RuntimeGlobals.require}(${JSON.stringify(federationModuleId)});\n`,
+ generateEntryStartup(
+ chunkGraph,
+ runtimeTemplate,
+ entryModules,
+ chunk,
+ false,
+ ),
+ );
+ },
+ );
+ },
+ );
+ }
+}
+
+export default StartupChunkDependenciesPlugin;
diff --git a/packages/enhanced/src/lib/startup/StartupHelpers.ts b/packages/enhanced/src/lib/startup/StartupHelpers.ts
new file mode 100644
index 0000000000..7acb388c81
--- /dev/null
+++ b/packages/enhanced/src/lib/startup/StartupHelpers.ts
@@ -0,0 +1,155 @@
+/*
+ MIT License http://www.opensource.org/licenses/mit-license.php
+ Author Tobias Koppers @sokra, Zack Jackson @ScriptedAlchemy
+*/
+
+'use strict';
+import type Chunk from 'webpack/lib/Chunk';
+import type ChunkGraph from 'webpack/lib/ChunkGraph';
+import { normalizeWebpackPath } from '@module-federation/sdk/normalize-webpack-path';
+import type { EntryModuleWithChunkGroup } from 'webpack/lib/ChunkGraph';
+import type RuntimeTemplate from 'webpack/lib/RuntimeTemplate';
+import type Entrypoint from 'webpack/lib/Entrypoint';
+
+const { RuntimeGlobals, Template } = require(
+ normalizeWebpackPath('webpack'),
+) as typeof import('webpack');
+const { isSubset } = require(
+ normalizeWebpackPath('webpack/lib/util/SetHelpers'),
+) as typeof import('webpack/lib/util/SetHelpers');
+const { getAllChunks } = require(
+ normalizeWebpackPath('webpack/lib/javascript/ChunkHelpers'),
+) as typeof import('webpack/lib/javascript/ChunkHelpers');
+
+const EXPORT_PREFIX = `var ${RuntimeGlobals.exports} = `;
+
+export const federationStartup = 'federation-entry-startup';
+
+export const generateEntryStartup = (
+ chunkGraph: ChunkGraph,
+ runtimeTemplate: RuntimeTemplate,
+ entries: EntryModuleWithChunkGroup[],
+ chunk: Chunk,
+ passive: boolean,
+): string => {
+ /** @type {string[]} */
+ const runtime: string[] = [
+ `var __webpack_exec__ = ${runtimeTemplate.returningFunction(
+ `${RuntimeGlobals.require}(${RuntimeGlobals.entryModuleId} = moduleId)`,
+ 'moduleId',
+ )}`,
+ '',
+ '\n',
+ 'var promises = [];',
+ ];
+
+ const treeRuntimeRequirements = chunkGraph.getTreeRuntimeRequirements(chunk);
+ const chunkRuntimeRequirements =
+ chunkGraph.getChunkRuntimeRequirements(chunk);
+ const federation =
+ chunkRuntimeRequirements.has(federationStartup) ||
+ treeRuntimeRequirements.has(federationStartup);
+
+ const hasRemotes =
+ chunkRuntimeRequirements.has(RuntimeGlobals.currentRemoteGetScope) ||
+ // check if tree has req
+ treeRuntimeRequirements.has(RuntimeGlobals.currentRemoteGetScope) ||
+ // check if chunk contains remote module types
+ // currentRemoteGetScope is not reliable requirement for host check
+ !!chunkGraph.getChunkModulesIterableBySourceType(chunk, 'remote');
+
+ const hasConsumes =
+ chunkRuntimeRequirements.has(RuntimeGlobals.initializeSharing) ||
+ treeRuntimeRequirements.has(RuntimeGlobals.initializeSharing) ||
+ chunkRuntimeRequirements.has(RuntimeGlobals.shareScopeMap) ||
+ treeRuntimeRequirements.has(RuntimeGlobals.shareScopeMap);
+
+ const runModule = (id: string) => {
+ return `__webpack_exec__(${JSON.stringify(id)})`;
+ };
+ const outputCombination = (
+ chunks: Set,
+ moduleIds: string[],
+ final?: boolean,
+ ) => {
+ if (chunks.size === 0 && !federation) {
+ runtime.push(
+ `${final ? EXPORT_PREFIX : ''}(${moduleIds.map(runModule).join(', ')});`,
+ );
+ } else {
+ const fn = runtimeTemplate.returningFunction(
+ moduleIds.map(runModule).join(', '),
+ );
+ if (federation) {
+ const chunkIds = Array.from(chunks, (c: Chunk) => c.id);
+
+ const wrappedInit = (body: string) =>
+ Template.asString([
+ 'Promise.all([',
+ Template.indent([
+ hasConsumes
+ ? `${RuntimeGlobals.ensureChunkHandlers}.consumes,`
+ : '',
+ hasRemotes
+ ? `${RuntimeGlobals.ensureChunkHandlers}.remotes,`
+ : '',
+ ]),
+ `].reduce(${runtimeTemplate.returningFunction(`handler('${chunk.id}', p), p`, 'p, handler')}, promises)`,
+ `).then(${runtimeTemplate.returningFunction(body)});`,
+ ]);
+
+ const wrap = wrappedInit(
+ `${
+ passive
+ ? RuntimeGlobals.onChunksLoaded
+ : RuntimeGlobals.startupEntrypoint
+ }(0, ${JSON.stringify(chunkIds)}, ${fn})`,
+ );
+
+ runtime.push(`${final && !passive ? EXPORT_PREFIX : ''}${wrap}`);
+ } else {
+ const chunkIds = Array.from(chunks, (c: Chunk) => c.id);
+ runtime.push(
+ `${final && !passive ? EXPORT_PREFIX : ''}${
+ passive
+ ? RuntimeGlobals.onChunksLoaded
+ : RuntimeGlobals.startupEntrypoint
+ }(0, ${JSON.stringify(chunkIds)}, ${fn});`,
+ );
+ if (final && passive) {
+ runtime.push(`${EXPORT_PREFIX}${RuntimeGlobals.onChunksLoaded}();`);
+ }
+ }
+ }
+ };
+
+ let currentChunks: Set | undefined = undefined;
+ let currentModuleIds: string[] | undefined = undefined;
+
+ for (const [module, entrypoint] of entries) {
+ if (!entrypoint) continue;
+ const runtimeChunk = entrypoint.getRuntimeChunk() as Entrypoint.Chunk;
+ const moduleId = chunkGraph.getModuleId(module) as string;
+ const chunks = getAllChunks(entrypoint as Entrypoint, chunk, runtimeChunk);
+ if (
+ currentChunks &&
+ currentChunks.size === chunks.size &&
+ isSubset(currentChunks, chunks)
+ ) {
+ currentModuleIds!.push(moduleId);
+ } else {
+ if (currentChunks) {
+ outputCombination(currentChunks, currentModuleIds!);
+ }
+ currentChunks = chunks;
+ currentModuleIds = [moduleId];
+ }
+ }
+
+ // output current modules with export prefix
+ if (currentChunks) {
+ outputCombination(currentChunks, currentModuleIds!, true);
+ }
+ runtime.push('');
+ return Template.asString(runtime);
+};
diff --git a/packages/enhanced/src/wrapper/HoistContainerReferencesPlugin.ts b/packages/enhanced/src/wrapper/HoistContainerReferencesPlugin.ts
index e2fc48aed2..a1ea8b3657 100644
--- a/packages/enhanced/src/wrapper/HoistContainerReferencesPlugin.ts
+++ b/packages/enhanced/src/wrapper/HoistContainerReferencesPlugin.ts
@@ -7,10 +7,21 @@ export default class HoistContainerReferencesPlugin
implements WebpackPluginInstance
{
name: string;
- private containerName?: string | undefined;
+ private containerName: string;
+ private entryFilePath?: string;
+ private bundlerRuntimeDep?: string;
+ private explanation: string;
- constructor(name?: string | undefined) {
- this.containerName = name;
+ constructor(
+ name?: string,
+ entryFilePath?: string,
+ bundlerRuntimeDep?: string,
+ ) {
+ this.containerName = name || 'no known chunk name';
+ this.entryFilePath = entryFilePath;
+ this.bundlerRuntimeDep = bundlerRuntimeDep;
+ this.explanation =
+ 'Bundler runtime path module is required for proper functioning';
this.name = PLUGIN_NAME;
}
@@ -20,6 +31,10 @@ export default class HoistContainerReferencesPlugin
const CoreHoistContainerReferencesPlugin =
require('../lib/container/HoistContainerReferencesPlugin')
.default as typeof import('../lib/container/HoistContainerReferencesPlugin').default;
- new CoreHoistContainerReferencesPlugin().apply(compiler);
+ new CoreHoistContainerReferencesPlugin(
+ this.containerName,
+ this.entryFilePath,
+ this.bundlerRuntimeDep,
+ ).apply(compiler);
}
}
diff --git a/packages/nextjs-mf/package.json b/packages/nextjs-mf/package.json
index c3c0b178e3..5bf3aa530a 100644
--- a/packages/nextjs-mf/package.json
+++ b/packages/nextjs-mf/package.json
@@ -43,7 +43,8 @@
"@module-federation/runtime": "workspace:*",
"@module-federation/sdk": "workspace:*",
"@module-federation/enhanced": "workspace:*",
- "@module-federation/node": "workspace:*"
+ "@module-federation/node": "workspace:*",
+ "@module-federation/webpack-bundler-runtime": "workspace:*"
},
"peerDependencies": {
"webpack": "^5.40.0",
diff --git a/packages/nextjs-mf/src/loaders/fixImageLoader.ts b/packages/nextjs-mf/src/loaders/fixImageLoader.ts
index db0d528196..99a0903ea7 100644
--- a/packages/nextjs-mf/src/loaders/fixImageLoader.ts
+++ b/packages/nextjs-mf/src/loaders/fixImageLoader.ts
@@ -27,9 +27,8 @@ export async function fixImageLoader(
) {
this.cacheable(true);
- const isServer = this._compiler?.options.name !== 'client';
- //@ts-ignore
- const { publicPath } = this._compiler.webpack.RuntimeGlobals;
+ const isServer = this._compiler?.options?.name !== 'client';
+ const publicPath = this._compiler?.webpack?.RuntimeGlobals?.publicPath ?? '';
const result = await this.importModule(
`${this.resourcePath}.webpack[javascript/auto]!=!${remaining}`,
diff --git a/packages/nextjs-mf/src/plugins/NextFederationPlugin/apply-client-plugins.ts b/packages/nextjs-mf/src/plugins/NextFederationPlugin/apply-client-plugins.ts
index 1f33dd3012..53ad5124b6 100644
--- a/packages/nextjs-mf/src/plugins/NextFederationPlugin/apply-client-plugins.ts
+++ b/packages/nextjs-mf/src/plugins/NextFederationPlugin/apply-client-plugins.ts
@@ -1,11 +1,9 @@
import type { Compiler } from 'webpack';
-import {
- ModuleFederationPluginOptions,
- NextFederationPluginExtraOptions,
-} from '@module-federation/utilities';
+import { NextFederationPluginExtraOptions } from '@module-federation/utilities';
import { ChunkCorrelationPlugin } from '@module-federation/node';
import InvertedContainerPlugin from '../container/InvertedContainerPlugin';
-import { HoistContainerReferencesPlugin } from '@module-federation/enhanced';
+import type { moduleFederationPlugin } from '@module-federation/sdk';
+
/**
* Applies client-specific plugins.
*
@@ -17,33 +15,32 @@ import { HoistContainerReferencesPlugin } from '@module-federation/enhanced';
* This function applies plugins to the Webpack compiler instance that are specific to the client build of
* a Next.js application with Module Federation enabled. These plugins include the following:
*
- * - DelegateModulesPlugin: Delegates modules to the webpack container runtime that can be streamed to other runtimes.
* - ChunkCorrelationPlugin: Collects metadata on chunks to enable proper module loading across different runtimes.
* - InvertedContainerPlugin: Adds custom runtime modules to the container runtime to allow a host to expose its
* own remote interface at startup.
- *
- * If automatic page stitching is enabled, a loader is added to process the `next/dist/client/page-loader.js`
- * file. If a custom library is specified in the options, an error is thrown. The options.library property is
+
+ * If automatic page stitching is enabled, a warning is logged indicating that it is disabled in v7.
+ * If a custom library is specified in the options, an error is logged. The options.library property is
* also set to `{ type: 'window', name: options.name }`.
*/
export function applyClientPlugins(
compiler: Compiler,
- options: ModuleFederationPluginOptions,
+ options: moduleFederationPlugin.ModuleFederationPluginOptions,
extraOptions: NextFederationPluginExtraOptions,
): void {
- const { webpack } = compiler;
- const { remotes, name } = options;
+ const { name } = options;
+ // Adjust the public path if it is set to the default Next.js path
if (compiler.options.output.publicPath === '/_next/') {
compiler.options.output.publicPath = 'auto';
}
- // If automatic page stitching is enabled, add a new rule to the compiler's module rules
+ // Log a warning if automatic page stitching is enabled, as it is disabled in v7
if (extraOptions.automaticPageStitching) {
console.warn('[nextjs-mf]', 'automatic page stitching is disabled in v7');
}
- // If a custom library is set, log an error message
+ // Log an error if a custom library is set, as it is not allowed
if (options.library) {
console.error('[nextjs-mf] you cannot set custom library');
}
@@ -54,23 +51,19 @@ export function applyClientPlugins(
name,
};
- // Add a new chunk correlation plugin to the compiler
+ // Apply the ChunkCorrelationPlugin to collect metadata on chunks
new ChunkCorrelationPlugin({
filename: [
'static/chunks/federated-stats.json',
'server/federated-stats.json',
],
- //@ts-ignore
}).apply(compiler);
- new HoistContainerReferencesPlugin(options.name).apply(compiler);
-
- // Add a new commonjs chunk loading plugin to the compiler
+ // Apply the InvertedContainerPlugin to add custom runtime modules to the container runtime
new InvertedContainerPlugin({
runtime: 'webpack',
container: options.name,
remotes: options.remotes as Record,
debug: extraOptions.debug,
- //@ts-ignore
}).apply(compiler);
}
diff --git a/packages/nextjs-mf/src/plugins/NextFederationPlugin/apply-server-plugins.ts b/packages/nextjs-mf/src/plugins/NextFederationPlugin/apply-server-plugins.ts
index 3d20453a06..b09b17a927 100644
--- a/packages/nextjs-mf/src/plugins/NextFederationPlugin/apply-server-plugins.ts
+++ b/packages/nextjs-mf/src/plugins/NextFederationPlugin/apply-server-plugins.ts
@@ -1,65 +1,98 @@
-import type { Compiler } from 'webpack';
-import { ModuleFederationPluginOptions } from '@module-federation/utilities';
-import { HoistContainerReferencesPlugin } from '@module-federation/enhanced';
+import type {
+ WebpackOptionsNormalized,
+ Compiler,
+ ExternalItemFunctionData,
+} from 'webpack';
+import type { moduleFederationPlugin } from '@module-federation/sdk';
import path from 'path';
import InvertedContainerPlugin from '../container/InvertedContainerPlugin';
-import { ModuleFederationPlugin } from '@module-federation/enhanced/webpack';
+
+type EntryStaticNormalized = Awaited<
+ ReturnType any>>
+>;
+
+interface ModifyEntryOptions {
+ compiler: Compiler;
+ prependEntry?: (entry: EntryStaticNormalized) => void;
+ staticEntry?: EntryStaticNormalized;
+}
+
+// Modifies the Webpack entry configuration
+export function modifyEntry(options: ModifyEntryOptions): void {
+ const { compiler, staticEntry, prependEntry } = options;
+ const operator = (
+ oriEntry: EntryStaticNormalized,
+ newEntry: EntryStaticNormalized,
+ ): EntryStaticNormalized => Object.assign(oriEntry, newEntry);
+
+ // If the entry is a function, wrap it to modify the result
+ if (typeof compiler.options.entry === 'function') {
+ const prevEntryFn = compiler.options.entry;
+ compiler.options.entry = async () => {
+ let res = await prevEntryFn();
+ if (staticEntry) {
+ res = operator(res, staticEntry);
+ }
+ if (prependEntry) {
+ prependEntry(res);
+ }
+ return res;
+ };
+ } else {
+ // If the entry is an object, directly modify it
+ if (staticEntry) {
+ compiler.options.entry = operator(compiler.options.entry, staticEntry);
+ }
+ if (prependEntry) {
+ prependEntry(compiler.options.entry);
+ }
+ }
+}
+
/**
- * This function applies server-specific plugins to the webpack compiler.
+ * Applies server-specific plugins to the webpack compiler.
*
* @param {Compiler} compiler - The Webpack compiler instance.
- * @param {ModuleFederationPluginOptions} options - The ModuleFederationPluginOptions instance.
- *
- * @returns {void}
+ * @param {moduleFederationPlugin.ModuleFederationPluginOptions} options - The ModuleFederationPluginOptions instance.
*/
export function applyServerPlugins(
compiler: Compiler,
- options: ModuleFederationPluginOptions,
+ options: moduleFederationPlugin.ModuleFederationPluginOptions,
): void {
const chunkFileName = compiler.options?.output?.chunkFilename;
const uniqueName = compiler?.options?.output?.uniqueName || options.name;
+ const suffix = `-[chunkhash].js`;
+ // Modify chunk filename to include a unique suffix if not already present
if (
typeof chunkFileName === 'string' &&
uniqueName &&
!chunkFileName.includes(uniqueName)
) {
- const suffix = `-[chunkhash].js`;
compiler.options.output.chunkFilename = chunkFileName.replace(
'.js',
suffix,
);
}
- new HoistContainerReferencesPlugin(options.name).apply(compiler);
-
- // Add a new commonjs chunk loading plugin to the compiler
+ // Apply the InvertedContainerPlugin to the compiler
new InvertedContainerPlugin({
runtime: 'webpack-runtime',
container: options.name,
remotes: options.remotes as Record,
debug: false,
- //@ts-ignore
}).apply(compiler);
}
/**
- * This function configures server-specific library and filename options.
+ * Configures server-specific library and filename options.
*
* @param {ModuleFederationPluginOptions} options - The ModuleFederationPluginOptions instance.
- *
- * @returns {void}
- *
- * @remarks
- * This function configures the library and filename options for server builds. The library option is
- * set to the commonjs-module format for chunks and the container, which allows them to be streamed over
- * to hosts with the NodeFederationPlugin. The filename option is set to the basename of the current
- * filename.
*/
export function configureServerLibraryAndFilename(
- options: ModuleFederationPluginOptions,
+ options: moduleFederationPlugin.ModuleFederationPluginOptions,
): void {
- // Configure the library option with type "commonjs-module" and the name from the options
+ // Set the library option to "commonjs-module" format with the name from the options
options.library = {
type: 'commonjs-module',
name: options.name,
@@ -70,67 +103,53 @@ export function configureServerLibraryAndFilename(
}
/**
- * This function patches Next.js' default externals function to make sure shared modules are bundled and not treated as external.
+ * Patches Next.js' default externals function to ensure shared modules are bundled and not treated as external.
*
* @param {Compiler} compiler - The Webpack compiler instance.
* @param {ModuleFederationPluginOptions} options - The ModuleFederationPluginOptions instance.
- *
- * @returns {void}
- *
- * @remarks
- * In server builds, all node modules are treated as external, which prevents them from being shared
- * via module federation. To work around this limitation, we mark shared modules as internalizable
- * modules that webpack puts into chunks that can be streamed to other runtimes as needed.
- *
- * This function replaces Next.js' default externals function with a new asynchronous function that
- * checks whether a module should be treated as external. If the module should not be treated as
- * external, the function returns without calling the original externals function. Otherwise, the
- * function calls the original externals function and retrieves the result. If the result is null,
- * the function returns without further processing. If the module is from Next.js or React, the
- * function returns the original result. Otherwise, the function returns null.
*/
export function handleServerExternals(
compiler: Compiler,
- options: ModuleFederationPluginOptions,
+ options: moduleFederationPlugin.ModuleFederationPluginOptions,
): void {
if (
Array.isArray(compiler.options.externals) &&
- compiler.options.externals[0]
+ typeof compiler.options.externals[0] === 'function'
) {
- // Retrieve the original externals function
- const originalExternals = compiler.options.externals[0];
+ const originalExternals = compiler.options.externals[0] as (
+ data: ExternalItemFunctionData,
+ callback: any,
+ ) => undefined | string;
- // Replace the original externals function with a new asynchronous function
- compiler.options.externals[0] = async function (ctx: any, callback: any) {
- //@ts-ignore
+ compiler.options.externals[0] = async function (
+ ctx: ExternalItemFunctionData,
+ callback: any,
+ ) {
const fromNext = await originalExternals(ctx, callback);
- // If the result is null, return without further processing
if (!fromNext) {
return;
}
- // If the module is from Next.js or React, return the original result
const req = fromNext.split(' ')[1];
- // Check if the module should not be treated as external
if (
ctx.request &&
(ctx.request.includes('@module-federation/utilities') ||
Object.keys(options.shared || {}).some((key) => {
+ const sharedOptions = options.shared as Record<
+ string,
+ { import: boolean }
+ >;
return (
- //@ts-ignore
- options.shared?.[key]?.import !== false &&
+ sharedOptions[key]?.import !== false &&
(key.endsWith('/') ? req.includes(key) : req === key)
);
}) ||
ctx.request.includes('@module-federation/'))
) {
- // If the module should not be treated as external, return without calling the original externals function
return;
}
if (
req.startsWith('next') ||
- // make sure we dont screw up package names that start with react
- // like react-carousel or react-spring
req.startsWith('react/') ||
req.startsWith('react-dom/') ||
req === 'react' ||
@@ -139,38 +158,25 @@ export function handleServerExternals(
) {
return fromNext;
}
- // Otherwise, return (null) to treat the module as internalizable
return;
};
}
}
/**
- * This function configures server-specific compiler options.
+ * Configures server-specific compiler options.
*
* @param {Compiler} compiler - The Webpack compiler instance.
- *
- * @returns {void}
- *
- * @remarks
- * This function configures the compiler options for server builds. It turns off the compiler target on node
- * builds because it adds its own chunk loading runtime module with NodeFederationPlugin and StreamingTargetPlugin.
- * It also disables split chunks to prevent conflicts from occurring in the graph.
- *
*/
export function configureServerCompilerOptions(compiler: Compiler): void {
- // Turn off the compiler target on node builds because we add our own chunk loading runtime module
- // with NodeFederationPlugin and StreamingTargetPlugin
+ // Disable the global option in node builds and set the target to "async-node"
compiler.options.node = {
...compiler.options.node,
global: false,
};
compiler.options.target = 'async-node';
- // no custom chunk rules
- compiler.options.optimization.splitChunks = undefined;
- // solves strange issues where next doesnt create a runtime chunk
- // might be related to if an api route exists or not
+ // Ensure a runtime chunk is created
compiler.options.optimization.runtimeChunk = {
name: 'webpack-runtime',
};
diff --git a/packages/nextjs-mf/src/plugins/NextFederationPlugin/index.ts b/packages/nextjs-mf/src/plugins/NextFederationPlugin/index.ts
index 1c9a1fb1c2..09f0dd4f0a 100644
--- a/packages/nextjs-mf/src/plugins/NextFederationPlugin/index.ts
+++ b/packages/nextjs-mf/src/plugins/NextFederationPlugin/index.ts
@@ -20,6 +20,7 @@ import {
validatePluginOptions,
} from './validate-options';
import {
+ modifyEntry,
applyServerPlugins,
configureServerCompilerOptions,
configureServerLibraryAndFilename,
@@ -60,15 +61,28 @@ export class NextFederationPlugin {
if (!this.validateOptions(compiler)) return;
const isServer = this.isServerCompiler(compiler);
new CopyFederationPlugin(isServer).apply(compiler);
- this.applyConditionalPlugins(compiler, isServer);
const normalFederationPluginOptions = this.getNormalFederationPluginOptions(
compiler,
isServer,
);
- // ContainerPlugin will get NextFederationPlugin._options, so NextFederationPlugin._options should be the same as normalFederationPluginOptions
this._options = normalFederationPluginOptions;
- new ModuleFederationPlugin(normalFederationPluginOptions).apply(compiler);
+ this.applyConditionalPlugins(compiler, isServer);
+ new ModuleFederationPlugin(normalFederationPluginOptions).apply(compiler);
+ modifyEntry({
+ compiler,
+ prependEntry: (entry) => {
+ Object.keys(entry).forEach((entryName) => {
+ const entryItem = entry[entryName];
+ if (!entryName.startsWith('pages/api')) return;
+ if (!entryItem.import) return;
+ // unpatch entry of webpack api runtime
+ entryItem.import = entryItem.import.filter((i) => {
+ return !i.includes('.federation/entry');
+ });
+ });
+ },
+ });
const runtimeESMPath = require.resolve(
'@module-federation/runtime/dist/index.esm.js',
);
@@ -81,7 +95,8 @@ export class NextFederationPlugin {
compiler.hooks.afterPlugins.tap('PatchAliasWebpackPlugin', () => {
compiler.options.resolve.alias = {
...compiler.options.resolve.alias,
- '@module-federation/runtime$': runtimeESMPath,
+ //useing embedded runtime
+ // '@module-federation/runtime$': runtimeESMPath,
};
});
}
@@ -131,7 +146,7 @@ export class NextFederationPlugin {
asyncFunction: true,
};
- applyPathFixes(compiler, this._extraOptions);
+ applyPathFixes(compiler, this._options, this._extraOptions);
if (this._extraOptions.debug) {
compiler.options.devtool = false;
}
@@ -174,9 +189,10 @@ export class NextFederationPlugin {
...(isServer
? [require.resolve('@module-federation/node/runtimePlugin')]
: []),
+ //disable loaders on internal plugins
require.resolve(path.join(__dirname, '../container/runtimePlugin')),
...(this._options.runtimePlugins || []),
- ],
+ ].map((plugin) => plugin + '?runtimePlugin'),
//@ts-ignore
exposes: {
...defaultExpose,
@@ -198,6 +214,7 @@ export class NextFederationPlugin {
// nextjs project needs to add config.watchOptions = ['**/node_modules/**', '**/@mf-types/**'] to prevent loop types update
dts: this._options.dts ?? false,
shareStrategy: this._options.shareStrategy ?? 'loaded-first',
+ embedRuntime: true,
};
}
diff --git a/packages/nextjs-mf/src/plugins/NextFederationPlugin/next-fragments.ts b/packages/nextjs-mf/src/plugins/NextFederationPlugin/next-fragments.ts
index c447fab074..ef3346eedc 100644
--- a/packages/nextjs-mf/src/plugins/NextFederationPlugin/next-fragments.ts
+++ b/packages/nextjs-mf/src/plugins/NextFederationPlugin/next-fragments.ts
@@ -1,14 +1,16 @@
-import type { container, Compiler } from 'webpack';
-import type {
- ModuleFederationPluginOptions,
- SharedObject,
-} from '@module-federation/utilities';
+import type { Compiler, RuleSetRule } from 'webpack';
+import type { moduleFederationPlugin } from '@module-federation/sdk';
+import type { SharedObject } from '@module-federation/utilities';
import {
DEFAULT_SHARE_SCOPE,
DEFAULT_SHARE_SCOPE_BROWSER,
- getDelegates,
} from '../../internal';
-import { hasLoader, injectRuleLoader } from '../../loaders/helpers';
+import {
+ hasLoader,
+ injectRuleLoader,
+ findLoaderForResource,
+} from '../../loaders/helpers';
+import path from 'path';
/**
* Set up default shared values based on the environment.
@@ -25,47 +27,116 @@ export const retrieveDefaultShared = (isServer: boolean): SharedObject => {
return DEFAULT_SHARE_SCOPE_BROWSER;
};
-/**
- * Apply path fixes.
- *
- * This function applies fixes to the path for certain loaders. It checks if the fix is enabled in the options
- * and if the loader is present in the rule. If both conditions are met, it injects the fix loader.
- *
- * @param {Compiler} compiler - The Webpack compiler instance.
- * @param {any} options - The ModuleFederationPluginOptions instance.
- */
-export const applyPathFixes = (compiler: Compiler, options: any) => {
- //@ts-ignore
- compiler.options.module.rules.forEach((rule) => {
+export const applyPathFixes = (
+ compiler: Compiler,
+ pluginOptions: moduleFederationPlugin.ModuleFederationPluginOptions,
+ options: any,
+) => {
+ const match = findLoaderForResource(compiler.options.module.rules, {
+ path: path.join(compiler.context, '/something/thing.js'),
+ issuerLayer: undefined,
+ layer: undefined,
+ });
+
+ // Get ruleset from normalModuleFactory
+ // compiler.hooks.normalModuleFactory.tap('NextFederationPlugin', (nmf) => {
+ // const ruleSet = nmf.ruleSet;
+ // return;
+ // console.log(runtimeModulePath);
+ // const result = ruleSet.exec({
+ // resource: runtimeModulePath,
+ // realResource: runtimeModulePath,
+ // resourceQuery: undefined,
+ // resourceFragment: undefined,
+ // scheme: getScheme(runtimeModulePath),
+ // assertions: undefined,
+ // mimetype: 'text/javascript',
+ // dependency: 'commonjs',
+ // descriptionData: undefined,
+ // issuer: undefined,
+ // compiler: compiler.name,
+ // issuerLayer: ''
+ // });
+ // console.log(result);
+ // debugger;
+ // });
+
+ compiler.options.module.rules.forEach((rule: RuleSetRule) => {
// next-image-loader fix which adds remote's hostname to the assets url
- //@ts-ignore
if (options.enableImageLoaderFix && hasLoader(rule, 'next-image-loader')) {
- // childCompiler.options.module.parser.javascript?.url = 'relative';
- //@ts-ignore
injectRuleLoader(rule, {
loader: require.resolve('../../loaders/fixImageLoader'),
});
}
// url-loader fix for which adds remote's hostname to the assets url
- //@ts-ignore
if (options.enableUrlLoaderFix && hasLoader(rule, 'url-loader')) {
- injectRuleLoader({
+ injectRuleLoader(rule, {
loader: require.resolve('../../loaders/fixUrlLoader'),
});
}
- //@ts-ignore
- if (rule?.oneOf) {
- //@ts-ignore
- rule.oneOf.forEach((oneOfRule) => {
- if (hasLoader(oneOfRule, 'react-refresh-utils')) {
- oneOfRule.exclude = [
- oneOfRule.exclude,
- /universe\/packages/,
- /core\/packages/,
- ].filter((i) => i);
+ });
+ if (match) {
+ let matchCopy: RuleSetRule;
+
+ if (match.use) {
+ matchCopy = { ...match };
+
+ if (Array.isArray(match.use)) {
+ matchCopy.use = match.use.filter((loader: any) => {
+ return (
+ typeof loader === 'object' &&
+ loader.loader &&
+ !loader.loader.includes('react')
+ );
+ });
+ } else if (typeof match.use === 'string') {
+ if (match.use.includes('react')) {
+ matchCopy.use = '';
+ } else {
+ matchCopy.use = match.use;
+ }
+ } else if (typeof match.use === 'object' && match.use !== null) {
+ if (match.use.loader && match.use.loader.includes('react')) {
+ matchCopy.use = {};
+ } else {
+ matchCopy.use = match.use;
}
+ }
+ } else {
+ matchCopy = { ...match };
+ }
+
+ // Create the first new rule using descriptionData
+ const descriptionDataRule: RuleSetRule = {
+ ...matchCopy,
+ descriptionData: {
+ name: /^(@module-federation)/,
+ },
+ exclude: undefined,
+ include: undefined,
+ };
+
+ // Create the second new rule using test on regex for /runtimePlugin/
+ const testRule: RuleSetRule = {
+ ...matchCopy,
+ resourceQuery: /runtimePlugin/,
+ exclude: undefined,
+ include: undefined,
+ };
+
+ const oneOfRule = compiler.options.module.rules.find(
+ (rule: RuleSetRule) => {
+ return rule && typeof rule === 'object' && 'oneOf' in rule;
+ },
+ ) as RuleSetRule;
+
+ if (!oneOfRule) {
+ compiler.options.module.rules.unshift({
+ oneOf: [descriptionDataRule, testRule],
});
+ } else if (oneOfRule.oneOf) {
+ oneOfRule.oneOf.unshift(descriptionDataRule, testRule);
}
- });
+ }
};
diff --git a/packages/nextjs-mf/src/plugins/container/InvertedContainerPlugin.ts b/packages/nextjs-mf/src/plugins/container/InvertedContainerPlugin.ts
index f4ab382e44..2f13607d31 100644
--- a/packages/nextjs-mf/src/plugins/container/InvertedContainerPlugin.ts
+++ b/packages/nextjs-mf/src/plugins/container/InvertedContainerPlugin.ts
@@ -1,6 +1,5 @@
import type { Compiler } from 'webpack';
import EmbeddedContainerPlugin from './EmbeddedContainerPlugin';
-import { AsyncBoundaryPlugin } from '@module-federation/enhanced';
interface InvertedContainerOptions {
container?: string;
@@ -21,15 +20,6 @@ class InvertedContainerPlugin {
runtime: this.options.runtime,
container: this.options.container,
}).apply(compiler);
-
- new AsyncBoundaryPlugin({
- excludeChunk: (chunk) =>
- chunk.name === this.options.container ||
- chunk.name === this.options.container + '_partial',
- // @ts-ignore
- eager: (module) => /\.federation/.test(module?.request || ''),
- }).apply(compiler);
}
}
-
export default InvertedContainerPlugin;
diff --git a/packages/nextjs-mf/src/plugins/container/runtimePlugin.ts b/packages/nextjs-mf/src/plugins/container/runtimePlugin.ts
index fd0e7f8ff5..67dd9b5210 100644
--- a/packages/nextjs-mf/src/plugins/container/runtimePlugin.ts
+++ b/packages/nextjs-mf/src/plugins/container/runtimePlugin.ts
@@ -3,46 +3,65 @@ import { FederationRuntimePlugin } from '@module-federation/runtime/types';
export default function (): FederationRuntimePlugin {
return {
name: 'next-internal-plugin',
- //@ts-ignore
- createScript({ url, attrs }) {
+ createScript: function (args: {
+ url: string;
+ attrs?: Record;
+ }) {
+ // Updated type
+ var url = args.url;
+ var attrs = args.attrs;
if (typeof window !== 'undefined') {
- const script = document.createElement('script');
+ var script = document.createElement('script');
script.src = url;
script.async = true;
- //@ts-ignore
- delete attrs.crossorigin;
+ delete attrs?.['crossorigin'];
- return { script, timeout: 8000 };
+ return { script: script, timeout: 8000 };
}
return undefined;
},
- errorLoadRemote({ id, error, from, origin }) {
+ errorLoadRemote: function (args: {
+ id: string;
+ error: any;
+ from: string;
+ origin: any;
+ }) {
+ var id = args.id;
+ var error = args.error;
+ var from = args.from;
console.error(id, 'offline');
- const pg = function () {
+ var pg = function () {
console.error(id, 'offline', error);
return null;
};
- pg.getInitialProps = function (ctx: any) {
+ (pg as any).getInitialProps = function (ctx: any) {
+ // Type assertion to add getInitialProps
return {};
};
- let mod;
+ var mod;
if (from === 'build') {
- mod = () => ({
- __esModule: true,
- default: pg,
- getServerSideProps: () => ({ props: {} }),
- });
+ mod = function () {
+ return {
+ __esModule: true,
+ default: pg,
+ getServerSideProps: function () {
+ return { props: {} };
+ },
+ };
+ };
} else {
mod = {
default: pg,
- getServerSideProps: () => ({ props: {} }),
+ getServerSideProps: function () {
+ return { props: {} };
+ },
};
}
return mod;
},
- beforeInit(args) {
+ beforeInit: function (args) {
if (!globalThis.usedChunks) globalThis.usedChunks = new Set();
if (
typeof __webpack_runtime_id__ === 'string' &&
@@ -51,72 +70,73 @@ export default function (): FederationRuntimePlugin {
return args;
}
- // if (__webpack_runtime_id__ && !__webpack_runtime_id__.startsWith('webpack')) return args;
- const { moduleCache, name } = args.origin;
- const gs = new Function('return globalThis')();
- const attachedRemote = gs[name];
+ var moduleCache = args.origin.moduleCache;
+ var name = args.origin.name;
+ var gs = new Function('return globalThis')();
+ var attachedRemote = gs[name];
if (attachedRemote) {
moduleCache.set(name, attachedRemote);
}
return args;
},
- init(args) {
+ init: function (args: any) {
return args;
},
- beforeRequest: (args) => {
- const { options, id } = args;
- const remoteName = id.split('/').shift();
- const remote = options.remotes.find(
- (remote) => remote.name === remoteName,
- );
+ beforeRequest: function (args: any) {
+ var options = args.options;
+ var id = args.id;
+ var remoteName = id.split('/').shift();
+ var remote = options.remotes.find(function (remote: any) {
+ return remote.name === remoteName;
+ });
if (!remote) return args;
- //@ts-ignore
- if (remote?.entry?.includes('?t=')) {
+ if (remote && remote.entry && remote.entry.includes('?t=')) {
return args;
}
- //@ts-ignore
- remote.entry = `${remote?.entry}?t=${Date.now()}`;
+ remote.entry = remote.entry + '?t=' + Date.now();
return args;
},
- afterResolve(args) {
+ afterResolve: function (args: any) {
return args;
},
- onLoad(args) {
- const { exposeModuleFactory, exposeModule, id } = args;
- const moduleOrFactory = exposeModuleFactory || exposeModule;
+ onLoad: function (args: any) {
+ var exposeModuleFactory = args.exposeModuleFactory;
+ var exposeModule = args.exposeModule;
+ var id = args.id;
+ var moduleOrFactory = exposeModuleFactory || exposeModule;
if (!moduleOrFactory) return args; // Ensure moduleOrFactory is defined
if (typeof window === 'undefined') {
- let exposedModuleExports: any;
+ var exposedModuleExports: any;
try {
exposedModuleExports = moduleOrFactory();
} catch (e) {
exposedModuleExports = moduleOrFactory;
}
- const handler: ProxyHandler = {
- get(target, prop, receiver) {
+ var handler: ProxyHandler = {
+ get: function (target, prop, receiver) {
// Check if accessing a static property of the function itself
if (
target === exposedModuleExports &&
typeof exposedModuleExports[prop] === 'function'
) {
- return function (this: unknown, ...args: any[]) {
+ return function (this: unknown) {
globalThis.usedChunks.add(id);
- return exposedModuleExports[prop].apply(this, args);
+ return exposedModuleExports[prop].apply(this, arguments);
};
}
- const originalMethod = target[prop];
+ var originalMethod = target[prop];
if (typeof originalMethod === 'function') {
- const proxiedFunction = function (this: unknown, ...args: any[]) {
+ var proxiedFunction = function (this: unknown) {
globalThis.usedChunks.add(id);
- return originalMethod.apply(this, args);
+ return originalMethod.apply(this, arguments);
};
// Copy all enumerable properties from the original method to the proxied function
- Object.keys(originalMethod).forEach((prop) => {
+ Object.keys(originalMethod).forEach(function (prop) {
Object.defineProperty(proxiedFunction, prop, {
value: originalMethod[prop],
writable: true,
@@ -138,8 +158,8 @@ export default function (): FederationRuntimePlugin {
exposedModuleExports = new Proxy(exposedModuleExports, handler);
// Proxy static properties specifically
- const staticProps = Object.getOwnPropertyNames(exposedModuleExports);
- staticProps.forEach((prop) => {
+ var staticProps = Object.getOwnPropertyNames(exposedModuleExports);
+ staticProps.forEach(function (prop) {
if (typeof exposedModuleExports[prop] === 'function') {
exposedModuleExports[prop] = new Proxy(
exposedModuleExports[prop],
@@ -147,7 +167,9 @@ export default function (): FederationRuntimePlugin {
);
}
});
- return () => exposedModuleExports;
+ return function () {
+ return exposedModuleExports;
+ };
} else {
// For objects, just wrap the exported object itself
exposedModuleExports = new Proxy(exposedModuleExports, handler);
@@ -159,7 +181,7 @@ export default function (): FederationRuntimePlugin {
return args;
},
- resolveShare(args) {
+ resolveShare: function (args: any) {
if (
args.pkgName !== 'react' &&
args.pkgName !== 'react-dom' &&
@@ -167,8 +189,12 @@ export default function (): FederationRuntimePlugin {
) {
return args;
}
- const { shareScopeMap, scope, pkgName, version, GlobalFederation } = args;
- const host = GlobalFederation['__INSTANCES__'][0];
+ var shareScopeMap = args.shareScopeMap;
+ var scope = args.scope;
+ var pkgName = args.pkgName;
+ var version = args.version;
+ var GlobalFederation = args.GlobalFederation;
+ var host = GlobalFederation['__INSTANCES__'][0];
if (!host) {
return args;
}
@@ -176,7 +202,7 @@ export default function (): FederationRuntimePlugin {
if (!host.options.shared[pkgName]) {
return args;
}
-
+ //handle react host next remote, disable resolving when not next host
args.resolver = function () {
shareScopeMap[scope][pkgName][version] =
host.options.shared[pkgName][0]; // replace local share scope manually with desired module
@@ -184,7 +210,7 @@ export default function (): FederationRuntimePlugin {
};
return args;
},
- async beforeLoadShare(args) {
+ beforeLoadShare: async function (args: any) {
return args;
},
};
diff --git a/packages/nextjs-mf/utils/index.ts b/packages/nextjs-mf/utils/index.ts
index 13af6e110a..f3f49da9bc 100644
--- a/packages/nextjs-mf/utils/index.ts
+++ b/packages/nextjs-mf/utils/index.ts
@@ -4,8 +4,8 @@
*/
export { extractUrlAndGlobal } from '@module-federation/utilities';
import { injectScript as injectLegacy } from '@module-federation/utilities';
-//@ts-ignore
-export const injectScript = (args) => {
+
+export const injectScript = function (args: any): any {
console.error(
'@module-federation/utilities injectScript is deprecated, use module-federation/runtime {init,loadRemote}',
);
@@ -16,7 +16,6 @@ export const injectScript = (args) => {
* Flushes chunks from the module federation node utilities.
* @module @module-federation/node/utils
*/
-// @ts-ignore
export { flushChunks } from '@module-federation/node/utils';
/**
@@ -35,16 +34,15 @@ export type { FlushedChunksProps } from './flushedChunks';
* If the function is called on the server side, it imports the revalidate function from the module federation node utilities and returns the result of calling that function.
* @returns {Promise} A promise that resolves with a boolean.
*/
-export const revalidate = (
+export const revalidate = function (
fetchModule: any = undefined,
force: boolean = false,
-) => {
+): Promise {
if (typeof window !== 'undefined') {
console.error('revalidate should only be called server-side');
return Promise.resolve(false);
}
- // @ts-ignore
- return import('@module-federation/node/utils').then((utils) => {
+ return import('@module-federation/node/utils').then(function (utils) {
return utils.revalidate(fetchModule, force);
});
};
diff --git a/packages/node/src/plugins/ChunkCorrelationPlugin.js b/packages/node/src/plugins/ChunkCorrelationPlugin.js
index e3412273ef..29d4a3ccfc 100644
--- a/packages/node/src/plugins/ChunkCorrelationPlugin.js
+++ b/packages/node/src/plugins/ChunkCorrelationPlugin.js
@@ -413,7 +413,6 @@ class FederationStatsPlugin {
);
if (!federationPlugins || federationPlugins.length === 0) {
- console.error('No ModuleFederationPlugin(s) found.');
return;
}
diff --git a/packages/runtime/.swcrc b/packages/runtime/.swcrc
index 2b61b980ff..28e88ec1cd 100644
--- a/packages/runtime/.swcrc
+++ b/packages/runtime/.swcrc
@@ -11,7 +11,7 @@
"legacyDecorator": true
},
"keepClassNames": true,
- "externalHelpers": false,
+ "externalHelpers": true,
"loose": true
},
"module": {
diff --git a/packages/runtime/package.json b/packages/runtime/package.json
index 00726123ea..cb3e9579df 100644
--- a/packages/runtime/package.json
+++ b/packages/runtime/package.json
@@ -34,6 +34,11 @@
"import": "./dist/retry-plugin.esm.js",
"require": "./dist/retry-plugin.cjs.js"
},
+ "./embedded": {
+ "types": "./dist/embedded.cjs.d.ts",
+ "import": "./dist/embedded.esm.js",
+ "require": "./dist/embedded.cjs.js"
+ },
"./*": "./*"
},
"typesVersions": {
diff --git a/packages/runtime/project.json b/packages/runtime/project.json
index 2e76d95899..ebdcc7904a 100644
--- a/packages/runtime/project.json
+++ b/packages/runtime/project.json
@@ -13,7 +13,8 @@
"main": "packages/runtime/src/index.ts",
"additionalEntryPoints": [
"packages/runtime/src/types.ts",
- "packages/runtime/src/helpers.ts"
+ "packages/runtime/src/helpers.ts",
+ "packages/runtime/src/embedded.ts"
],
"tsConfig": "packages/runtime/tsconfig.lib.json",
"assets": [],
@@ -21,9 +22,7 @@
"compiler": "swc",
"rollupConfig": "packages/runtime/rollup.config.js",
"format": ["cjs", "esm"],
- "external": ["@module-federation/*"],
- "buildableProjectDepsInPackageJsonType": "dependencies",
- "updateBuildableProjectDepsInPackageJson": true
+ "external": ["@module-federation/", "@swc"]
},
"dependsOn": [
{
diff --git a/packages/runtime/rollup.config.js b/packages/runtime/rollup.config.js
index 58d7060c21..9b45240e36 100644
--- a/packages/runtime/rollup.config.js
+++ b/packages/runtime/rollup.config.js
@@ -9,6 +9,7 @@ module.exports = (rollupConfig, projectOptions) => {
types: 'packages/runtime/src/types.ts',
helpers: 'packages/runtime/src/helpers.ts',
'retry-plugin': 'packages/runtime/src/plugins/retry-plugin.ts',
+ embedded: 'packages/runtime/src/embedded.ts',
};
const project = projectOptions.project;
diff --git a/packages/runtime/src/embedded.ts b/packages/runtime/src/embedded.ts
new file mode 100644
index 0000000000..0c628c4f8e
--- /dev/null
+++ b/packages/runtime/src/embedded.ts
@@ -0,0 +1,34 @@
+const {
+ FederationHost,
+ registerGlobalPlugins,
+ getRemoteEntry,
+ getRemoteInfo,
+ loadScript,
+ loadScriptNode,
+ init,
+ loadRemote,
+ loadShare,
+ loadShareSync,
+ preloadRemote,
+ registerRemotes,
+ registerPlugins,
+ getInstance,
+ //@ts-ignore
+} = __webpack_require__.federation.runtime;
+
+export {
+ FederationHost,
+ registerGlobalPlugins,
+ getRemoteEntry,
+ getRemoteInfo,
+ loadScript,
+ loadScriptNode,
+ init,
+ loadRemote,
+ loadShare,
+ loadShareSync,
+ preloadRemote,
+ registerRemotes,
+ registerPlugins,
+ getInstance,
+};
diff --git a/packages/runtime/src/utils/env.ts b/packages/runtime/src/utils/env.ts
index 40cd0d8544..94fa980ebb 100644
--- a/packages/runtime/src/utils/env.ts
+++ b/packages/runtime/src/utils/env.ts
@@ -1,3 +1,5 @@
+export { isBrowserEnv, isDebugMode } from '@module-federation/sdk';
+
export function isDevelopmentMode(): boolean {
return true;
}
diff --git a/packages/sdk/project.json b/packages/sdk/project.json
index 5c889f5fa7..2a52a0fb98 100644
--- a/packages/sdk/project.json
+++ b/packages/sdk/project.json
@@ -12,7 +12,7 @@
"main": "packages/sdk/src/index.ts",
"tsConfig": "packages/sdk/tsconfig.lib.json",
"assets": [],
- "external": ["@module-federation/*"],
+ "external": ["@module-federation/*", "@swc"],
"project": "packages/sdk/package.json",
"additionalEntryPoints": ["packages/sdk/src/normalize-webpack-path.ts"],
"rollupConfig": "packages/sdk/rollup.config.js",
diff --git a/packages/sdk/src/types/plugins/ModuleFederationPlugin.ts b/packages/sdk/src/types/plugins/ModuleFederationPlugin.ts
index 70ebceee0e..ee32841b08 100644
--- a/packages/sdk/src/types/plugins/ModuleFederationPlugin.ts
+++ b/packages/sdk/src/types/plugins/ModuleFederationPlugin.ts
@@ -228,6 +228,7 @@ export interface ModuleFederationPluginOptions {
dts?: boolean | PluginDtsOptions;
async?: boolean | AsyncBoundaryOptions;
virtualRuntimeEntry?: boolean;
+ embedRuntime?: boolean;
}
/**
* Modules that should be exposed by this container. Property names are used as public paths.
diff --git a/packages/typescript/src/plugins/FederatedTypesPlugin.ts b/packages/typescript/src/plugins/FederatedTypesPlugin.ts
index 685c3a6031..34b5dc74de 100644
--- a/packages/typescript/src/plugins/FederatedTypesPlugin.ts
+++ b/packages/typescript/src/plugins/FederatedTypesPlugin.ts
@@ -109,7 +109,6 @@ export class FederatedTypesPlugin {
compiler.hooks.watchRun.tap(PLUGIN_NAME, () => {
isServe = true;
});
-
compiler.hooks.beforeCompile.tapAsync(
PLUGIN_NAME,
async (params: unknown, callback: InnerCallback) => {
diff --git a/packages/typescript/tsconfig.json b/packages/typescript/tsconfig.json
index bdfa011dff..12b73bad73 100644
--- a/packages/typescript/tsconfig.json
+++ b/packages/typescript/tsconfig.json
@@ -4,7 +4,6 @@
"module": "commonjs",
"forceConsistentCasingInFileNames": true,
"strict": true,
- "force": true,
"noImplicitOverride": true,
"noPropertyAccessFromIndexSignature": true,
"noImplicitReturns": true,
diff --git a/packages/utilities/src/plugins/DelegateModulesPlugin.ts b/packages/utilities/src/plugins/DelegateModulesPlugin.ts
index a8ac7a5cef..59bb37408d 100644
--- a/packages/utilities/src/plugins/DelegateModulesPlugin.ts
+++ b/packages/utilities/src/plugins/DelegateModulesPlugin.ts
@@ -1,4 +1,10 @@
-import type { Compiler, Compilation, Chunk, NormalModule } from 'webpack';
+import type {
+ Compiler,
+ Compilation,
+ Chunk,
+ NormalModule,
+ Module,
+} from 'webpack';
class DelegateModulesPlugin {
options: { debug: boolean; [key: string]: any };
@@ -62,14 +68,13 @@ class DelegateModulesPlugin {
}
}
}
-
apply(compiler: Compiler): void {
compiler.hooks.thisCompilation.tap(
'DelegateModulesPlugin',
(compilation: Compilation) => {
compilation.hooks.finishModules.tapAsync(
'DelegateModulesPlugin',
- (modules, callback) => {
+ (modules: Iterable, callback: () => void) => {
const { remotes } = this.options;
const knownDelegates = new Set(
remotes
@@ -103,7 +108,7 @@ class DelegateModulesPlugin {
compilation.hooks.optimizeChunks.tap(
'DelegateModulesPlugin',
- (chunks) => {
+ (chunks: Iterable) => {
const { runtime, container } = this.options;
const runtimeChunk = this.getChunkByName(chunks, runtime);
if (!runtimeChunk || !runtimeChunk.hasRuntime()) {
diff --git a/packages/webpack-bundler-runtime/package.json b/packages/webpack-bundler-runtime/package.json
index d59aed1653..7fd9b84844 100644
--- a/packages/webpack-bundler-runtime/package.json
+++ b/packages/webpack-bundler-runtime/package.json
@@ -36,6 +36,10 @@
"import": "./dist/container.esm.js",
"require": "./dist/container.cjs.js"
},
+ "./vendor": {
+ "import": "./dist/vendored.esm.js",
+ "require": "./dist/vendored.cjs.js"
+ },
"./*": "./*"
},
"typesVersions": {
@@ -49,6 +53,9 @@
}
},
"devDependencies": {
- "@module-federation/runtime": "workspace:*"
+ "@module-federation/runtime": "workspace:*",
+ "@rollup/plugin-swc": "^0.3.1",
+ "rollup-plugin-cleanup": "^3.2.1",
+ "rollup": "4.21.0"
}
}
diff --git a/packages/webpack-bundler-runtime/project.json b/packages/webpack-bundler-runtime/project.json
index 62e684b30e..9c99d1fd08 100644
--- a/packages/webpack-bundler-runtime/project.json
+++ b/packages/webpack-bundler-runtime/project.json
@@ -20,7 +20,7 @@
"packages/webpack-bundler-runtime/src/constant.ts",
"packages/webpack-bundler-runtime/src/container.ts"
],
- "external": ["@module-federation/*"],
+ "external": ["@module-federation/*", "@swc"],
"buildableProjectDepsInPackageJsonType": "dependencies",
"updateBuildableProjectDepsInPackageJson": true,
"rollupConfig": "packages/webpack-bundler-runtime/rollup.config.js"
diff --git a/packages/webpack-bundler-runtime/rollup.config.js b/packages/webpack-bundler-runtime/rollup.config.js
index 11a4a6cf68..ed3eebb34f 100644
--- a/packages/webpack-bundler-runtime/rollup.config.js
+++ b/packages/webpack-bundler-runtime/rollup.config.js
@@ -1,5 +1,8 @@
const copy = require('rollup-plugin-copy');
-
+const { rollup } = require('rollup');
+const swc = require('@rollup/plugin-swc');
+const cleanup = require('rollup-plugin-cleanup');
+const fs = require('fs');
module.exports = (rollupConfig, projectOptions) => {
rollupConfig.plugins.push(
copy({
@@ -12,5 +15,77 @@ module.exports = (rollupConfig, projectOptions) => {
}),
);
+ const currentPlugins = Array.from(
+ rollupConfig.plugins.filter(
+ (p) =>
+ p.name !== 'nx-swc' &&
+ p.name !== 'dts-bundle' &&
+ p.name !== 'peer-deps-external',
+ ),
+ );
+ currentPlugins.push(
+ swc({
+ swc: {
+ jsc: {
+ parser: {
+ syntax: 'typescript',
+ jsx: false,
+ dynamicImport: true,
+ privateMethod: false,
+ functionBind: false,
+ exportDefaultFrom: false,
+ exportNamespaceFrom: false,
+ decorators: false,
+ decoratorsBeforeExport: false,
+ topLevelAwait: false,
+ importMeta: false,
+ preserveAllComments: false,
+ },
+ transform: null,
+ target: rollupConfig.output.format === 'cjs' ? 'es5' : 'es2020',
+ loose: false,
+ externalHelpers: true,
+ // Requires v1.2.50 or upper and requires target to be es2016 or upper.
+ keepClassNames: false,
+ minify: {
+ compress: false,
+ format: {
+ comments: false,
+ },
+ },
+ },
+ env: null,
+ minify: false,
+ },
+ }),
+ );
+ // Custom plugin to add a new child compile
+ rollupConfig.plugins.push({
+ name: 'child-compile',
+ buildEnd: async () => {
+ const childConfig = {
+ ...rollupConfig,
+ input: projectOptions.main,
+ output: {
+ file:
+ projectOptions.outputPath +
+ `/vendored.${rollupConfig.output.format}.js`,
+ format: rollupConfig.output.format,
+ },
+ plugins: currentPlugins,
+ external: [/@swc/],
+ };
+ const bundle = await rollup(childConfig);
+ await bundle.write(childConfig.output);
+ let content = fs.readFileSync(
+ projectOptions.outputPath +
+ `/vendored.${rollupConfig.output.format}.js`,
+ 'utf-8',
+ );
+ content = content.replace(/\/\*[\s\S]*?\*\//g, '');
+ fs.writeFileSync(projectOptions.outputPath + '/vendored.js', content);
+ },
+ });
+
return rollupConfig;
};
diff --git a/packages/webpack-bundler-runtime/src/index.ts b/packages/webpack-bundler-runtime/src/index.ts
index 656367d38b..f206ea7076 100644
--- a/packages/webpack-bundler-runtime/src/index.ts
+++ b/packages/webpack-bundler-runtime/src/index.ts
@@ -6,7 +6,6 @@ import { initializeSharing } from './initializeSharing';
import { installInitialConsumes } from './installInitialConsumes';
import { attachShareScopeMap } from './attachShareScopeMap';
import { initContainerEntry } from './initContainerEntry';
-
export * from './types';
const federation: Federation = {
@@ -24,4 +23,5 @@ const federation: Federation = {
attachShareScopeMap,
bundlerRuntimeOptions: {},
};
+
export default federation;
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index fb3e37faa9..8db785c1ba 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -574,6 +574,9 @@ importers:
'@module-federation/nextjs-mf':
specifier: workspace:*
version: link:../../packages/nextjs-mf
+ '@module-federation/runtime':
+ specifier: workspace:*
+ version: link:../../packages/runtime
'@module-federation/utilities':
specifier: workspace:*
version: link:../../packages/utilities
@@ -2212,6 +2215,9 @@ importers:
'@types/btoa':
specifier: ^1.2.5
version: 1.2.5
+ '@types/enhanced-resolve':
+ specifier: ^5.0.0
+ version: 5.0.0
packages/esbuild:
dependencies:
@@ -2422,6 +2428,9 @@ importers:
'@module-federation/utilities':
specifier: workspace:*
version: link:../utilities
+ '@module-federation/webpack-bundler-runtime':
+ specifier: workspace:*
+ version: link:../webpack-bundler-runtime
fast-glob:
specifier: ^3.2.11
version: 3.3.2
@@ -2609,6 +2618,16 @@ importers:
'@module-federation/sdk':
specifier: workspace:*
version: link:../sdk
+ devDependencies:
+ '@rollup/plugin-swc':
+ specifier: ^0.3.1
+ version: 0.3.1(@swc/core@1.6.13)(rollup@4.21.0)
+ rollup:
+ specifier: 4.21.0
+ version: 4.21.0
+ rollup-plugin-cleanup:
+ specifier: ^3.2.1
+ version: 3.2.1(rollup@4.21.0)
webpack:
dependencies:
@@ -14111,6 +14130,22 @@ packages:
magic-string: 0.30.10
rollup: 2.79.1
+ /@rollup/plugin-swc@0.3.1(@swc/core@1.6.13)(rollup@4.21.0):
+ resolution: {integrity: sha512-oqHt6W2J3CoIrdWpbLiRXdRkepEv+qwCgHMnSmh7waPFxaEeO3tocA1xy2p2qoJmk1zygDoxtPeP95z8bsJ+fA==}
+ engines: {node: '>=14.0.0'}
+ peerDependencies:
+ '@swc/core': ^1.3.0
+ rollup: ^3.0.0||^4.0.0
+ peerDependenciesMeta:
+ rollup:
+ optional: true
+ dependencies:
+ '@rollup/pluginutils': 5.1.0(rollup@4.21.0)
+ '@swc/core': 1.6.13(@swc/helpers@0.5.12)
+ rollup: 4.21.0
+ smob: 1.5.0
+ dev: true
+
/@rollup/pluginutils@3.1.0(rollup@2.79.1):
resolution: {integrity: sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==}
engines: {node: '>= 8.0.0'}
@@ -14152,6 +14187,21 @@ packages:
picomatch: 2.3.1
rollup: 2.79.1
+ /@rollup/pluginutils@5.1.0(rollup@4.21.0):
+ resolution: {integrity: sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==}
+ engines: {node: '>=14.0.0'}
+ peerDependencies:
+ rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0
+ peerDependenciesMeta:
+ rollup:
+ optional: true
+ dependencies:
+ '@types/estree': 1.0.5
+ estree-walker: 2.0.2
+ picomatch: 2.3.1
+ rollup: 4.21.0
+ dev: true
+
/@rollup/rollup-android-arm-eabi@4.19.0:
resolution: {integrity: sha512-JlPfZ/C7yn5S5p0yKk7uhHTTnFlvTgLetl2VxqE518QgyM7C9bSfFTYvB/Q/ftkq0RIPY4ySxTz+/wKJ/dXC0w==}
cpu: [arm]
@@ -14159,6 +14209,14 @@ packages:
requiresBuild: true
optional: true
+ /@rollup/rollup-android-arm-eabi@4.21.0:
+ resolution: {integrity: sha512-WTWD8PfoSAJ+qL87lE7votj3syLavxunWhzCnx3XFxFiI/BA/r3X7MUM8dVrH8rb2r4AiO8jJsr3ZjdaftmnfA==}
+ cpu: [arm]
+ os: [android]
+ requiresBuild: true
+ dev: true
+ optional: true
+
/@rollup/rollup-android-arm64@4.19.0:
resolution: {integrity: sha512-RDxUSY8D1tWYfn00DDi5myxKgOk6RvWPxhmWexcICt/MEC6yEMr4HNCu1sXXYLw8iAsg0D44NuU+qNq7zVWCrw==}
cpu: [arm64]
@@ -14166,6 +14224,14 @@ packages:
requiresBuild: true
optional: true
+ /@rollup/rollup-android-arm64@4.21.0:
+ resolution: {integrity: sha512-a1sR2zSK1B4eYkiZu17ZUZhmUQcKjk2/j9Me2IDjk1GHW7LB5Z35LEzj9iJch6gtUfsnvZs1ZNyDW2oZSThrkA==}
+ cpu: [arm64]
+ os: [android]
+ requiresBuild: true
+ dev: true
+ optional: true
+
/@rollup/rollup-darwin-arm64@4.19.0:
resolution: {integrity: sha512-emvKHL4B15x6nlNTBMtIaC9tLPRpeA5jMvRLXVbl/W9Ie7HhkrE7KQjvgS9uxgatL1HmHWDXk5TTS4IaNJxbAA==}
cpu: [arm64]
@@ -14173,6 +14239,14 @@ packages:
requiresBuild: true
optional: true
+ /@rollup/rollup-darwin-arm64@4.21.0:
+ resolution: {integrity: sha512-zOnKWLgDld/svhKO5PD9ozmL6roy5OQ5T4ThvdYZLpiOhEGY+dp2NwUmxK0Ld91LrbjrvtNAE0ERBwjqhZTRAA==}
+ cpu: [arm64]
+ os: [darwin]
+ requiresBuild: true
+ dev: true
+ optional: true
+
/@rollup/rollup-darwin-x64@4.19.0:
resolution: {integrity: sha512-fO28cWA1dC57qCd+D0rfLC4VPbh6EOJXrreBmFLWPGI9dpMlER2YwSPZzSGfq11XgcEpPukPTfEVFtw2q2nYJg==}
cpu: [x64]
@@ -14180,6 +14254,14 @@ packages:
requiresBuild: true
optional: true
+ /@rollup/rollup-darwin-x64@4.21.0:
+ resolution: {integrity: sha512-7doS8br0xAkg48SKE2QNtMSFPFUlRdw9+votl27MvT46vo44ATBmdZdGysOevNELmZlfd+NEa0UYOA8f01WSrg==}
+ cpu: [x64]
+ os: [darwin]
+ requiresBuild: true
+ dev: true
+ optional: true
+
/@rollup/rollup-linux-arm-gnueabihf@4.19.0:
resolution: {integrity: sha512-2Rn36Ubxdv32NUcfm0wB1tgKqkQuft00PtM23VqLuCUR4N5jcNWDoV5iBC9jeGdgS38WK66ElncprqgMUOyomw==}
cpu: [arm]
@@ -14187,6 +14269,14 @@ packages:
requiresBuild: true
optional: true
+ /@rollup/rollup-linux-arm-gnueabihf@4.21.0:
+ resolution: {integrity: sha512-pWJsfQjNWNGsoCq53KjMtwdJDmh/6NubwQcz52aEwLEuvx08bzcy6tOUuawAOncPnxz/3siRtd8hiQ32G1y8VA==}
+ cpu: [arm]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
/@rollup/rollup-linux-arm-musleabihf@4.19.0:
resolution: {integrity: sha512-gJuzIVdq/X1ZA2bHeCGCISe0VWqCoNT8BvkQ+BfsixXwTOndhtLUpOg0A1Fcx/+eA6ei6rMBzlOz4JzmiDw7JQ==}
cpu: [arm]
@@ -14194,6 +14284,14 @@ packages:
requiresBuild: true
optional: true
+ /@rollup/rollup-linux-arm-musleabihf@4.21.0:
+ resolution: {integrity: sha512-efRIANsz3UHZrnZXuEvxS9LoCOWMGD1rweciD6uJQIx2myN3a8Im1FafZBzh7zk1RJ6oKcR16dU3UPldaKd83w==}
+ cpu: [arm]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
/@rollup/rollup-linux-arm64-gnu@4.19.0:
resolution: {integrity: sha512-0EkX2HYPkSADo9cfeGFoQ7R0/wTKb7q6DdwI4Yn/ULFE1wuRRCHybxpl2goQrx4c/yzK3I8OlgtBu4xvted0ug==}
cpu: [arm64]
@@ -14201,6 +14299,14 @@ packages:
requiresBuild: true
optional: true
+ /@rollup/rollup-linux-arm64-gnu@4.21.0:
+ resolution: {integrity: sha512-ZrPhydkTVhyeGTW94WJ8pnl1uroqVHM3j3hjdquwAcWnmivjAwOYjTEAuEDeJvGX7xv3Z9GAvrBkEzCgHq9U1w==}
+ cpu: [arm64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
/@rollup/rollup-linux-arm64-musl@4.19.0:
resolution: {integrity: sha512-GlIQRj9px52ISomIOEUq/IojLZqzkvRpdP3cLgIE1wUWaiU5Takwlzpz002q0Nxxr1y2ZgxC2obWxjr13lvxNQ==}
cpu: [arm64]
@@ -14208,6 +14314,14 @@ packages:
requiresBuild: true
optional: true
+ /@rollup/rollup-linux-arm64-musl@4.21.0:
+ resolution: {integrity: sha512-cfaupqd+UEFeURmqNP2eEvXqgbSox/LHOyN9/d2pSdV8xTrjdg3NgOFJCtc1vQ/jEke1qD0IejbBfxleBPHnPw==}
+ cpu: [arm64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
/@rollup/rollup-linux-powerpc64le-gnu@4.19.0:
resolution: {integrity: sha512-N6cFJzssruDLUOKfEKeovCKiHcdwVYOT1Hs6dovDQ61+Y9n3Ek4zXvtghPPelt6U0AH4aDGnDLb83uiJMkWYzQ==}
cpu: [ppc64]
@@ -14215,6 +14329,14 @@ packages:
requiresBuild: true
optional: true
+ /@rollup/rollup-linux-powerpc64le-gnu@4.21.0:
+ resolution: {integrity: sha512-ZKPan1/RvAhrUylwBXC9t7B2hXdpb/ufeu22pG2psV7RN8roOfGurEghw1ySmX/CmDDHNTDDjY3lo9hRlgtaHg==}
+ cpu: [ppc64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
/@rollup/rollup-linux-riscv64-gnu@4.19.0:
resolution: {integrity: sha512-2DnD3mkS2uuam/alF+I7M84koGwvn3ZVD7uG+LEWpyzo/bq8+kKnus2EVCkcvh6PlNB8QPNFOz6fWd5N8o1CYg==}
cpu: [riscv64]
@@ -14222,6 +14344,14 @@ packages:
requiresBuild: true
optional: true
+ /@rollup/rollup-linux-riscv64-gnu@4.21.0:
+ resolution: {integrity: sha512-H1eRaCwd5E8eS8leiS+o/NqMdljkcb1d6r2h4fKSsCXQilLKArq6WS7XBLDu80Yz+nMqHVFDquwcVrQmGr28rg==}
+ cpu: [riscv64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
/@rollup/rollup-linux-s390x-gnu@4.19.0:
resolution: {integrity: sha512-D6pkaF7OpE7lzlTOFCB2m3Ngzu2ykw40Nka9WmKGUOTS3xcIieHe82slQlNq69sVB04ch73thKYIWz/Ian8DUA==}
cpu: [s390x]
@@ -14229,6 +14359,14 @@ packages:
requiresBuild: true
optional: true
+ /@rollup/rollup-linux-s390x-gnu@4.21.0:
+ resolution: {integrity: sha512-zJ4hA+3b5tu8u7L58CCSI0A9N1vkfwPhWd/puGXwtZlsB5bTkwDNW/+JCU84+3QYmKpLi+XvHdmrlwUwDA6kqw==}
+ cpu: [s390x]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
/@rollup/rollup-linux-x64-gnu@4.19.0:
resolution: {integrity: sha512-HBndjQLP8OsdJNSxpNIN0einbDmRFg9+UQeZV1eiYupIRuZsDEoeGU43NQsS34Pp166DtwQOnpcbV/zQxM+rWA==}
cpu: [x64]
@@ -14236,6 +14374,14 @@ packages:
requiresBuild: true
optional: true
+ /@rollup/rollup-linux-x64-gnu@4.21.0:
+ resolution: {integrity: sha512-e2hrvElFIh6kW/UNBQK/kzqMNY5mO+67YtEh9OA65RM5IJXYTWiXjX6fjIiPaqOkBthYF1EqgiZ6OXKcQsM0hg==}
+ cpu: [x64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
/@rollup/rollup-linux-x64-musl@4.19.0:
resolution: {integrity: sha512-HxfbvfCKJe/RMYJJn0a12eiOI9OOtAUF4G6ozrFUK95BNyoJaSiBjIOHjZskTUffUrB84IPKkFG9H9nEvJGW6A==}
cpu: [x64]
@@ -14243,6 +14389,14 @@ packages:
requiresBuild: true
optional: true
+ /@rollup/rollup-linux-x64-musl@4.21.0:
+ resolution: {integrity: sha512-1vvmgDdUSebVGXWX2lIcgRebqfQSff0hMEkLJyakQ9JQUbLDkEaMsPTLOmyccyC6IJ/l3FZuJbmrBw/u0A0uCQ==}
+ cpu: [x64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
/@rollup/rollup-win32-arm64-msvc@4.19.0:
resolution: {integrity: sha512-HxDMKIhmcguGTiP5TsLNolwBUK3nGGUEoV/BO9ldUBoMLBssvh4J0X8pf11i1fTV7WShWItB1bKAKjX4RQeYmg==}
cpu: [arm64]
@@ -14250,6 +14404,14 @@ packages:
requiresBuild: true
optional: true
+ /@rollup/rollup-win32-arm64-msvc@4.21.0:
+ resolution: {integrity: sha512-s5oFkZ/hFcrlAyBTONFY1TWndfyre1wOMwU+6KCpm/iatybvrRgmZVM+vCFwxmC5ZhdlgfE0N4XorsDpi7/4XQ==}
+ cpu: [arm64]
+ os: [win32]
+ requiresBuild: true
+ dev: true
+ optional: true
+
/@rollup/rollup-win32-ia32-msvc@4.19.0:
resolution: {integrity: sha512-xItlIAZZaiG/u0wooGzRsx11rokP4qyc/79LkAOdznGRAbOFc+SfEdfUOszG1odsHNgwippUJavag/+W/Etc6Q==}
cpu: [ia32]
@@ -14257,6 +14419,14 @@ packages:
requiresBuild: true
optional: true
+ /@rollup/rollup-win32-ia32-msvc@4.21.0:
+ resolution: {integrity: sha512-G9+TEqRnAA6nbpqyUqgTiopmnfgnMkR3kMukFBDsiyy23LZvUCpiUwjTRx6ezYCjJODXrh52rBR9oXvm+Fp5wg==}
+ cpu: [ia32]
+ os: [win32]
+ requiresBuild: true
+ dev: true
+ optional: true
+
/@rollup/rollup-win32-x64-msvc@4.19.0:
resolution: {integrity: sha512-xNo5fV5ycvCCKqiZcpB65VMR11NJB+StnxHz20jdqRAktfdfzhgjTiJ2doTDQE/7dqGaV5I7ZGqKpgph6lCIag==}
cpu: [x64]
@@ -14264,6 +14434,14 @@ packages:
requiresBuild: true
optional: true
+ /@rollup/rollup-win32-x64-msvc@4.21.0:
+ resolution: {integrity: sha512-2jsCDZwtQvRhejHLfZ1JY6w6kEuEtfF9nzYsZxzSlNVKDX+DpsDJ+Rbjkm74nvg2rdx0gwBS+IMdvwJuq3S9pQ==}
+ cpu: [x64]
+ os: [win32]
+ requiresBuild: true
+ dev: true
+ optional: true
+
/@rsbuild/babel-preset@0.3.4(@rsbuild/core@0.3.11)(@swc/helpers@0.5.3):
resolution: {integrity: sha512-lGYVxjuf5SmWt10cBu/agYxpXNfFrvgcl7r9pnObWF9bRwsuaI1S+EuigjFeBUVPdNs4OMQy46sQaTpMfp4p0A==}
dependencies:
@@ -14974,8 +15152,8 @@ packages:
dependencies:
'@rsbuild/core': 0.6.15
'@rsbuild/shared': 0.6.15(@swc/helpers@0.5.12)
- vue-loader: 17.4.2(vue@3.4.34)(webpack@5.93.0)
- webpack: 5.93.0(@swc/core@1.6.13)(esbuild@0.23.0)
+ vue-loader: 17.4.2(vue@3.4.34)(webpack@5.99.1)
+ webpack: github.com/ScriptedAlchemy/webpack/df61a5c271f36ad32c8c575ff843424e4906378a(@swc/core@1.6.13)(esbuild@0.23.0)
transitivePeerDependencies:
- '@swc/core'
- '@swc/helpers'
@@ -15874,7 +16052,7 @@ packages:
'@rspack/binding': 1.0.0-alpha.3
'@rspack/lite-tapable': 1.0.0-alpha.3
'@swc/helpers': 0.5.11
- caniuse-lite: 1.0.30001643
+ caniuse-lite: 1.0.30001649
dev: false
/@rspack/core@1.0.0-alpha.5(@swc/helpers@0.5.11):
@@ -19153,6 +19331,13 @@ packages:
resolution: {integrity: sha512-cFq+fO/isvhvmuP/+Sl4K4jtU6E23DoivtbO4r50e3odaxAiVdbfSYRDdJ4gCdxx+3aRjhphS5ZMwIH4hFy/Cw==}
dev: true
+ /@types/enhanced-resolve@5.0.0:
+ resolution: {integrity: sha512-jrgQjVFFHk7lK+Dyv8Lb5agHaCzL9OQdT9aciA61fxs6KI89u5yfEM7qubHq8DdN3UnTcho+S3Lzyr5mfdLUGg==}
+ deprecated: This is a stub types definition. enhanced-resolve provides its own type definitions, so you do not need this installed.
+ dependencies:
+ enhanced-resolve: 5.17.1
+ dev: true
+
/@types/escodegen@0.0.6:
resolution: {integrity: sha512-AjwI4MvWx3HAOaZqYsjKWyEObT9lcVV0Y0V8nXo6cXzN8ZiMxVhf6F3d/UNvXVGKrEzL/Dluc5p+y9GkzlTWig==}
dev: true
@@ -22667,13 +22852,14 @@ packages:
electron-to-chromium: 1.5.1
node-releases: 2.0.18
update-browserslist-db: 1.1.0(browserslist@4.23.1)
+ dev: true
/browserslist@4.23.2:
resolution: {integrity: sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA==}
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
hasBin: true
dependencies:
- caniuse-lite: 1.0.30001643
+ caniuse-lite: 1.0.30001649
electron-to-chromium: 1.5.1
node-releases: 2.0.18
update-browserslist-db: 1.1.0(browserslist@4.23.2)
@@ -22928,7 +23114,7 @@ packages:
/caniuse-api@3.0.0:
resolution: {integrity: sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==}
dependencies:
- browserslist: 4.23.1
+ browserslist: 4.23.2
caniuse-lite: 1.0.30001649
lodash.memoize: 4.1.2
lodash.uniq: 4.5.0
@@ -25613,6 +25799,7 @@ packages:
/errno@0.1.8:
resolution: {integrity: sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==}
hasBin: true
+ requiresBuild: true
dependencies:
prr: 1.0.1
dev: true
@@ -30955,6 +31142,15 @@ packages:
resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==}
engines: {node: '>=10'}
+ /js-cleanup@1.2.0:
+ resolution: {integrity: sha512-JeDD0yiiSt80fXzAVa/crrS0JDPQljyBG/RpOtaSbyDq03VHa9szJWMaWOYU/bcTn412uMN2MxApXq8v79cUiQ==}
+ engines: {node: ^10.14.2 || >=12.0.0}
+ dependencies:
+ magic-string: 0.25.9
+ perf-regexes: 1.0.1
+ skip-regex: 1.0.2
+ dev: true
+
/js-cookie@2.2.1:
resolution: {integrity: sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==}
dev: false
@@ -35047,6 +35243,11 @@ packages:
resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==}
dev: true
+ /perf-regexes@1.0.1:
+ resolution: {integrity: sha512-L7MXxUDtqr4PUaLFCDCXBfGV/6KLIuSEccizDI7JxT+c9x1G1v04BQ4+4oag84SHaCdrBgQAIs/Cqn+flwFPng==}
+ engines: {node: '>=6.14'}
+ dev: true
+
/performance-now@2.1.0:
resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==}
dev: true
@@ -39881,7 +40082,7 @@ packages:
/reduce-configs@1.0.0:
resolution: {integrity: sha512-/JCYSgL/QeXXsq0Lv/7kOZfqvof7vyzHWfyNQPt3c6vc73mU4WRyT8RJ6ZH5Ci08vUOqXwk7jkZy6BycHTDD9w==}
dependencies:
- browserslist: 4.23.1
+ browserslist: 4.23.2
/reduce-flatten@2.0.0:
resolution: {integrity: sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==}
@@ -40419,6 +40620,17 @@ packages:
inherits: 2.0.4
dev: true
+ /rollup-plugin-cleanup@3.2.1(rollup@4.21.0):
+ resolution: {integrity: sha512-zuv8EhoO3TpnrU8MX8W7YxSbO4gmOR0ny06Lm3nkFfq0IVKdBUtHwhVzY1OAJyNCIAdLiyPnOrU0KnO0Fri1GQ==}
+ engines: {node: ^10.14.2 || >=12.0.0}
+ peerDependencies:
+ rollup: '>=2.0'
+ dependencies:
+ js-cleanup: 1.2.0
+ rollup: 4.21.0
+ rollup-pluginutils: 2.8.2
+ dev: true
+
/rollup-plugin-copy@3.5.0:
resolution: {integrity: sha512-wI8D5dvYovRMx/YYKtUNt3Yxaw4ORC9xo6Gt9t22kveWz1enG9QrhVlagzwrxSC455xD1dHMKhIJkbsQ7d48BA==}
engines: {node: '>=8.3'}
@@ -40533,6 +40745,32 @@ packages:
'@rollup/rollup-win32-x64-msvc': 4.19.0
fsevents: 2.3.3
+ /rollup@4.21.0:
+ resolution: {integrity: sha512-vo+S/lfA2lMS7rZ2Qoubi6I5hwZwzXeUIctILZLbHI+laNtvhhOIon2S1JksA5UEDQ7l3vberd0fxK44lTYjbQ==}
+ engines: {node: '>=18.0.0', npm: '>=8.0.0'}
+ hasBin: true
+ dependencies:
+ '@types/estree': 1.0.5
+ optionalDependencies:
+ '@rollup/rollup-android-arm-eabi': 4.21.0
+ '@rollup/rollup-android-arm64': 4.21.0
+ '@rollup/rollup-darwin-arm64': 4.21.0
+ '@rollup/rollup-darwin-x64': 4.21.0
+ '@rollup/rollup-linux-arm-gnueabihf': 4.21.0
+ '@rollup/rollup-linux-arm-musleabihf': 4.21.0
+ '@rollup/rollup-linux-arm64-gnu': 4.21.0
+ '@rollup/rollup-linux-arm64-musl': 4.21.0
+ '@rollup/rollup-linux-powerpc64le-gnu': 4.21.0
+ '@rollup/rollup-linux-riscv64-gnu': 4.21.0
+ '@rollup/rollup-linux-s390x-gnu': 4.21.0
+ '@rollup/rollup-linux-x64-gnu': 4.21.0
+ '@rollup/rollup-linux-x64-musl': 4.21.0
+ '@rollup/rollup-win32-arm64-msvc': 4.21.0
+ '@rollup/rollup-win32-ia32-msvc': 4.21.0
+ '@rollup/rollup-win32-x64-msvc': 4.21.0
+ fsevents: 2.3.3
+ dev: true
+
/rrweb-cssom@0.6.0:
resolution: {integrity: sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==}
dev: true
@@ -41405,6 +41643,11 @@ packages:
unicode-emoji-modifier-base: 1.0.0
dev: true
+ /skip-regex@1.0.2:
+ resolution: {integrity: sha512-pEjMUbwJ5Pl/6Vn6FsamXHXItJXSRftcibixDmNCWbWhic0hzHrwkMZo0IZ7fMRH9KxcWDFSkzhccB4285PutA==}
+ engines: {node: '>=4.2'}
+ dev: true
+
/slash@3.0.0:
resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
engines: {node: '>=8'}
@@ -41445,6 +41688,10 @@ packages:
is-fullwidth-code-point: 4.0.0
dev: true
+ /smob@1.5.0:
+ resolution: {integrity: sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==}
+ dev: true
+
/snake-case@3.0.4:
resolution: {integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==}
dependencies:
@@ -42853,6 +43100,32 @@ packages:
terser: 5.31.3
webpack: 5.93.0(@swc/core@1.6.13)(esbuild@0.23.0)
+ /terser-webpack-plugin@5.3.10(@swc/core@1.6.13)(esbuild@0.23.0)(webpack@5.99.1):
+ resolution: {integrity: sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==}
+ engines: {node: '>= 10.13.0'}
+ peerDependencies:
+ '@swc/core': '*'
+ esbuild: '*'
+ uglify-js: '*'
+ webpack: ^5.1.0
+ peerDependenciesMeta:
+ '@swc/core':
+ optional: true
+ esbuild:
+ optional: true
+ uglify-js:
+ optional: true
+ dependencies:
+ '@jridgewell/trace-mapping': 0.3.25
+ '@swc/core': 1.6.13(@swc/helpers@0.5.12)
+ esbuild: 0.23.0
+ jest-worker: 27.5.1
+ schema-utils: 3.3.0
+ serialize-javascript: 6.0.2
+ terser: 5.31.3
+ webpack: github.com/ScriptedAlchemy/webpack/df61a5c271f36ad32c8c575ff843424e4906378a(@swc/core@1.6.13)(esbuild@0.23.0)
+ dev: true
+
/terser-webpack-plugin@5.3.9(@swc/core@1.6.13)(esbuild@0.17.19)(webpack@5.93.0):
resolution: {integrity: sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==}
engines: {node: '>= 10.13.0'}
@@ -44216,6 +44489,7 @@ packages:
browserslist: 4.23.1
escalade: 3.1.2
picocolors: 1.0.1
+ dev: true
/update-browserslist-db@1.1.0(browserslist@4.23.2):
resolution: {integrity: sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==}
@@ -44952,7 +45226,7 @@ packages:
- supports-color
dev: true
- /vue-loader@17.4.2(vue@3.4.34)(webpack@5.93.0):
+ /vue-loader@17.4.2(vue@3.4.34)(webpack@5.99.1):
resolution: {integrity: sha512-yTKOA4R/VN4jqjw4y5HrynFL8AK0Z3/Jt7eOJXEitsm0GMRHDBjCfCiuTiLP7OESvsZYo2pATCWhDqxC5ZrM6w==}
peerDependencies:
'@vue/compiler-sfc': '*'
@@ -44968,7 +45242,7 @@ packages:
hash-sum: 2.0.0
vue: 3.4.34(typescript@5.5.2)
watchpack: 2.4.1
- webpack: 5.93.0(@swc/core@1.6.13)(esbuild@0.23.0)
+ webpack: github.com/ScriptedAlchemy/webpack/df61a5c271f36ad32c8c575ff843424e4906378a(@swc/core@1.6.13)(esbuild@0.23.0)
dev: true
/vue-router@4.3.2(vue@3.4.34):
@@ -46153,3 +46427,47 @@ packages:
/zwitch@2.0.4:
resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
+
+ github.com/ScriptedAlchemy/webpack/df61a5c271f36ad32c8c575ff843424e4906378a(@swc/core@1.6.13)(esbuild@0.23.0):
+ resolution: {tarball: https://codeload.github.com/ScriptedAlchemy/webpack/tar.gz/df61a5c271f36ad32c8c575ff843424e4906378a}
+ id: github.com/ScriptedAlchemy/webpack/df61a5c271f36ad32c8c575ff843424e4906378a
+ name: webpack
+ version: 5.99.1
+ engines: {node: '>=10.13.0'}
+ hasBin: true
+ requiresBuild: true
+ peerDependencies:
+ webpack-cli: '*'
+ peerDependenciesMeta:
+ webpack-cli:
+ optional: true
+ dependencies:
+ '@types/eslint-scope': 3.7.7
+ '@types/estree': 1.0.5
+ '@webassemblyjs/ast': 1.12.1
+ '@webassemblyjs/wasm-edit': 1.12.1
+ '@webassemblyjs/wasm-parser': 1.12.1
+ acorn: 8.12.1
+ acorn-import-attributes: 1.9.5(acorn@8.12.1)
+ browserslist: 4.23.2
+ chrome-trace-event: 1.0.4
+ enhanced-resolve: 5.17.1
+ es-module-lexer: 1.5.4
+ eslint-scope: 5.1.1
+ events: 3.3.0
+ glob-to-regexp: 0.4.1
+ graceful-fs: 4.2.11
+ json-parse-even-better-errors: 2.3.1
+ loader-runner: 4.3.0
+ mime-types: 2.1.35
+ neo-async: 2.6.2
+ schema-utils: 3.3.0
+ tapable: 2.2.1
+ terser-webpack-plugin: 5.3.10(@swc/core@1.6.13)(esbuild@0.23.0)(webpack@5.99.1)
+ watchpack: 2.4.1
+ webpack-sources: 3.2.3
+ transitivePeerDependencies:
+ - '@swc/core'
+ - esbuild
+ - uglify-js
+ dev: true
diff --git a/webpack/lib/NormalModule.d.ts b/webpack/lib/NormalModule.d.ts
index e6cb8f59b9..c709f78f33 100644
--- a/webpack/lib/NormalModule.d.ts
+++ b/webpack/lib/NormalModule.d.ts
@@ -36,12 +36,14 @@ declare class NormalModule extends Module {
rawRequest: string;
/** @type {boolean} */
binary: boolean;
- /** @type {Parser} */
- parser: Parser;
- parserOptions: Record;
- /** @type {Generator} */
- generator: Generator;
- generatorOptions: Record;
+ /** @type {undefined | Parser} */
+ parser: undefined | Parser;
+ /** @type {undefined | ParserOptions} */
+ parserOptions: undefined | ParserOptions;
+ /** @type {undefined | Generator} */
+ generator: undefined | Generator;
+ /** @type {undefined | GeneratorOptions} */
+ generatorOptions: undefined | GeneratorOptions;
/** @type {string} */
resource: string;
resourceResolveData: Record;
@@ -49,13 +51,22 @@ declare class NormalModule extends Module {
matchResource: string | undefined;
/** @type {LoaderItem[]} */
loaders: LoaderItem[];
- /** @type {(WebpackError | null)=} */
- error: (WebpackError | null) | undefined;
- /** @private @type {Source=} */
+ /** @type {WebpackError | null} */
+ error: WebpackError | null;
+ /**
+ * @private
+ * @type {Source | null}
+ */
private _source;
- /** @private @type {Map | undefined} **/
+ /**
+ * @private
+ * @type {Map | undefined}
+ */
private _sourceSizes;
- /** @private @type {Set} */
+ /**
+ * @private
+ * @type {undefined | SourceTypes}
+ */
private _sourceTypes;
_lastSuccessfulBuildMeta: {};
_forceBuild: boolean;
@@ -64,52 +75,60 @@ declare class NormalModule extends Module {
_addedSideEffectsBailout: WeakSet | undefined;
/** @type {Map} */
_codeGeneratorData: Map;
- context: any;
- restoreFromUnsafeCache(unsafeCacheData: any, normalModuleFactory: any): void;
+ /**
+ * restore unsafe cache data
+ * @param {NormalModuleUnsafeCacheData} unsafeCacheData data from getUnsafeCacheData
+ * @param {NormalModuleFactory} normalModuleFactory the normal module factory handling the unsafe caching
+ */
+ restoreFromUnsafeCache(
+ unsafeCacheData: NormalModuleUnsafeCacheData,
+ normalModuleFactory: NormalModuleFactory,
+ ): void;
/**
* @param {string} context the compilation context
* @param {string} name the asset name
- * @param {string} content the content
- * @param {string | TODO} sourceMap an optional source map
- * @param {Object=} associatedObjectForCache object for caching
+ * @param {string | Buffer} content the content
+ * @param {(string | SourceMap)=} sourceMap an optional source map
+ * @param {object=} associatedObjectForCache object for caching
* @returns {Source} the created source
*/
createSourceForAsset(
context: string,
name: string,
- content: string,
- sourceMap: string | TODO,
- associatedObjectForCache?: any | undefined,
- ): any;
+ content: string | Buffer,
+ sourceMap?: (string | SourceMap) | undefined,
+ associatedObjectForCache?: object | undefined,
+ ): Source;
/**
+ * @private
+ * @template T
* @param {ResolverWithOptions} resolver a resolver
* @param {WebpackOptions} options webpack options
* @param {Compilation} compilation the compilation
* @param {InputFileSystem} fs file system from reading
* @param {NormalModuleCompilationHooks} hooks the hooks
- * @returns {NormalModuleLoaderContext} loader context
+ * @returns {import("../declarations/LoaderContext").NormalModuleLoaderContext} loader context
*/
- _createLoaderContext(
- resolver: ResolverWithOptions,
- options: WebpackOptions,
- compilation: Compilation,
- fs: InputFileSystem,
- hooks: NormalModuleCompilationHooks,
- ): import('../declarations/LoaderContext').NormalModuleLoaderContext;
- getCurrentLoader(loaderContext: any, index?: any): LoaderItem;
+ private _createLoaderContext;
+ /**
+ * @param {TODO} loaderContext loader context
+ * @param {number} index index
+ * @returns {LoaderItem | null} loader
+ */
+ getCurrentLoader(loaderContext: TODO, index?: number): LoaderItem | null;
/**
* @param {string} context the compilation context
* @param {string | Buffer} content the content
- * @param {string | TODO} sourceMap an optional source map
- * @param {Object=} associatedObjectForCache object for caching
+ * @param {(string | SourceMapSource | null)=} sourceMap an optional source map
+ * @param {object=} associatedObjectForCache object for caching
* @returns {Source} the created source
*/
createSource(
context: string,
content: string | Buffer,
- sourceMap: string | TODO,
- associatedObjectForCache?: any | undefined,
- ): any;
+ sourceMap?: (string | SourceMapSource | null) | undefined,
+ associatedObjectForCache?: object | undefined,
+ ): Source;
/**
* @param {WebpackOptions} options webpack options
* @param {Compilation} compilation the compilation
@@ -133,9 +152,23 @@ declare class NormalModule extends Module {
* @returns {void}
*/
markModuleAsErrored(error: WebpackError): void;
- applyNoParseRule(rule: any, content: any): any;
- shouldPreventParsing(noParseRule: any, request: any): any;
- _initBuildHash(compilation: any): void;
+ /**
+ * @param {TODO} rule rule
+ * @param {string} content content
+ * @returns {boolean} result
+ */
+ applyNoParseRule(rule: TODO, content: string): boolean;
+ /**
+ * @param {TODO} noParseRule no parse rule
+ * @param {string} request request
+ * @returns {boolean} check if module should not be parsed, returns "true" if the module should !not! be parsed, returns "false" if the module !must! be parsed
+ */
+ shouldPreventParsing(noParseRule: TODO, request: string): boolean;
+ /**
+ * @param {Compilation} compilation compilation
+ * @private
+ */
+ private _initBuildHash;
/**
* @param {Hash} hash the hash used to track dependencies
* @param {UpdateHashContext} context context
@@ -146,7 +179,6 @@ declare class NormalModule extends Module {
declare namespace NormalModule {
export {
Source,
- NormalModuleLoaderContext,
Mode,
ResolveOptions,
WebpackOptions,
@@ -155,17 +187,23 @@ declare namespace NormalModule {
UpdateHashContext,
DependencyTemplates,
Generator,
+ BuildInfo,
+ BuildMeta,
CodeGenerationContext,
CodeGenerationResult,
ConcatenationBailoutReasonContext,
+ KnownBuildInfo,
LibIdentOptions,
NeedBuildContext,
+ SourceTypes,
+ UnsafeCacheData,
ModuleGraph,
ConnectionState,
JavaScriptModuleTypes,
NormalModuleFactory,
Parser,
RequestShortener,
+ ResolveContext,
ResolverWithOptions,
RuntimeTemplate,
WebpackLogger,
@@ -174,6 +212,13 @@ declare namespace NormalModule {
Hash,
InputFileSystem,
RuntimeSpec,
+ Algorithm,
+ FakeHook,
+ ParserOptions,
+ GeneratorOptions,
+ NormalModuleUnsafeCacheData,
+ LoaderContext,
+ NormalModuleLoaderContext,
SourceMap,
LoaderItem,
NormalModuleCompilationHooks,
@@ -181,34 +226,96 @@ declare namespace NormalModule {
};
}
import Module = require('./Module');
-type Parser = import('./Parser');
+import WebpackError = require('./WebpackError');
+import { SourceMapSource } from 'webpack-sources';
+import Compilation = require('./Compilation');
+type Source = import('webpack-sources').Source;
+type Mode = import('../declarations/WebpackOptions').Mode;
+type ResolveOptions = import('../declarations/WebpackOptions').ResolveOptions;
+type WebpackOptions =
+ import('../declarations/WebpackOptions').WebpackOptionsNormalized;
+type ChunkGraph = import('./ChunkGraph');
+type Compiler = import('./Compiler');
+type UpdateHashContext = import('./Dependency').UpdateHashContext;
+type DependencyTemplates = import('./DependencyTemplates');
type Generator = import('./Generator');
+type BuildInfo = import('./Module').BuildInfo;
+type BuildMeta = import('./Module').BuildMeta;
+type CodeGenerationContext = import('./Module').CodeGenerationContext;
+type CodeGenerationResult = import('./Module').CodeGenerationResult;
+type ConcatenationBailoutReasonContext =
+ import('./Module').ConcatenationBailoutReasonContext;
+type KnownBuildInfo = import('./Module').KnownBuildInfo;
+type LibIdentOptions = import('./Module').LibIdentOptions;
+type NeedBuildContext = import('./Module').NeedBuildContext;
+type SourceTypes = import('./Module').SourceTypes;
+type UnsafeCacheData = import('./Module').UnsafeCacheData;
+type ModuleGraph = import('./ModuleGraph');
+type ConnectionState = import('./ModuleGraphConnection').ConnectionState;
+type JavaScriptModuleTypes =
+ import('./ModuleTypeConstants').JavaScriptModuleTypes;
+type NormalModuleFactory = import('./NormalModuleFactory');
+type Parser = import('./Parser');
+type RequestShortener = import('./RequestShortener');
+type ResolveContext = import('./ResolverFactory').ResolveContext;
+type ResolverWithOptions = import('./ResolverFactory').ResolverWithOptions;
+type RuntimeTemplate = import('./RuntimeTemplate');
+type WebpackLogger = import('./logging/Logger').Logger;
+type ObjectDeserializerContext =
+ import('./serialization/ObjectMiddleware').ObjectDeserializerContext;
+type ObjectSerializerContext =
+ import('./serialization/ObjectMiddleware').ObjectSerializerContext;
+type Hash = import('./util/Hash');
+type InputFileSystem = import('./util/fs').InputFileSystem;
+type RuntimeSpec = import('./util/runtime').RuntimeSpec;
+type Algorithm = import('./util/createHash').Algorithm;
+type FakeHook = import('./util/deprecation').FakeHook;
+type ParserOptions = {
+ [k: string]: any;
+};
+type GeneratorOptions = {
+ [k: string]: any;
+};
+type NormalModuleUnsafeCacheData = UnsafeCacheData & {
+ parser: undefined | Parser;
+ parserOptions: undefined | ParserOptions;
+ generator: undefined | Generator;
+ generatorOptions: undefined | GeneratorOptions;
+};
+type LoaderContext =
+ import('../declarations/LoaderContext').LoaderContext;
+type NormalModuleLoaderContext =
+ import('../declarations/LoaderContext').NormalModuleLoaderContext;
+type SourceMap = {
+ version: number;
+ sources: string[];
+ mappings: string;
+ file?: string | undefined;
+ sourceRoot?: string | undefined;
+ sourcesContent?: string[] | undefined;
+ names?: string[] | undefined;
+};
type LoaderItem = {
loader: string;
options: any;
ident: string | null;
type: string | null;
};
-import WebpackError = require('./WebpackError');
-type ModuleGraph = import('./ModuleGraph');
-type ResolverWithOptions = import('./ResolverFactory').ResolverWithOptions;
-type WebpackOptions =
- import('../declarations/WebpackOptions').WebpackOptionsNormalized;
-import Compilation = require('./Compilation');
-type InputFileSystem = import('./util/fs').InputFileSystem;
type NormalModuleCompilationHooks = {
- loader: SyncHook<[object, NormalModule]>;
- beforeLoaders: SyncHook<[LoaderItem[], NormalModule, object]>;
+ loader: SyncHook<[LoaderContext, NormalModule]>;
+ beforeLoaders: SyncHook<[LoaderItem[], NormalModule, LoaderContext]>;
beforeParse: SyncHook<[NormalModule]>;
beforeSnapshot: SyncHook<[NormalModule]>;
readResourceForScheme: HookMap<
- AsyncSeriesBailHook<[string, NormalModule], string | Buffer>
+ FakeHook<
+ AsyncSeriesBailHook<[string, NormalModule], string | Buffer | null>
+ >
+ >;
+ readResource: HookMap<
+ AsyncSeriesBailHook<[LoaderContext], string | Buffer | null>
>;
- readResource: HookMap>;
needBuild: AsyncSeriesBailHook<[NormalModule, NeedBuildContext], boolean>;
};
-type Hash = import('./util/Hash');
-type UpdateHashContext = import('./Dependency').UpdateHashContext;
type NormalModuleCreateData = {
/**
* an optional layer in which the module is
@@ -257,7 +364,7 @@ type NormalModuleCreateData = {
/**
* the options of the parser used
*/
- parserOptions?: Record | undefined;
+ parserOptions?: ParserOptions | undefined;
/**
* the generator used
*/
@@ -265,47 +372,12 @@ type NormalModuleCreateData = {
/**
* the options of the generator used
*/
- generatorOptions?: Record | undefined;
+ generatorOptions?: GeneratorOptions | undefined;
/**
* options used for resolving requests from this module
*/
resolveOptions?: ResolveOptions | undefined;
};
-type Source = any;
-type NormalModuleLoaderContext =
- import('../declarations/LoaderContext').NormalModuleLoaderContext;
-type Mode = import('../declarations/WebpackOptions').Mode;
-type ResolveOptions = import('../declarations/WebpackOptions').ResolveOptions;
-type ChunkGraph = import('./ChunkGraph');
-type Compiler = import('./Compiler');
-type DependencyTemplates = import('./DependencyTemplates');
-type CodeGenerationContext = import('./Module').CodeGenerationContext;
-type CodeGenerationResult = import('./Module').CodeGenerationResult;
-type ConcatenationBailoutReasonContext =
- import('./Module').ConcatenationBailoutReasonContext;
-type LibIdentOptions = import('./Module').LibIdentOptions;
-type NeedBuildContext = import('./Module').NeedBuildContext;
-type ConnectionState = import('./ModuleGraphConnection').ConnectionState;
-type JavaScriptModuleTypes =
- import('./ModuleTypeConstants').JavaScriptModuleTypes;
-type NormalModuleFactory = import('./NormalModuleFactory');
-type RequestShortener = import('./RequestShortener');
-type RuntimeTemplate = import('./RuntimeTemplate');
-type WebpackLogger = import('./logging/Logger').Logger;
-type ObjectDeserializerContext =
- import('./serialization/ObjectMiddleware').ObjectDeserializerContext;
-type ObjectSerializerContext =
- import('./serialization/ObjectMiddleware').ObjectSerializerContext;
-type RuntimeSpec = import('./util/runtime').RuntimeSpec;
-type SourceMap = {
- version: number;
- sources: string[];
- mappings: string;
- file?: string | undefined;
- sourceRoot?: string | undefined;
- sourcesContent?: string[] | undefined;
- names?: string[] | undefined;
-};
import { SyncHook } from 'tapable';
import { HookMap } from 'tapable';
import { AsyncSeriesBailHook } from 'tapable';
diff --git a/webpack/types.d.ts b/webpack/types.d.ts
index 986bf72e69..3e64eed797 100644
--- a/webpack/types.d.ts
+++ b/webpack/types.d.ts
@@ -5,6 +5,7 @@
*/
import Compilation from './lib/Compilation';
import Stats from './lib/Stats';
+import NormalModuleReplacementPlugin from './lib/NormalModuleReplacementPlugin';
import MultiCompiler from './lib/MultiCompiler';
import Parser from './lib/Parser';
import ModuleDependency from './lib/dependencies/ModuleDependency';
@@ -3178,24 +3179,6 @@ declare interface NormalModuleLoaderContext {
_compiler?: Compiler;
}
-declare class NormalModuleReplacementPlugin {
- /**
- * Create an instance of the plugin
- */
- constructor(
- resourceRegExp: RegExp,
- newResource: string | ((arg0: ResolveData) => void),
- );
-
- resourceRegExp: RegExp;
- newResource: string | ((arg0: ResolveData) => void);
-
- /**
- * Apply the plugin
- */
- apply(compiler: Compiler): void;
-}
-
declare class NullDependency extends Dependency {
constructor();