Skip to content
Closed
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
e22f492
feat(runtime): add shared webpack require accessor helpers
cursoragent Feb 17, 2026
dce6b4d
fix(utils): update remote container typing for helper import
cursoragent Feb 17, 2026
76c2216
refactor(runtime-core): decouple bundler ignore helper from sdk exports
cursoragent Feb 17, 2026
adff9b6
fix(utils): keep remote container type surface unchanged
cursoragent Feb 17, 2026
707aab5
fix(webpack-bundler-runtime): keep internal direct webpack require usage
cursoragent Feb 17, 2026
aa47578
refactor(utils): simplify esm remote initialization typing
cursoragent Feb 17, 2026
14d1b76
fix(webpack-bundler-runtime): use module-level webpack require accessor
cursoragent Feb 17, 2026
04ba1b4
feat(runtime-core): prefer bundler runtime import ignore helper
cursoragent Feb 17, 2026
7b274f1
refactor(webpack-bundler-runtime): keep ignore helper as standalone e…
cursoragent Feb 17, 2026
e3de5a3
Merge branch 'main' into cursor/bundler-runtime-require-access-725d
ScriptedAlchemy Feb 17, 2026
e0c0704
refactor(node): migrate runtime webpack require access to bundler acc…
cursoragent Feb 17, 2026
f953e6e
refactor: keep webpack require helpers on accessor entrypoint
cursoragent Feb 17, 2026
4c257d8
test(webpack-bundler-runtime): avoid global webpack require mutation
cursoragent Feb 17, 2026
92b7ec0
refactor(runtime-core): source bundler-ignore helper from sdk
cursoragent Feb 17, 2026
2e41604
refactor(sdk): expose bundler helper via standalone entrypoint
cursoragent Feb 17, 2026
49d79a6
refactor: route webpack runtime helpers through sdk bundler entry
cursoragent Feb 18, 2026
385f226
fix(utils): avoid esm namespace mutation and defer webpack require
cursoragent Feb 18, 2026
0211f52
refactor(webpack-bundler-runtime): remove accessor entrypoint leftovers
cursoragent Feb 18, 2026
ac23c9a
fix(webpack-bundler-runtime): use sdk bundler webpack require
cursoragent Feb 18, 2026
c911bb6
fix: add regression coverage and align release metadata
cursoragent Feb 18, 2026
ce7453a
fix(node): inline webpack require in runtime chunk strategies
cursoragent Feb 18, 2026
f2ba7eb
feat(sdk): expose webpack sharing accessors in bundler entry
cursoragent Feb 18, 2026
ca9fea3
fix(node): use sdk bundler accessor in strategies
cursoragent Feb 18, 2026
dd14287
fix(node): remove any cast in hot-reload webpack accessor
cursoragent Feb 18, 2026
6e56bd7
refactor(utils): remove async wrappers in sharing scope setup
cursoragent Feb 18, 2026
55fa8f6
test(core): add bundler and esm validation coverage
cursoragent Feb 18, 2026
bcff4b2
Merge branch 'main' into cursor/bundler-runtime-require-access-725d
ScriptedAlchemy Feb 19, 2026
e278fde
Merge remote-tracking branch 'origin/main' into cursor/bundler-runtim…
ScriptedAlchemy Feb 24, 2026
539aef8
fix(dts-plugin): align workspace entrypoints and RawSource typing
ScriptedAlchemy Feb 24, 2026
2fabca3
Merge branch 'main' into cursor/bundler-runtime-require-access-725d
ScriptedAlchemy Feb 25, 2026
fa6339f
fix(sdk): align package entrypoints with emitted artifacts
ScriptedAlchemy Feb 25, 2026
e85e0f4
Merge branch 'main' into cursor/bundler-runtime-require-access-725d
ScriptedAlchemy Feb 25, 2026
d550fd4
Merge branch 'main' into cursor/bundler-runtime-require-access-725d
ScriptedAlchemy Feb 26, 2026
cb38d95
Merge branch 'main' into cursor/bundler-runtime-require-access-725d
ScriptedAlchemy Feb 26, 2026
724a9b4
Merge branch 'main' into cursor/bundler-runtime-require-access-725d
ScriptedAlchemy Feb 27, 2026
9f163a2
Merge branch 'main' into cursor/bundler-runtime-require-access-725d
ScriptedAlchemy Feb 27, 2026
acbd6d6
Merge branch 'main' into cursor/bundler-runtime-require-access-725d
ScriptedAlchemy Feb 28, 2026
443d2df
chore: merge main into cursor/bundler-runtime-require-access-725d
ScriptedAlchemy Feb 28, 2026
535729c
Merge branch 'main' into cursor/bundler-runtime-require-access-725d
ScriptedAlchemy Mar 2, 2026
0b299ab
Merge branch 'main' into cursor/bundler-runtime-require-access-725d
ScriptedAlchemy Mar 3, 2026
949cfb7
Merge remote-tracking branch 'origin/main' into cursor/bundler-runtim…
ScriptedAlchemy Mar 5, 2026
c1fea4a
Merge branch 'main' into cursor/bundler-runtime-require-access-725d
ScriptedAlchemy Mar 9, 2026
c885b33
Merge remote-tracking branch 'origin/main' into cursor/bundler-runtim…
ScriptedAlchemy Mar 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/twelve-forks-whisper.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@module-federation/webpack-bundler-runtime': patch
'@module-federation/runtime-core': patch
'@module-federation/utilities': patch
---

Add runtime-safe access helpers for webpack require and ignored dynamic imports, and migrate core runtime loaders to use these helpers so intermediate bundling steps are less likely to rewrite runtime globals.
10 changes: 9 additions & 1 deletion packages/runtime-core/src/utils/load.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@ import {
declare const ENV_TARGET: 'web' | 'node';
const importCallback = '.then(callbacks[0]).catch(callbacks[1])';

function importWithBundlerIgnore<T = unknown>(modulePath: string): Promise<T> {
return import(
/* webpackIgnore: true */
/* @vite-ignore */
modulePath
) as Promise<T>;
}

async function loadEsmEntry({
entry,
remoteEntryExports,
Expand All @@ -36,7 +44,7 @@ async function loadEsmEntry({
reject,
]);
} else {
import(/* webpackIgnore: true */ /* @vite-ignore */ entry)
importWithBundlerIgnore<RemoteEntryExports>(entry)
.then(resolve)
.catch(reject);
}
Expand Down
3 changes: 2 additions & 1 deletion packages/utilities/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@
"rsbuild-plugin-publint": "^0.2.1"
},
"dependencies": {
"@module-federation/sdk": "workspace:*"
"@module-federation/sdk": "workspace:*",
"@module-federation/webpack-bundler-runtime": "workspace:*"
},
"peerDependencies": {
"react": "^16 || ^17 || ^18",
Expand Down
16 changes: 9 additions & 7 deletions packages/utilities/src/utils/importRemote.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ import type {
WebpackShareScopes,
RemoteData,
} from '../types';
import {
importWithBundlerIgnore,
getWebpackRequireOrThrow,
} from '@module-federation/webpack-bundler-runtime/accessor';

/**
* Type definition for RemoteUrl
Expand Down Expand Up @@ -50,7 +54,8 @@ const loadRemote = (
) =>
new Promise<void>((resolve, reject) => {
const timestamp = bustRemoteEntryCache ? `?t=${new Date().getTime()}` : '';
const webpackRequire = __webpack_require__ as unknown as WebpackRequire;
const webpackRequire =
getWebpackRequireOrThrow() as unknown as WebpackRequire;
webpackRequire.l(
`${url}${timestamp}`,
(event) => {
Expand All @@ -72,19 +77,16 @@ const loadEsmRemote = async (
url: RemoteData['url'],
scope: ImportRemoteOptions['scope'],
) => {
const module = await import(/* webpackIgnore: true */ url);
const module = await importWithBundlerIgnore<WebpackRemoteContainer>(url);

if (!module) {
throw new Error(
`Unable to load requested remote from ${url} with scope ${scope}`,
);
}

(window as any)[scope] = {
...module,
__initializing: false,
__initialized: false,
} satisfies WebpackRemoteContainer;
module.__initialized = false;
(window as any)[scope] = module;
};

/**
Expand Down
6 changes: 5 additions & 1 deletion packages/utilities/src/utils/pure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ import {
RemoteVars,
RuntimeRemote,
RuntimeRemotesMap,
WebpackRequire,
WebpackRemoteContainer,
} from '../types';
import { getWebpackRequireOrThrow } from '@module-federation/webpack-bundler-runtime/accessor';

const pure = typeof process !== 'undefined' ? process.env['REMOTES'] || {} : {};
export const remoteVars = pure as RemoteVars;
Expand All @@ -19,6 +21,8 @@ export const extractUrlAndGlobal = (urlAndGlobal: string): [string, string] => {

export const loadScript = (keyOrRuntimeRemoteItem: string | RuntimeRemote) => {
const runtimeRemotes = getRuntimeRemotes();
const webpackRequire =
getWebpackRequireOrThrow() as unknown as WebpackRequire;

// 1) Load remote container if needed
let asyncContainer: RuntimeRemote['asyncContainer'];
Expand Down Expand Up @@ -83,7 +87,7 @@ export const loadScript = (keyOrRuntimeRemoteItem: string | RuntimeRemote) => {
return resolveRemoteGlobal();
}

(__webpack_require__ as any).l(
webpackRequire.l(
reference.url,
function (event: Event) {
//@ts-ignore
Expand Down
36 changes: 36 additions & 0 deletions packages/webpack-bundler-runtime/__tests__/accessor.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import {
getWebpackRequire,
getWebpackRequireOrThrow,
importWithBundlerIgnore,
} from '../src/accessor';

describe('webpack require accessor', () => {
afterEach(() => {
delete (globalThis as { __webpack_require__?: unknown })
.__webpack_require__;
});

test('returns undefined when webpack runtime is unavailable', () => {
expect(getWebpackRequire()).toBeUndefined();
});

test('returns the webpack require function when present', () => {
const webpackRequire = Object.assign(jest.fn(), {
federation: { bundlerRuntime: {} },
});
(globalThis as { __webpack_require__?: unknown }).__webpack_require__ =
webpackRequire;

expect(getWebpackRequire()).toBe(webpackRequire);
});

test('throws with clear message when webpack runtime is unavailable', () => {
expect(() => getWebpackRequireOrThrow()).toThrow(
'Unable to access __webpack_require__.',
);
});

test('re-exports dynamic import helper', () => {
expect(typeof importWithBundlerIgnore).toBe('function');
});
});
13 changes: 13 additions & 0 deletions packages/webpack-bundler-runtime/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,16 @@
"default": "./dist/constant.cjs.cjs"
}
},
"./accessor": {
"import": {
"types": "./dist/accessor.d.ts",
"default": "./dist/accessor.esm.js"
},
"require": {
"types": "./dist/accessor.d.ts",
"default": "./dist/accessor.cjs.cjs"
}
},
"./*": "./*"
},
"typesVersions": {
Expand All @@ -59,6 +69,9 @@
],
"constant": [
"./dist/constant.d.ts"
],
"accessor": [
"./dist/accessor.d.ts"
]
}
}
Expand Down
3 changes: 2 additions & 1 deletion packages/webpack-bundler-runtime/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
"compiler": "tsc",
"format": ["cjs", "esm"],
"additionalEntryPoints": [
"packages/webpack-bundler-runtime/src/constant.ts"
"packages/webpack-bundler-runtime/src/constant.ts",
"packages/webpack-bundler-runtime/src/accessor.ts"
],
"generatePackageJson": false,
"useLegacyTypescriptPlugin": false,
Expand Down
33 changes: 33 additions & 0 deletions packages/webpack-bundler-runtime/src/accessor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import type { WebpackRequire } from './types';

declare const __webpack_require__: unknown;

export function getWebpackRequire(): WebpackRequire | undefined {
if (typeof __webpack_require__ !== 'function') {
return undefined;
}

return __webpack_require__ as WebpackRequire;
}

export function getWebpackRequireOrThrow(): WebpackRequire {
const webpackRequire = getWebpackRequire();

if (!webpackRequire) {
throw new Error(
'Unable to access __webpack_require__. Ensure this code runs inside a webpack-compatible runtime.',
);
}

return webpackRequire;
}

export function importWithBundlerIgnore<T = unknown>(
modulePath: string,
): Promise<T> {
return import(
/* webpackIgnore: true */
/* @vite-ignore */
modulePath
) as Promise<T>;
}
6 changes: 6 additions & 0 deletions packages/webpack-bundler-runtime/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,14 @@ import { attachShareScopeMap } from './attachShareScopeMap';
import { initContainerEntry } from './initContainerEntry';
import { init } from './init';
import { getSharedFallbackGetter } from './getSharedFallbackGetter';
import {
getWebpackRequire,
getWebpackRequireOrThrow,
importWithBundlerIgnore,
} from './accessor';

export * from './types';
export { getWebpackRequire, getWebpackRequireOrThrow, importWithBundlerIgnore };

const federation: Federation = {
runtime,
Expand Down
Loading
Loading