Skip to content

Commit

Permalink
Implement the ESM loader used in fixtures
Browse files Browse the repository at this point in the history
Wired up an example of how to call into the server
  • Loading branch information
sebmarkbage committed Feb 9, 2023
1 parent 6278554 commit b35a364
Show file tree
Hide file tree
Showing 9 changed files with 298 additions and 89 deletions.
1 change: 1 addition & 0 deletions fixtures/flight/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"babel-plugin-named-asset-import": "^0.3.8",
"babel-preset-react-app": "^10.0.1",
"bfj": "^7.0.2",
"body-parser": "^1.20.1",
"browserslist": "^4.18.1",
"camelcase": "^6.2.1",
"case-sensitive-paths-webpack-plugin": "^2.4.0",
Expand Down
12 changes: 12 additions & 0 deletions fixtures/flight/server/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,25 @@ babelRegister({
});

const express = require('express');
const bodyParser = require('body-parser');
const app = express();

// Application
app.get('/', function (req, res) {
require('./handler.js')(req, res);
});

app.options('/', function (req, res) {
res.setHeader('Allow', 'Allow: GET,HEAD,POST');
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Headers', 'rsc-action');
res.end();
});

app.post('/', bodyParser.text(), function (req, res) {
require('./handler.js')(req, res);
});

app.get('/todos', function (req, res) {
res.setHeader('Access-Control-Allow-Origin', '*');
res.json([
Expand Down
64 changes: 41 additions & 23 deletions fixtures/flight/server/handler.js
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;
}
}
};
6 changes: 6 additions & 0 deletions fixtures/flight/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import {Counter} from './Counter.js';
import {Counter as Counter2} from './Counter2.js';

import ShowMore from './ShowMore.js';
import Button from './Button.js';

import {like} from './actions.js';

export default async function App() {
const res = await fetch('http://localhost:3001/todos');
Expand All @@ -23,6 +26,9 @@ export default async function App() {
<ShowMore>
<p>Lorem ipsum</p>
</ShowMore>
<div>
<Button action={like}>Like</Button>
</div>
</Container>
);
}
15 changes: 15 additions & 0 deletions fixtures/flight/src/Button.js
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>
);
}
6 changes: 6 additions & 0 deletions fixtures/flight/src/actions.js
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';
}
17 changes: 16 additions & 1 deletion fixtures/flight/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,22 @@ import {Suspense} from 'react';
import ReactDOM from 'react-dom/client';
import ReactServerDOMReader from 'react-server-dom-webpack/client';

let data = ReactServerDOMReader.createFromFetch(fetch('http://localhost:3001'));
let data = ReactServerDOMReader.createFromFetch(
fetch('http://localhost:3001'),
{
callServer(id, args) {
const response = fetch('http://localhost:3001', {
method: 'POST',
cors: 'cors',
headers: {
'rsc-action': JSON.stringify({filepath: id.id, name: id.name}),
},
body: JSON.stringify(args),
});
return ReactServerDOMReader.createFromFetch(response);
},
}
);

function Content() {
return React.use(data);
Expand Down
25 changes: 25 additions & 0 deletions fixtures/flight/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3221,6 +3221,24 @@ body-parser@1.20.0:
type-is "~1.6.18"
unpipe "1.0.0"

body-parser@^1.20.1:
version "1.20.1"
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.1.tgz#b1812a8912c195cd371a3ee5e66faa2338a5c668"
integrity sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==
dependencies:
bytes "3.1.2"
content-type "~1.0.4"
debug "2.6.9"
depd "2.0.0"
destroy "1.2.0"
http-errors "2.0.0"
iconv-lite "0.4.24"
on-finished "2.4.1"
qs "6.11.0"
raw-body "2.5.1"
type-is "~1.6.18"
unpipe "1.0.0"

bonjour-service@^1.0.11:
version "1.0.13"
resolved "https://registry.yarnpkg.com/bonjour-service/-/bonjour-service-1.0.13.tgz#4ac003dc1626023252d58adf2946f57e5da450c1"
Expand Down Expand Up @@ -7970,6 +7988,13 @@ qs@6.10.3:
dependencies:
side-channel "^1.0.4"

qs@6.11.0:
version "6.11.0"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a"
integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==
dependencies:
side-channel "^1.0.4"

quick-lru@^5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932"
Expand Down
Loading

0 comments on commit b35a364

Please sign in to comment.