-
Notifications
You must be signed in to change notification settings - Fork 46.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Enable passing Server References from Server to Client (#26124)
This is the first of a series of PRs, that let you pass functions, by reference, to the client and back. E.g. through Server Context. It's like client references but they're opaque on the client and resolved on the server. To do this, for security, you must opt-in to exposing these functions to the client using the `"use server"` directive. The `"use client"` directive lets you enter the client from the server. The `"use server"` directive lets you enter the server from the client. This works by tagging those functions as Server References. We could potentially expand this to other non-serializable or stateful objects too like classes. This only implements server->server CJS imports and server->server ESM imports. We really should add a loader to the webpack plug-in for client->server imports too. I'll leave closures as an exercise for integrators. You can't "call" a client reference on the server, however, you can "call" a server reference on the client. This invokes a callback on the Flight client options called `callServer`. This lets a router implement calling back to the server. Effectively creating an RPC. This is using JSON for serializing those arguments but more utils coming from client->server serialization.
- Loading branch information
1 parent
6c75d4e
commit ef9f6e7
Showing
38 changed files
with
844 additions
and
219 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,31 +1,49 @@ | ||
'use strict'; | ||
|
||
const {renderToPipeableStream} = require('react-server-dom-webpack/server'); | ||
const {readFile} = require('fs'); | ||
const {readFile} = require('fs').promises; | ||
const {resolve} = require('path'); | ||
const React = require('react'); | ||
|
||
module.exports = function (req, res) { | ||
// const m = require('../src/App.js'); | ||
import('../src/App.js').then(m => { | ||
const dist = process.env.NODE_ENV === 'development' ? 'dist' : 'build'; | ||
readFile( | ||
resolve(__dirname, `../${dist}/react-client-manifest.json`), | ||
'utf8', | ||
(err, data) => { | ||
if (err) { | ||
throw err; | ||
} | ||
|
||
const App = m.default.default || m.default; | ||
res.setHeader('Access-Control-Allow-Origin', '*'); | ||
const moduleMap = JSON.parse(data); | ||
const {pipe} = renderToPipeableStream( | ||
React.createElement(App), | ||
moduleMap | ||
); | ||
pipe(res); | ||
module.exports = async function (req, res) { | ||
switch (req.method) { | ||
case 'POST': { | ||
const serverReference = JSON.parse(req.get('rsc-action')); | ||
const {filepath, name} = serverReference; | ||
const action = (await import(filepath))[name]; | ||
// Validate that this is actually a function we intended to expose and | ||
// not the client trying to invoke arbitrary functions. In a real app, | ||
// you'd have a manifest verifying this before even importing it. | ||
if (action.$$typeof !== Symbol.for('react.server.reference')) { | ||
throw new Error('Invalid action'); | ||
} | ||
); | ||
}); | ||
|
||
const args = JSON.parse(req.body); | ||
const result = action.apply(null, args); | ||
|
||
res.setHeader('Access-Control-Allow-Origin', '*'); | ||
const {pipe} = renderToPipeableStream(result, {}); | ||
pipe(res); | ||
|
||
return; | ||
} | ||
default: { | ||
// const m = require('../src/App.js'); | ||
const m = await import('../src/App.js'); | ||
const dist = process.env.NODE_ENV === 'development' ? 'dist' : 'build'; | ||
const data = await readFile( | ||
resolve(__dirname, `../${dist}/react-client-manifest.json`), | ||
'utf8' | ||
); | ||
const App = m.default.default || m.default; | ||
res.setHeader('Access-Control-Allow-Origin', '*'); | ||
const moduleMap = JSON.parse(data); | ||
const {pipe} = renderToPipeableStream( | ||
React.createElement(App), | ||
moduleMap | ||
); | ||
pipe(res); | ||
return; | ||
} | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
'use client'; | ||
|
||
import * as React from 'react'; | ||
|
||
export default function Button({action, children}) { | ||
return ( | ||
<button | ||
onClick={async () => { | ||
const result = await action(); | ||
console.log(result); | ||
}}> | ||
{children} | ||
</button> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
'use server'; | ||
|
||
export async function like() { | ||
console.log('Like'); | ||
return 'Liked'; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.