fixtures/flight-parcel/src/server.tsx TYPESCRIPT 141 lines View on github.com → Search inside
1// Server dependencies.2import express, {3  type Request as ExpressRequest,4  type Response as ExpressResponse,5} from 'express';6import {Readable} from 'node:stream';7import type {ReadableStream as NodeReadableStream} from 'stream/web';8import {9  renderToReadableStream,10  loadServerAction,11  decodeReply,12  decodeAction,13} from 'react-server-dom-parcel/server.edge';14import {injectRSCPayload} from 'rsc-html-stream/server';1516// Client dependencies, used for SSR.17// These must run in the same environment as client components (e.g. same instance of React).18import {createFromReadableStream} from 'react-server-dom-parcel/client.edge' with {env: 'react-client'};19import {renderToReadableStream as renderHTMLToReadableStream} from 'react-dom/server.edge' with {env: 'react-client'};20import ReactClient, {ReactElement} from 'react' with {env: 'react-client'};2122// Page components. These must have "use server-entry" so they are treated as code splitting entry points.23import {Todos} from './Todos';2425const app = express();2627app.use(function (req, res, next) {28  res.setHeader('Access-Control-Allow-Methods', 'GET,HEAD,POST');29  res.setHeader('Access-Control-Allow-Origin', '*');30  res.setHeader('Access-Control-Allow-Headers', 'rsc-action');31  next();32});3334app.use(express.static('dist'));3536app.get('/', async (req, res) => {37  await render(req, res, <Todos />);38});3940app.post('/', async (req, res) => {41  await handleAction(req, res, <Todos />);42});4344app.get('/todos/:id', async (req, res) => {45  await render(req, res, <Todos id={Number(req.params.id)} />);46});4748app.post('/todos/:id', async (req, res) => {49  await handleAction(req, res, <Todos id={Number(req.params.id)} />);50});5152async function render(53  req: ExpressRequest,54  res: ExpressResponse,55  component: ReactElement,56  actionResult?: any,57) {58  // Render RSC payload.59  let root: any = component;60  if (actionResult) {61    root = {result: actionResult, root};62  }63  let stream = renderToReadableStream(root);64  if (req.accepts('text/html')) {65    res.setHeader('Content-Type', 'text/html');6667    // Use client react to render the RSC payload to HTML.68    let [s1, s2] = stream.tee();69    let data: Promise<ReactElement>;70    function Content() {71      data ??= createFromReadableStream<ReactElement>(s1);72      return ReactClient.use(data);73    }7475    let htmlStream = await renderHTMLToReadableStream(<Content />, {76      bootstrapScriptContent: (Todos as any).bootstrapScript,77    });78    let response = htmlStream.pipeThrough(injectRSCPayload(s2));79    Readable.fromWeb(response as NodeReadableStream).pipe(res);80  } else {81    res.set('Content-Type', 'text/x-component');82    Readable.fromWeb(stream as NodeReadableStream).pipe(res);83  }84}8586// Handle server actions.87async function handleAction(88  req: ExpressRequest,89  res: ExpressResponse,90  component: ReactElement,91) {92  let id = req.get('rsc-action-id');93  let request = new Request('http://localhost' + req.url, {94    method: 'POST',95    headers: req.headers as any,96    body: Readable.toWeb(req) as ReadableStream,97    // @ts-ignore98    duplex: 'half',99  });100101  if (id) {102    let action = await loadServerAction(id);103    let body = req.is('multipart/form-data')104      ? await request.formData()105      : await request.text();106    let args = await decodeReply<any[]>(body);107    let result = action.apply(null, args);108    try {109      // Wait for any mutations110      await result;111    } catch (x) {112      // We handle the error on the client113    }114115    await render(req, res, component, result);116  } else {117    // Form submitted by browser (progressive enhancement).118    let formData = await request.formData();119    let action = await decodeAction(formData);120    try {121      // Wait for any mutations122      await action();123    } catch (err) {124      // TODO render error page?125    }126    await render(req, res, component);127  }128}129130let server = app.listen(3001);131console.log('Server listening on port 3001');132133// Restart the server when it changes.134if (module.hot) {135  module.hot.dispose(() => {136    server.close();137  });138139  module.hot.accept();140}

Findings

✓ No findings reported for this file.

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.