React Server Components (RSC)

Last time we tried to use React Server Component libraries (npm packages) they didnā€™t work. So probably still donā€™t.

are you setting the react-server condition anywhere? i think i had an issue where i was applying the condition to user code but not external packages or my react overrides. that was in webpack though

(easiest way to check is npm i server-only and then import 'server-only'; in RSC code. if that works youā€™re good)

1 Like

@lubieowoce Thank you so much for jumping in and offering suggestions :pray:

Right now Iā€™m launching the RSC server like this

execa(
  'node',
  ['--conditions react-server', './node_modules/@redwoodjs/vite/dist/runRscFeServer.js'],
  {
    cwd: getPaths().base,
    stdio: 'inherit',
    shell: true,
  }
)

I hope thatā€™s enough, but Iā€™ll double check with the server-only package :slight_smile:

idk your setup, but if youā€™re running Vite over RSC code (from a quick look, I think I saw a rscIndexPlugin() somewhere?) then you probably need to tell Vite to use that condition too ā€“ that obv affects how itā€™ll resolve imports of things like server-only

@lubieowoce You were right all along. Thereā€™s a bug with Vite where it doesnā€™t care about the conditions (like react-server) that you pass into it when SSR loading modules

Some exciting new developments! Redwood now supports React Server Functions aka React Server Actions :tada:

Server Functions is a way for client components to directly call functions on the server. For this to work the server function needs to be placed in a separate file with a 'use server' directive at the top.

It can look like this

'use server'

// module state on server
let counter = 0

export const getCounter = () => counter

export const increment = () => {
  counter += 1
}

Note that this is just a simple example - not best-practice. counter will be shared by everyone!

Pressing ā€œIncrement server counterā€ in the client component will update counter on the server and re-render the page.

Hereā€™s the code for that client component

'use client'

import { useState } from 'react'

import { mutate } from '@redwoodjs/vite/client'

interface Props {
  increment: () => void
}

export const ServerActionCounter = ({ increment }: Props) => {
  const [count, setCount] = useState(0)
  return (
    <div style={{ border: '3px blue dashed', margin: '1em', padding: '1em' }}>
      <h3>This is a client component.</h3>
      <p>Count: {count}</p>
      <button onClick={() => setCount((c) => c + 1)}>Increment</button>
      <p>
        <button onClick={() => mutate(() => increment())}>
          Increment server counter
        </button>
      </p>
    </div>
  )
}

And hereā€™s how itā€™s used:

import { getCounter, increment } from './funcs.js'

// ...

return (
  <>
    <p>Server counter: {getCounter()}</p>
    <ServerActionCounter increment={increment} />
  </>
)

Iā€™ve youā€™ve tried Server Actions in Next you should know that the RW implementation is still very limited. For example you canā€™t yet add use server inside a function to make it a server action. You can only make an entire file a ā€œReact Server Functions-fileā€.

4 Likes

Redwoodā€™s RSC implementation now supports using React Server Functions/Server Actions as form actions. I.e. <form action={onSendServerAction()}>. Iā€™ve also made it support importing npm packages that have react components that uses the 'use client' directive.

Hereā€™s a video demonstrating both those features by calling ChatGTP to build an AI chatbot:

It uses https://www.fixie.aiā€™s ai-jsx package to call the chatgpt api in an RSC.

1 Like

Iā€™ve created a bunch of demo repos for RSCs, including the AI chatbot one from the post above (do note that you need to add your own OpenAI API key to .env for that one to work)

Hereā€™s the list

  1. GitHub - Tobbe/rw-rsc-client-counter: Initial RW RSC demo with 'use client' Counter component
  2. GitHub - Tobbe/rw-rsc-suspense: RW RSC Demo showing Suspense
  3. GitHub - Tobbe/rw-rsc-server-mutation: RW RSC demo that mutates server state
  4. GitHub - Tobbe/rw-rsc-rsf-return-value: RW RSC demo that asynchronously gets a value from a server function
  5. GitHub - Tobbe/rw-rsc-form-server-action: RW RSC Demo showing a form action
  6. GitHub - Tobbe/rw-rsc-ai-jsx: RW RSC demo that integrates with ai-jsx

And I also added GitPod buttons to all the demo READMEs, so you can try them out really easily without setting anything up on your own computer!

Hereā€™s an example for the first demo (rw-rsc-client-counter)

Open in Gitpod

1 Like

Iā€™m going through the process of building an app and wanted to document the issues I ran into getting started with the instructions in the first post:

  • Tried to run npx create-redwood-app, got an error that node > 20 required
    • Fix: installed node 20 with nvm install 20
  • npx create-redwood-app command successful
  • Tied to yarn install, got an error that yarn command not found
    • Fix: Installed yarn with npm install -g yarn See Tobbeā€™s reply below
  • Tried to run yarn install, got an error that yarn needs to be 4.1.0 and not 1.22.21.
    • Tried yarn set version 4 but got the error that Corepack needs to be enabled.
      • Fix: enabled corepack with corepack enable
    • Fix: switched to yarn 4 with yarn set version 4
  • yarn install successful

Remaining commands worked, site serving!

Hereā€™s a nice temporary workaround for using Tailwind. You get it from their CDN, but can still extend it and even use @apply to create your own composite classes. This goes into the <head> of web/src/index.html:

<script src="https://cdn.tailwindcss.com"></script>
<script>
  tailwind.config = {
    theme: {
      extend: {
        colors: {
          clifford: '#da373d',
        },
      },
    },
  }
</script>
<style type="text/tailwindcss">
  @layer utilities {
    .button {
      @apply bg-clifford text-white font-bold py-2 px-4 rounded;
    }
  }
</style>

The downside is that youā€™re downloading 110KB of CSS, essentially all of the Tailwind classes and definitions, even though your site may only use a very small subset of those (Spokeā€™s index.css is 21KB).

But, the index.js file alone for our current build is 600KB, so in the grand scheme of things itā€™s not so bad!

Please donā€™t do this! Itā€™s explicitly called out as a very bad thing in the yarn docs :smiley:

This is the right thing to do instead :slight_smile:

We have a note about all of this in our tutorial

Not quite as simple as just pointing to a CDN, but a better way to do this would be to use the Tailwind CLI to generate a minified build just for your project and use that build instead of the huge generic one.

npx tailwindcss -o tw-build.css --minify

And then you can just include that like any other css file in your index.html file

<link href="./tw-build.css" rel="stylesheet">

Yarn itself told me to install it that way!! Installation | Yarn First result for a google of ā€œinstall yarnā€!

Ahhh the Javascript ecosystem is so nice to work with. :blush:

Hmm I thought you needed an input file and then it digested that to create the output. Do I just need the tailwind.config.js to let it know where to search for class names then?

Yes, a proper config file should be all you need

Update: Getting Started with RSC Walkthrough

As of this morning, we are starting a new development process, releasing support incrementally via RedwoodJS canary versions.

Thereā€™s a new Walkthrough guide to get you started:
https://redwoodjs.com/blog/rsc-now-in-redwoodjs

ā€œBighornā€ forum category

And weā€™ve created a new section of the Forum for all ongoing conversation about the Bighorn development epoch. (Read more about what Bighorn means in the blog post linked above.)

After reading the blog post Iā€™m wondering, how refetching will work - if thereā€™s a plan for that (as we traditionally use query for that, but they are gone now :slight_smile:

I guess that might be part of the server action milestone?

1 Like

Good question. Since Redwood ā€œClassicā€ (aka Redwood with GraphQL) relied on Apollo Client to do lots (fetching, refetching, error handling, state management, caching) I expect one will have to find some similar solutions for each in the new sever-cell world.

1 Like

Yes, this is a big part of that milestone :slightly_smiling_face:

2 Likes

Iā€™m following the steps in the ā€œGetting Startedā€ section and am bumping into errors.

  • npx -y create-redwood-app@canary -y rsc_test
  • cd rsc_test
    • added: yarn install
  • yarn rw experimental setup-streaming-ssr -f
  • yarn rw experimental setup-rsc
  • yarn rw build
  • yarn rw serve

Error during serve:

renderFromDist HomePage
renderFromDist FatalErrorPage
renderFromDist AboutPage
[HPM] Proxy created: /  -> http://127.0.0.1:8911
[HPM] Proxy rewrite rule created: "^/.redwood/functions" ~> ""
Started production FE server on http://localhost:8910
Error: The following dependencies are imported but could not be resolved:

  src/pages/FatalErrorPage (imported by C:/Users/bburnworth/Documents/Code/rsc_test/web/src/App.tsx)
  src/Routes (imported by C:/Users/bburnworth/Documents/Code/rsc_test/web/src/App.tsx)

Are they installed?
    at file:///C:/Users/bburnworth/Documents/Code/rsc_test/node_modules/vite/dist/node/chunks/dep-jvB8WLp9.js:52405:23
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async file:///C:/Users/bburnworth/Documents/Code/rsc_test/node_modules/vite/dist/node/chunks/dep-jvB8WLp9.js:51817:38

...

 - Here's your unique error reference to quote: '6399bce4-d9f6-490c-8adb-8fc2ce076088'

Output of yarn rw info:

  System:
    OS: Windows 10 10.0.19045
  Binaries:
    Node: 20.11.1 - C:\Users\BBURNW~1\AppData\Local\Temp\xfs-b46f4e63\node.CMD
    Yarn: 4.1.1 - C:\Users\BBURNW~1\AppData\Local\Temp\xfs-b46f4e63\yarn.CMD
  Browsers:
    Edge: Chromium (123.0.2420.65)
  npmPackages:
    @redwoodjs/core: 8.0.0-canary.426 => 8.0.0-canary.426+e11c9a2a6
    @redwoodjs/project-config: 8.0.0-canary.426 => 8.0.0-canary.426+e11c9a2a6

Any suggestions for me to move forward?