@samitouri / QOS-React-2 / commits / 2153a29661

[Flight] createServerReference should export $$FORM_ACTION on the Server (#26987)

Currently, only the browser build exposes the `$$FORM_ACTION` helper. It's used for creating progressive enhancement fro Server Actions imported from Client Components. This helper is only useful in SSR builds so it should be included in the Edge/Node builds of the client. I also removed it from the browser build. We assume that only the Edge or Node builds of the client are used together with SSR. On the client this feature is not needed so we can exclude the code. This might be a bit unnecessary because it's not that much code and in theory you might use SSR in a Service Worker or something where the Browser build would be used but currently we assume that build is only for the client. That's why it also don't take an option for reverse look up of file names.

Sebastian Markbåge committed Jun 28, 2023 at 19:12 UTC 2153a29661e5998604225f81d93c8a20a1934adf
14 files changed +36 -11
packages/react-client/src/ReactFlightClient.js
+5 -2
@@ -29,6 +29,7 @@ import {
29 readPartialStringChunk,
30 readFinalStringChunk,
31 createStringDecoder,
32 + usedWithSSR,
33 } from './ReactFlightClientConfig';
34
35 import {
@@ -529,8 +530,10 @@ function createServerReferenceProxy<A: Iterable<any>, T>(
530 });
531 };
532 // Expose encoder for use by SSR.
532 - // TODO: Only expose this in SSR builds and not the browser client.
533 - proxy.$$FORM_ACTION = encodeFormAction;
533 + if (usedWithSSR) {
534 + // Only expose this in builds that would actually use it. Not needed on the client.
535 + (proxy: any).$$FORM_ACTION = encodeFormAction;
536 + }
537 knownServerReferences.set(proxy, metaData);
538 return proxy;
539 }
packages/react-client/src/ReactFlightReplyClient.js
+6 -2
@@ -28,6 +28,8 @@ import type {
28 RejectedThenable,
29 } from '../../shared/ReactTypes';
30
31 +import {usedWithSSR} from './ReactFlightClientConfig';
32 +
33 type ReactJSONValue =
34 | string
35 | boolean
@@ -496,8 +498,10 @@ export function createServerReference<A: Iterable<any>, T>(
498 return callServer(id, args);
499 };
500 // Expose encoder for use by SSR.
499 - // TODO: Only expose this in SSR builds and not the browser client.
500 - proxy.$$FORM_ACTION = encodeFormAction;
501 + if (usedWithSSR) {
502 + // Only expose this in builds that would actually use it. Not needed on the client.
503 + (proxy: any).$$FORM_ACTION = encodeFormAction;
504 + }
505 knownServerReferences.set(proxy, {id: id, bound: null});
506 return proxy;
507 }
packages/react-client/src/forks/ReactFlightClientConfig.custom.js
+1
@@ -35,6 +35,7 @@ export const resolveServerReference = $$$config.resolveServerReference;
35 export const preloadModule = $$$config.preloadModule;
36 export const requireModule = $$$config.requireModule;
37 export const dispatchHint = $$$config.dispatchHint;
38 +export const usedWithSSR = true;
39
40 export opaque type Source = mixed;
41
packages/react-client/src/forks/ReactFlightClientConfig.dom-browser.js
+1
@@ -10,3 +10,4 @@
10 export * from 'react-client/src/ReactFlightClientConfigBrowser';
11 export * from 'react-server-dom-webpack/src/ReactFlightClientConfigWebpackBundler';
12 export * from 'react-dom-bindings/src/shared/ReactFlightClientConfigDOM';
13 +export const usedWithSSR = false;
packages/react-client/src/forks/ReactFlightClientConfig.dom-bun.js
+1
@@ -20,3 +20,4 @@ export const resolveClientReference: any = null;
20 export const resolveServerReference: any = null;
21 export const preloadModule: any = null;
22 export const requireModule: any = null;
23 +export const usedWithSSR = true;
packages/react-client/src/forks/ReactFlightClientConfig.dom-edge-webpack.js
+1
@@ -10,3 +10,4 @@
10 export * from 'react-client/src/ReactFlightClientConfigBrowser';
11 export * from 'react-server-dom-webpack/src/ReactFlightClientConfigWebpackBundler';
12 export * from 'react-dom-bindings/src/shared/ReactFlightClientConfigDOM';
13 +export const usedWithSSR = true;
packages/react-client/src/forks/ReactFlightClientConfig.dom-legacy.js
+1
@@ -10,3 +10,4 @@
10 export * from 'react-client/src/ReactFlightClientConfigBrowser';
11 export * from 'react-server-dom-webpack/src/ReactFlightClientConfigWebpackBundler';
12 export * from 'react-dom-bindings/src/shared/ReactFlightClientConfigDOM';
13 +export const usedWithSSR = true;
packages/react-client/src/forks/ReactFlightClientConfig.dom-node-esm.js
+1
@@ -11,3 +11,4 @@
11 export * from 'react-client/src/ReactFlightClientConfigBrowser';
12 export * from 'react-server-dom-esm/src/ReactFlightClientConfigESMBundler';
13 export * from 'react-dom-bindings/src/shared/ReactFlightClientConfigDOM';
14 +export const usedWithSSR = true;
packages/react-client/src/forks/ReactFlightClientConfig.dom-node-webpack.js
+1
@@ -10,3 +10,4 @@
10 export * from 'react-client/src/ReactFlightClientConfigNode';
11 export * from 'react-server-dom-webpack/src/ReactFlightClientConfigWebpackBundler';
12 export * from 'react-dom-bindings/src/shared/ReactFlightClientConfigDOM';
13 +export const usedWithSSR = true;
packages/react-client/src/forks/ReactFlightClientConfig.dom-node.js
+1
@@ -10,3 +10,4 @@
10 export * from 'react-client/src/ReactFlightClientConfigNode';
11 export * from 'react-server-dom-webpack/src/ReactFlightClientConfigNodeBundler';
12 export * from 'react-dom-bindings/src/shared/ReactFlightClientConfigDOM';
13 +export const usedWithSSR = true;
packages/react-server-dom-esm/src/ReactFlightDOMClientNode.js
+3 -1
@@ -21,6 +21,8 @@ import {
21 close,
22 } from 'react-client/src/ReactFlightClient';
23
24 +import {createServerReference as createServerReferenceImpl} from 'react-client/src/ReactFlightReplyClient';
25 +
26 function noServerCall() {
27 throw new Error(
28 'Server Functions cannot be called during initial render. ' +
@@ -33,7 +35,7 @@ export function createServerReference<A: Iterable<any>, T>(
35 id: any,
36 callServer: any,
37 ): (...A) => Promise<T> {
36 - return noServerCall;
38 + return createServerReferenceImpl(id, noServerCall);
39 }
40
41 function createFromNodeStream<T>(
packages/react-server-dom-webpack/src/ReactFlightDOMClientEdge.js
+3 -1
@@ -21,6 +21,8 @@ import {
21 close,
22 } from 'react-client/src/ReactFlightClient';
23
24 +import {createServerReference as createServerReferenceImpl} from 'react-client/src/ReactFlightReplyClient';
25 +
26 function noServerCall() {
27 throw new Error(
28 'Server Functions cannot be called during initial render. ' +
@@ -33,7 +35,7 @@ export function createServerReference<A: Iterable<any>, T>(
35 id: any,
36 callServer: any,
37 ): (...A) => Promise<T> {
36 - return noServerCall;
38 + return createServerReferenceImpl(id, noServerCall);
39 }
40
41 export type Options = {
packages/react-server-dom-webpack/src/ReactFlightDOMClientNode.js
+3 -1
@@ -23,6 +23,8 @@ import {
23 close,
24 } from 'react-client/src/ReactFlightClient';
25
26 +import {createServerReference as createServerReferenceImpl} from 'react-client/src/ReactFlightReplyClient';
27 +
28 function noServerCall() {
29 throw new Error(
30 'Server Functions cannot be called during initial render. ' +
@@ -35,7 +37,7 @@ export function createServerReference<A: Iterable<any>, T>(
37 id: any,
38 callServer: any,
39 ): (...A) => Promise<T> {
38 - return noServerCall;
40 + return createServerReferenceImpl(id, noServerCall);
41 }
42
43 function createFromNodeStream<T>(
packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMForm-test.js
+8 -4
@@ -17,6 +17,10 @@ global.ReadableStream =
17 global.TextEncoder = require('util').TextEncoder;
18 global.TextDecoder = require('util').TextDecoder;
19
20 +// Don't wait before processing work on the server.
21 +// TODO: we can replace this with FlightServer.act().
22 +global.setTimeout = cb => cb();
23 +
24 let container;
25 let serverExports;
26 let webpackServerMap;
@@ -25,16 +29,16 @@ let ReactDOMServer;
29 let ReactServerDOMServer;
30 let ReactServerDOMClient;
31
28 -describe('ReactFlightDOMReply', () => {
32 +describe('ReactFlightDOMForm', () => {
33 beforeEach(() => {
34 jest.resetModules();
35 const WebpackMock = require('./utils/WebpackMock');
36 serverExports = WebpackMock.serverExports;
37 webpackServerMap = WebpackMock.webpackServerMap;
38 React = require('react');
35 - ReactServerDOMServer = require('react-server-dom-webpack/server.browser');
36 - ReactServerDOMClient = require('react-server-dom-webpack/client');
37 - ReactDOMServer = require('react-dom/server.browser');
39 + ReactServerDOMServer = require('react-server-dom-webpack/server.edge');
40 + ReactServerDOMClient = require('react-server-dom-webpack/client.edge');
41 + ReactDOMServer = require('react-dom/server.edge');
42 container = document.createElement('div');
43 document.body.appendChild(container);
44 });