Skip to content

Commit f0c0530

Browse files
committed
refactor(rsc-mf): scope callback bootstrap to client/action exposes
1 parent d3a15f5 commit f0c0530

4 files changed

Lines changed: 57 additions & 19 deletions

File tree

tests/integration/rsc-mf/remote/src/runtime/createRscExposeDefinitions.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ const CALLBACK_BOOTSTRAP_PREFIX = './src/runtime/';
33
const USERLAND_EXPOSE_PREFIX = './';
44
const SOURCE_ENTRY_EXTENSION_PATTERN = /\.[cm]?[jt]sx?$/i;
55
const RSC_LAYER = 'react-server-components';
6+
const CALLBACK_BOOTSTRAP_EXPOSE_KEY_PATTERN =
7+
/^\.\/(?:RemoteClient[\w-]*|actions|nestedActions|defaultAction|actionBundle)$/;
8+
const CALLBACK_BOOTSTRAP_IMPORT_PATH_PATTERN =
9+
/\/(?:RemoteClient[\w-]*|actions|nestedActions|defaultAction|actionBundle)\.[cm]?[jt]sx?$/;
610

711
type ExposeImportInput = string | string[];
812
export type ExposeDefinitionInput =
@@ -102,13 +106,25 @@ const normalizeExposeImportPaths = (
102106
const createRscExpose = (
103107
importPaths: string[],
104108
exposeOverrides: Record<string, unknown>,
109+
includeCallbackBootstrap: boolean,
105110
) =>
106111
({
107112
...exposeOverrides,
108-
import: [CALLBACK_BOOTSTRAP_IMPORT, ...importPaths],
113+
import: includeCallbackBootstrap
114+
? [CALLBACK_BOOTSTRAP_IMPORT, ...importPaths]
115+
: importPaths,
109116
layer: RSC_LAYER,
110117
}) as const;
111118

119+
const shouldInjectCallbackBootstrap = (
120+
exposeKey: string,
121+
importPaths: string[],
122+
) =>
123+
CALLBACK_BOOTSTRAP_EXPOSE_KEY_PATTERN.test(exposeKey) ||
124+
importPaths.some(importPath =>
125+
CALLBACK_BOOTSTRAP_IMPORT_PATH_PATTERN.test(importPath),
126+
);
127+
112128
const assertValidExposeConfig = (
113129
normalizedExposeImportPaths: NormalizedExposeImportPaths,
114130
) => {
@@ -231,6 +247,10 @@ export const createRscExposeDefinitions = (
231247
createRscExpose(
232248
normalizedDefinition.importPaths,
233249
normalizedDefinition.exposeOverrides,
250+
shouldInjectCallbackBootstrap(
251+
exposeKey,
252+
normalizedDefinition.importPaths,
253+
),
234254
),
235255
]),
236256
);

tests/integration/rsc-mf/tests/createRscExposeDefinitions.test.ts

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -102,20 +102,19 @@ describe('createRscExposeDefinitions', () => {
102102
});
103103

104104
it('allows cts and mts expose entry extensions', () => {
105-
const { createRscExposeDefinitions, CALLBACK_BOOTSTRAP_MODULE } =
106-
loadCreateRscExposeDefinitions();
105+
const { createRscExposeDefinitions } = loadCreateRscExposeDefinitions();
107106
expect(
108107
createRscExposeDefinitions({
109108
'./serverOnlyHelper': './src/lib/serverOnlyHelper.cts',
110109
'./rscBridgeUtil': './src/lib/rscBridgeUtil.mts',
111110
}),
112111
).toEqual({
113112
'./serverOnlyHelper': {
114-
import: [CALLBACK_BOOTSTRAP_MODULE, './src/lib/serverOnlyHelper.cts'],
113+
import: ['./src/lib/serverOnlyHelper.cts'],
115114
layer: 'react-server-components',
116115
},
117116
'./rscBridgeUtil': {
118-
import: [CALLBACK_BOOTSTRAP_MODULE, './src/lib/rscBridgeUtil.mts'],
117+
import: ['./src/lib/rscBridgeUtil.mts'],
119118
layer: 'react-server-components',
120119
},
121120
});
@@ -162,8 +161,7 @@ describe('createRscExposeDefinitions', () => {
162161
});
163162

164163
it('deduplicates repeated entries in object expose import arrays', () => {
165-
const { createRscExposeDefinitions, CALLBACK_BOOTSTRAP_MODULE } =
166-
loadCreateRscExposeDefinitions();
164+
const { createRscExposeDefinitions } = loadCreateRscExposeDefinitions();
167165
const exposeDefinitions = createRscExposeDefinitions({
168166
'./infoBundle': {
169167
import: [
@@ -176,15 +174,14 @@ describe('createRscExposeDefinitions', () => {
176174

177175
expect(exposeDefinitions).toEqual({
178176
'./infoBundle': {
179-
import: [CALLBACK_BOOTSTRAP_MODULE, './src/components/infoBundle.ts'],
177+
import: ['./src/components/infoBundle.ts'],
180178
layer: 'react-server-components',
181179
},
182180
});
183181
});
184182

185183
it('trims expose import path entries before deduping', () => {
186-
const { createRscExposeDefinitions, CALLBACK_BOOTSTRAP_MODULE } =
187-
loadCreateRscExposeDefinitions();
184+
const { createRscExposeDefinitions } = loadCreateRscExposeDefinitions();
188185
const exposeDefinitions = createRscExposeDefinitions({
189186
'./infoBundle': {
190187
import: [
@@ -197,7 +194,7 @@ describe('createRscExposeDefinitions', () => {
197194

198195
expect(exposeDefinitions).toEqual({
199196
'./infoBundle': {
200-
import: [CALLBACK_BOOTSTRAP_MODULE, './src/components/infoBundle.ts'],
197+
import: ['./src/components/infoBundle.ts'],
201198
layer: 'react-server-components',
202199
},
203200
});
@@ -322,4 +319,32 @@ describe('createRscExposeDefinitions', () => {
322319
}),
323320
).toThrow('must remain internal-only and cannot be exposed');
324321
});
322+
323+
it('injects callback bootstrap only for callback-capable expose keys', () => {
324+
const { createRscExposeDefinitions, CALLBACK_BOOTSTRAP_MODULE } =
325+
loadCreateRscExposeDefinitions();
326+
expect(
327+
createRscExposeDefinitions({
328+
'./RemoteClientCounter': './src/components/RemoteClientCounter.tsx',
329+
'./actions': './src/components/actions.ts',
330+
'./RemoteServerDefault': './src/components/RemoteServerDefault.tsx',
331+
}),
332+
).toEqual({
333+
'./RemoteClientCounter': {
334+
import: [
335+
CALLBACK_BOOTSTRAP_MODULE,
336+
'./src/components/RemoteClientCounter.tsx',
337+
],
338+
layer: 'react-server-components',
339+
},
340+
'./actions': {
341+
import: [CALLBACK_BOOTSTRAP_MODULE, './src/components/actions.ts'],
342+
layer: 'react-server-components',
343+
},
344+
'./RemoteServerDefault': {
345+
import: ['./src/components/RemoteServerDefault.tsx'],
346+
layer: 'react-server-components',
347+
},
348+
});
349+
});
325350
});

tests/integration/rsc-mf/tests/index.test.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ const EXPECTED_BROWSER_EXPOSE_CHUNKS = [
2626
'__federation_expose_nestedActions',
2727
'__federation_expose_defaultAction',
2828
'__federation_expose_actionBundle',
29-
'__federation_expose_infoBundle',
3029
];
3130
const EXPECTED_REMOTE_EXPOSE_PATHS = [
3231
'./RemoteClientCounter',

tests/integration/rsc-mf/tests/moduleFederationConfig.test.ts

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -155,13 +155,7 @@ describe('rsc-mf module federation config contracts', () => {
155155
importPath => importPath === './src/components/infoBundle.ts',
156156
),
157157
).toEqual(['./src/components/infoBundle.ts']);
158-
expect(
159-
imports.every(
160-
importPath =>
161-
importPath === './src/components/infoBundle.ts' ||
162-
importPath === CALLBACK_BOOTSTRAP_IMPORT,
163-
),
164-
).toBe(true);
158+
expect(imports).toEqual(['./src/components/infoBundle.ts']);
165159
});
166160

167161
it('uses remote port env var in host manifest remote URL', () => {

0 commit comments

Comments
 (0)