Skip to content

Commit d3e904b

Browse files
fix(nextjs-mf): simplify handling of server externals (#3114)
1 parent ac46d9e commit d3e904b

File tree

3 files changed

+59
-46
lines changed

3 files changed

+59
-46
lines changed

.changeset/ai-brave-wolf.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
"@module-federation/nextjs-mf": patch
3+
---
4+
5+
Support Next 15 externals configuration
6+
7+
- Refactored external handling to dynamically find and replace the first function in the 'externals' array.
8+
- This change improves robustness by ensuring the system correctly overrides external functions regardless of their position in the list.
9+
- Maintained the existing logic to preserve intended behavior with conditions checking specific package prefixes and names.
10+
```

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
"prepare": "husky install",
5050
"changeset": "changeset",
5151
"build:packages": "npx nx affected -t build --parallel=10 --exclude='*,!tag:type:pkg'",
52-
"changegen": "./changeset-gen.js --path ./packages/enhanced --staged && ./changeset-gen.js --path ./packages/runtime --staged && ./changeset-gen.js --path ./packages/data-prefetch --staged",
52+
"changegen": "./changeset-gen.js --path ./packages/enhanced --staged && ./changeset-gen.js --path ./packages/runtime --staged && ./changeset-gen.js --path ./packages/data-prefetch --staged && ./changeset-gen.js --path ./packages/nextjs-mf --staged",
5353
"commitgen:staged": "./commit-gen.js --path ./packages --staged",
5454
"commitgen:main": "./commit-gen.js --path ./packages"
5555
},

packages/nextjs-mf/src/plugins/NextFederationPlugin/apply-server-plugins.ts

Lines changed: 48 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -107,54 +107,57 @@ export function handleServerExternals(
107107
compiler: Compiler,
108108
options: moduleFederationPlugin.ModuleFederationPluginOptions,
109109
): void {
110-
if (
111-
Array.isArray(compiler.options.externals) &&
112-
typeof compiler.options.externals[0] === 'function'
113-
) {
114-
const originalExternals = compiler.options.externals[0] as (
115-
data: ExternalItemFunctionData,
116-
callback: any,
117-
) => undefined | string;
110+
if (Array.isArray(compiler.options.externals)) {
111+
const functionIndex = compiler.options.externals.findIndex(
112+
(external) => typeof external === 'function',
113+
);
118114

119-
compiler.options.externals[0] = async function (
120-
ctx: ExternalItemFunctionData,
121-
callback: any,
122-
) {
123-
const fromNext = await originalExternals(ctx, callback);
124-
if (!fromNext) {
125-
return;
126-
}
127-
const req = fromNext.split(' ')[1];
128-
if (
129-
ctx.request &&
130-
(ctx.request.includes('@module-federation/utilities') ||
131-
Object.keys(options.shared || {}).some((key) => {
132-
const sharedOptions = options.shared as Record<
133-
string,
134-
{ import: boolean }
135-
>;
136-
return (
137-
sharedOptions[key]?.import !== false &&
138-
(key.endsWith('/') ? req.includes(key) : req === key)
139-
);
140-
}) ||
141-
ctx.request.includes('@module-federation/'))
142-
) {
143-
return;
144-
}
115+
if (functionIndex !== -1) {
116+
const originalExternals = compiler.options.externals[functionIndex] as (
117+
data: ExternalItemFunctionData,
118+
callback: any,
119+
) => undefined | string;
145120

146-
if (
147-
req.startsWith('next') ||
148-
req.startsWith('react/') ||
149-
req.startsWith('react-dom/') ||
150-
req === 'react' ||
151-
req === 'styled-jsx/style' ||
152-
req === 'react-dom'
121+
compiler.options.externals[functionIndex] = async function (
122+
ctx: ExternalItemFunctionData,
123+
callback: any,
153124
) {
154-
return fromNext;
155-
}
156-
return;
157-
};
125+
const fromNext = await originalExternals(ctx, callback);
126+
if (!fromNext) {
127+
return;
128+
}
129+
const req = fromNext.split(' ')[1];
130+
if (
131+
ctx.request &&
132+
(ctx.request.includes('@module-federation/utilities') ||
133+
Object.keys(options.shared || {}).some((key) => {
134+
const sharedOptions = options.shared as Record<
135+
string,
136+
{ import: boolean }
137+
>;
138+
return (
139+
sharedOptions[key]?.import !== false &&
140+
(key.endsWith('/') ? req.includes(key) : req === key)
141+
);
142+
}) ||
143+
ctx.request.includes('@module-federation/'))
144+
) {
145+
return;
146+
}
147+
148+
if (
149+
req.startsWith('next') ||
150+
req.startsWith('react/') ||
151+
req.startsWith('react-dom/') ||
152+
req === 'react' ||
153+
req === 'styled-jsx/style' ||
154+
req === 'react-dom'
155+
) {
156+
return fromNext;
157+
}
158+
return;
159+
};
160+
}
158161
}
159162
}
160163

0 commit comments

Comments
 (0)