Skip to content

Commit b2a1d3b

Browse files
committed
fix(rsc-mf): remap remote action ids to host proxy actions
1 parent e735717 commit b2a1d3b

3 files changed

Lines changed: 117 additions & 5 deletions

File tree

tests/integration/rsc-mf/host/server/modern.server.ts

Lines changed: 82 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import fs from 'node:fs/promises';
2+
import path from 'node:path';
13
import {
24
type MiddlewareHandler,
35
defineServerConfig,
@@ -25,6 +27,62 @@ const REMOTE_COUNTER_SOURCE_MODULE = './src/components/RemoteClientCounter.tsx';
2527
const createRemoteNestedMixedAliasChunk = () =>
2628
`\n;(globalThis["chunk_rscHost"] = globalThis["chunk_rscHost"] || []).push([["__federation_expose_RemoteNestedMixed_alias"],{"${REMOTE_COUNTER_ALIAS_MODULE}":function(module,__unused,__webpack_require__){module.exports=__webpack_require__("${REMOTE_COUNTER_SOURCE_MODULE}");}}]);`;
2729

30+
const REMOTE_ACTION_ID_TO_PROXY_EXPORT = {
31+
'606c30f35d74d843171a8a71358eda595991e4ee16270e9f052af3faef57a19999':
32+
'proxyIncrementRemoteCount',
33+
'40e41a2ee9d9de373b364dcf2a0201701057c8502037bf9ef2cd26bb2a1259dabd':
34+
'proxyRemoteActionEcho',
35+
'408da81ddb8214f8cb98a83552cb70c4d17b27b6fd36d972cac89e7030a4874fd4':
36+
'proxyNestedRemoteAction',
37+
'40fd3fd0c01e4d21630b7f6f902c1ddc49d3b05418ca1da003c4fdc6c6272e0bf2':
38+
'proxyDefaultRemoteAction',
39+
} as const;
40+
const ACTION_EXPOSE_PATHS = new Set([
41+
'/static/js/async/__federation_expose_actions.js',
42+
'/static/js/async/__federation_expose_nestedActions.js',
43+
'/static/js/async/__federation_expose_defaultAction.js',
44+
]);
45+
46+
let cachedProxyActionIds:
47+
| Partial<
48+
Record<
49+
(typeof REMOTE_ACTION_ID_TO_PROXY_EXPORT)[keyof typeof REMOTE_ACTION_ID_TO_PROXY_EXPORT],
50+
string
51+
>
52+
>
53+
| undefined;
54+
55+
const getProxyActionIds = async () => {
56+
if (cachedProxyActionIds) {
57+
return cachedProxyActionIds;
58+
}
59+
60+
const serverBundlePath = path.resolve(
61+
__dirname,
62+
'../dist/bundles/server-component-root.js',
63+
);
64+
const serverBundleCode = await fs.readFile(serverBundlePath, 'utf-8');
65+
66+
const actionIdMap: Partial<
67+
Record<
68+
(typeof REMOTE_ACTION_ID_TO_PROXY_EXPORT)[keyof typeof REMOTE_ACTION_ID_TO_PROXY_EXPORT],
69+
string
70+
>
71+
> = {};
72+
Object.values(REMOTE_ACTION_ID_TO_PROXY_EXPORT).forEach(exportName => {
73+
const pattern = new RegExp(
74+
`registerServerReference\\\\(${exportName},\\\\s*"([^"]+)"`,
75+
);
76+
const match = serverBundleCode.match(pattern);
77+
if (match?.[1]) {
78+
actionIdMap[exportName] = match[1];
79+
}
80+
});
81+
cachedProxyActionIds = actionIdMap;
82+
83+
return actionIdMap;
84+
};
85+
2886
const proxyRemoteFederationAsset: MiddlewareHandler = async (c, next) => {
2987
const reqUrl = new URL(c.req.url);
3088
const pathname = reqUrl.pathname;
@@ -48,11 +106,30 @@ const proxyRemoteFederationAsset: MiddlewareHandler = async (c, next) => {
48106
return;
49107
}
50108

51-
if (
52-
pathname === '/static/js/async/__federation_expose_RemoteNestedMixed.js'
53-
) {
54-
const chunkText = await upstream.text();
55-
c.res = new Response(`${chunkText}${createRemoteNestedMixedAliasChunk()}`, {
109+
const shouldPatchActionChunk = ACTION_EXPOSE_PATHS.has(pathname);
110+
const shouldPatchNestedMixed =
111+
pathname === '/static/js/async/__federation_expose_RemoteNestedMixed.js';
112+
if (shouldPatchActionChunk || shouldPatchNestedMixed) {
113+
let chunkText = await upstream.text();
114+
115+
if (shouldPatchActionChunk) {
116+
const proxyActionIds = await getProxyActionIds().catch(() => ({}));
117+
Object.entries(REMOTE_ACTION_ID_TO_PROXY_EXPORT).forEach(
118+
([remoteActionId, proxyExport]) => {
119+
const proxyActionId = proxyActionIds[proxyExport];
120+
if (!proxyActionId) {
121+
return;
122+
}
123+
chunkText = chunkText.split(remoteActionId).join(proxyActionId);
124+
},
125+
);
126+
}
127+
128+
if (shouldPatchNestedMixed) {
129+
chunkText = `${chunkText}${createRemoteNestedMixedAliasChunk()}`;
130+
}
131+
132+
c.res = new Response(chunkText, {
56133
status: upstream.status,
57134
headers: {
58135
'content-type': 'application/javascript; charset=utf-8',

tests/integration/rsc-mf/host/src/server-component-root/App.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,19 @@ import { getServerOnlyInfo } from 'rscRemote/remoteServerOnly';
88
import getServerOnlyDefaultInfo from 'rscRemote/remoteServerOnlyDefault';
99
import styles from './App.module.less';
1010
import HostRemoteActionRunner from './HostRemoteActionRunner';
11+
import {
12+
proxyDefaultRemoteAction,
13+
proxyIncrementRemoteCount,
14+
proxyNestedRemoteAction,
15+
proxyRemoteActionEcho,
16+
} from './remoteActionProxy';
1117

1218
const App = () => {
19+
// Ensure host action manifest includes proxy action IDs.
20+
void proxyIncrementRemoteCount;
21+
void proxyRemoteActionEcho;
22+
void proxyNestedRemoteAction;
23+
void proxyDefaultRemoteAction;
1324
const remoteServerOnlyInfo = getServerOnlyInfo();
1425
const remoteServerOnlyDefaultInfo = getServerOnlyDefaultInfo();
1526
const remoteMetaLabel = getRemoteMetaLabel();
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
'use server';
2+
3+
export async function proxyIncrementRemoteCount(
4+
previousState: number,
5+
formData: FormData,
6+
) {
7+
const remote = await import('rscRemote/actions');
8+
return remote.incrementRemoteCount(previousState, formData);
9+
}
10+
11+
export async function proxyRemoteActionEcho(value: string) {
12+
const remote = await import('rscRemote/actions');
13+
return remote.remoteActionEcho(value);
14+
}
15+
16+
export async function proxyNestedRemoteAction(value: string) {
17+
const remote = await import('rscRemote/nestedActions');
18+
return remote.nestedRemoteAction(value);
19+
}
20+
21+
export async function proxyDefaultRemoteAction(value: string) {
22+
const remote = await import('rscRemote/defaultAction');
23+
return remote.default(value);
24+
}

0 commit comments

Comments
 (0)