Why Does RSC Integrate with a Bundler? — overreacted

Fair warning—this one’s for the nerds.

React Server Components is a programming paradigm that extends the module system to express a server/client application as a single program spanning two runtimes. Under the hood, the RSC implementation consists of two main pieces:

The react-server and react-client packages are internal to the React repo.

They are fully open source, of course, but they don’t get published in their raw form to npm. This is because they’re missing a key ingredient—the module system integration. Unlike many (de)serializers, RSC concerns itself not only with sending data, but also with sending code. For example, consider this tree:

<p>Hello, worldp>

If you want to turn this tag into JSON, you could do it like this:

{
  type: 'p',
  props: {
    children: 'Hello world'
  }
}

But now consider this tag. How do you serialize it?

import { Counter } from './client';
 
<Counter initialCount={10} />
'use client';
 
import { useState, useEffect } from 'react';
 
export function Counter({ initialCount }) {
  const [count, setCount] = useState(initialCount);
  // ...
}

How does one serialize a module?


Serializing Modules

Recall that we want to revive an actual on the other side of the wire—so we don’t just want a snapshot of it. We want its entire logic for interactivity!

One way to serialize it is to literally embed the Counter code into our JSON:

{
  type: `
    import { useState, useEffect } from 'react';
 
    export function Counter({ initialCount }) {
      const [count, setCount] = useState(initialCount);
      // ...
    }
  `,
  props: {
    initialCount: 10
  }
}

But that’s kind of bad, right? You don’t really want to send code as strings to eval on the client, and you don’t want to send the same component’s code many times. So instead it’s reasonable to assume its code is being served by our app as a static JS asset—which we can refer to in the JSON. It’s almost like a