Skip to content

Latest commit

 

History

History

server

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 

Parcel RSC Server Entrypoint Example

This example is a server driven app built with Parcel and React Server Components. In this setup, routing happens on the server, delivering HTML on initial page load, and client side rendering on subsequent navigations. It also demonstrates React Server Actions to perform mutations, both by calling as a function and as the target of an HTML form.

Setup

The example consists of the following main files:

src/server.tsx

This is the main server entrypoint, built using Express. It is the entry of the Parcel build. All other client and server dependencies are discovered from here.

src/Todos.tsx

This is the entry React Server Component that renders the root <html> element, server content, and any client components. It is marked with the Parcel-specific "use server-entry" directive, which creates a code splitting entrypoint. Common dependencies between pages are extracted into shared bundles.

src/client.tsx

This is the main client entrypoint, imported from each page. It uses the Parcel-specific "use client-entry" directive to mark that it should only run on the client, and not on the server (even during SSR). The client is responsible for hydrating the initial page, and intercepting link clicks and navigations to perform client side routing.

src/actions.ts

This is a server actions file. Functions exported by this file can be imported from the client and called to send data to the server for processing. It is marked using the "use server" directive. When Parcel sees this directive, it places the actions into the server bundle, and creates a proxy module on the client that calls the server action via the handler in client.tsx.

Currently, server actions must be defined in a separate file. Inline server actions (e.g. "use server" inside a function) are not supported by Parcel.

src/TodoItem.tsx and src/Dialog.tsx

These are client components. <TodoItem> renders a todo list item, and uses server actions and useOptimistic to implement the checkbox and remove buttons. Dialog.tsx renders a dialog component using client APIs, and accepts the create todo form (which is a server component) as children.

Initial HTML rendering

The flow of initial rendering starts on the server.

Server

The server handles routing using Express. When a route handler is called, it calls renderRequest from @parcel/rsc/node. This renders the provided component to HTML or an RSC payload depending on the Accept header. The initial HTML embeds the RSC payload so it can be hydrated without additional network requests.

Client

To hydrate the initial page, the client calls hydrate from @parcel/rsc/client. This uses the RSC payload embedded into the initial HTML to make the page interactive. hydrate returns an updateRoot function that allows updating the page during client side navigations.

Client side routing

The client also includes a very simple router, allowing subsequent navigations after the initial page load to maintain client state without reloading the full HTML page.

Client

The client listens for the click event for all link elements on the page using event delegation, as well as the popstate event to detect when the user navigates with the browser back button. To perform a navigation:

  1. Use fetchRSC from @parcel/rsc/client to fetch a new RSC payload from the server. This is a simple fetch wrapper, with all of the options that the browser supports.
  2. Call the updateRoot function created during the initial render to update the page.
  3. Once the new page is finished loading, push the new URL to the browser's history with history.pushState.

These steps can be customized as needed for your server setup, e.g. using a better client side router, or adding authentication headers.

Server

The server handles fetch requests for RSC payloads using the same route handlers as for HTML. fetchRSC sets the Accept header to text/x-component, and renderRequest returns an RSC payload instead of HTML.

Server functions

Server functions allow the client to call the server to perform mutations and other actions. There are two ways server actions can be called: by calling an action function from the client, or by submitting an HTML form.

Client

When a server action is called, the client is responsible for sending a request to the server. This is done by passing a callServer callback to hydrate. When a server action proxy function generated by Parcel is called on the client, this handler will be invoked with the id of the action, and the arguments to pass to it.

  1. Create a POST request using fetchRSC, and set the rsc-action-id header to the id of the action to call. React will encode the arguments to the action using the RSC protocol.
  2. The server will return a new component to render, along with the return value of the server action.
  3. Call updateRoot to update the page with the component returned by the server.
  4. Return the result of the server action. This will be returned by the proxy function originally called in the client component.

These steps can be customized as needed for your server setup, e.g. adding authentication headers.

Server

When the POST request handler is called, the server performs the following steps:

  1. Get the rsc-action-id header and use callAction from @parcel/rsc/node to call the server function.
  2. Respond to the HTTP request by rendering the server component, following the steps above, and passing back the promise returned by the action as the result. This will be returned as the result of the action on the client.