Skip to content

Commit

Permalink
Unwrap createServerReference, and pass additional parameters (#69190)
Browse files Browse the repository at this point in the history
For facebook/react#30741

This PR adds several additional parameters to the
`createServerReference` calls generated by the Server Reference SWC
transform, to later enable React to map server actions that are imported
into client components back to their server locations (dev mode only).

Currently the inner `findSourceMapURL` function is not yet implemented.

In a follow-up we will unwrap `registerServerReference` as well, which
is needed for server actions in the react server layer.

---------

Co-authored-by: Hendrik Liebau <[email protected]>
  • Loading branch information
shuding and unstubbable authored Sep 27, 2024
1 parent 7418b26 commit 2fc641e
Show file tree
Hide file tree
Showing 10 changed files with 75 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -833,7 +833,7 @@ impl ReactServerComponentValidator {
}
}

/// ```
/// ```js
/// import dynamic from 'next/dynamic'
///
/// dynamic(() => import(...)) // ✅
Expand Down
58 changes: 43 additions & 15 deletions crates/next-custom-transforms/src/transforms/server_actions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1345,18 +1345,38 @@ impl<C: Comments> VisitMut for ServerActions<C> {
// If it's compiled in the client layer, each export field needs to be
// wrapped by a reference creation call.
let create_ref_ident = private_ident!("createServerReference");
let call_server_ident = private_ident!("callServer");
let find_source_map_url_ident = private_ident!("findSourceMapURL");

if !self.config.is_react_server_layer {
// import { createServerReference } from
// 'private-next-rsc-action-client-wrapper'
// import {
// createServerReference,
// callServer,
// findSourceMapURL
// } from 'private-next-rsc-action-client-wrapper'
// createServerReference("action_id")
new.push(ModuleItem::ModuleDecl(ModuleDecl::Import(ImportDecl {
span: DUMMY_SP,
specifiers: vec![ImportSpecifier::Named(ImportNamedSpecifier {
span: DUMMY_SP,
local: create_ref_ident.clone(),
imported: None,
is_type_only: false,
})],
specifiers: vec![
ImportSpecifier::Named(ImportNamedSpecifier {
span: DUMMY_SP,
local: create_ref_ident.clone(),
imported: None,
is_type_only: false,
}),
ImportSpecifier::Named(ImportNamedSpecifier {
span: DUMMY_SP,
local: call_server_ident.clone(),
imported: None,
is_type_only: false,
}),
ImportSpecifier::Named(ImportNamedSpecifier {
span: DUMMY_SP,
local: find_source_map_url_ident.clone(),
imported: None,
is_type_only: false,
}),
],
src: Box::new(Str {
span: DUMMY_SP,
value: "private-next-rsc-action-client-wrapper".into(),
Expand All @@ -1366,6 +1386,7 @@ impl<C: Comments> VisitMut for ServerActions<C> {
with: None,
phase: Default::default(),
})));
new.rotate_right(1);
}

for (id, export_name) in self.exported_idents.iter() {
Expand All @@ -1386,7 +1407,13 @@ impl<C: Comments> VisitMut for ServerActions<C> {
callee: Callee::Expr(Box::new(Expr::Ident(
create_ref_ident.clone(),
))),
args: vec![action_id.as_arg()],
args: vec![
action_id.as_arg(),
call_server_ident.clone().as_arg(),
Expr::undefined(DUMMY_SP).as_arg(),
find_source_map_url_ident.clone().as_arg(),
"default".as_arg(),
],
..Default::default()
})),
},
Expand All @@ -1410,7 +1437,13 @@ impl<C: Comments> VisitMut for ServerActions<C> {
callee: Callee::Expr(Box::new(Expr::Ident(
create_ref_ident.clone(),
))),
args: vec![action_id.as_arg()],
args: vec![
action_id.as_arg(),
call_server_ident.clone().as_arg(),
Expr::undefined(DUMMY_SP).as_arg(),
find_source_map_url_ident.clone().as_arg(),
export_name.clone().as_arg(),
],
..Default::default()
}))),
definite: false,
Expand Down Expand Up @@ -1520,11 +1553,6 @@ impl<C: Comments> VisitMut for ServerActions<C> {
text: generate_server_actions_comment(actions).into(),
},
);

if !self.config.is_react_server_layer {
// Make it the first item
new.rotate_right(1);
}
}

// import { cache as $cache } from "private-next-rsc-cache-wrapper";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* __next_internal_client_entry_do_not_use__ default auto */ /* __next_internal_action_entry_do_not_use__ {"6a88810ecce4a4e8b59d53b8327d7e98bbf251d7":"$$RSC_SERVER_ACTION_0"} */ export async function $$RSC_SERVER_ACTION_0() {}
export default function App() {
/* __next_internal_client_entry_do_not_use__ default auto */ /* __next_internal_action_entry_do_not_use__ {"6a88810ecce4a4e8b59d53b8327d7e98bbf251d7":"$$RSC_SERVER_ACTION_0"} */ export default function App() {
var fn = registerServerReference("6a88810ecce4a4e8b59d53b8327d7e98bbf251d7", $$RSC_SERVER_ACTION_0);
return <div>App</div>;
}
export async function $$RSC_SERVER_ACTION_0() {}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
// app/send.ts
/* __next_internal_action_entry_do_not_use__ {"ab21efdafbe611287bc25c0462b1e0510d13e48b":"foo"} */ export var foo = /*#__PURE__*/ createServerReference("ab21efdafbe611287bc25c0462b1e0510d13e48b");
import { createServerReference } from "private-next-rsc-action-client-wrapper";
/* __next_internal_action_entry_do_not_use__ {"ab21efdafbe611287bc25c0462b1e0510d13e48b":"foo"} */ import { createServerReference, callServer, findSourceMapURL } from "private-next-rsc-action-client-wrapper";
export var foo = /*#__PURE__*/ createServerReference("ab21efdafbe611287bc25c0462b1e0510d13e48b", callServer, void 0, findSourceMapURL, "foo");

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
// This file must be bundled in the app's client layer, it shouldn't be directly
// imported by the server.

import { callServer } from 'next/dist/client/app-call-server'
export { callServer } from 'next/dist/client/app-call-server'

// A noop wrapper to let the Flight client create the server reference.
// See also: https://github.com/facebook/react/pull/26632
export function createServerReference(id: string) {
// Since we're using the Edge build of Flight client for SSR [1], here we need to
// also use the same Edge build to create the reference. For the client bundle,
// we use the default and let Webpack to resolve it to the correct version.
// 1: https://github.com/vercel/next.js/blob/16eb80b0b0be13f04a6407943664b5efd8f3d7d0/packages/next/src/server/app-render/use-flight-response.tsx#L24-L26
const { createServerReference: createServerReferenceImpl } = (
!!process.env.NEXT_RUNTIME
? // eslint-disable-next-line import/no-extraneous-dependencies
require('react-server-dom-webpack/client.edge')
: // eslint-disable-next-line import/no-extraneous-dependencies
require('react-server-dom-webpack/client')
) as typeof import('react-server-dom-webpack/client')
// Since we're using the Edge build of Flight client for SSR [1], here we need to
// also use the same Edge build to create the reference. For the client bundle,
// we use the default and let Webpack to resolve it to the correct version.
// 1: https://github.com/vercel/next.js/blob/16eb80b0b0be13f04a6407943664b5efd8f3d7d0/packages/next/src/server/app-render/use-flight-response.tsx#L24-L26
export const createServerReference = (
(!!process.env.NEXT_RUNTIME
? // eslint-disable-next-line import/no-extraneous-dependencies
require('react-server-dom-webpack/client.edge')
: // eslint-disable-next-line import/no-extraneous-dependencies
require('react-server-dom-webpack/client')) as typeof import('react-server-dom-webpack/client')
).createServerReference

return createServerReferenceImpl(id, callServer)
}
export const findSourceMapURL = undefined
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ const flightServerReferenceProxyLoader: webpack.LoaderDefinitionFunction<{
// Because of that, Webpack is able to concatenate the modules and inline the
// reference IDs recursively directly into the module that uses them.
return `\
import { createServerReference } from 'private-next-rsc-action-client-wrapper'
import { createServerReference, callServer, findSourceMapURL } from 'private-next-rsc-action-client-wrapper'
export ${
name === 'default' ? 'default' : `const ${name} =`
} /*#__PURE__*/createServerReference(${JSON.stringify(id)})`
} /*#__PURE__*/createServerReference(${JSON.stringify(id)}, callServer, undefined, findSourceMapURL, ${JSON.stringify(name)})`
}

export default flightServerReferenceProxyLoader

0 comments on commit 2fc641e

Please sign in to comment.