Skip to content

A simple PoC to distribute (p)react apps from a NestJS backend

Notifications You must be signed in to change notification settings

ancyrweb/nestjs-react-vite-ssr

Repository files navigation

NestJS / pReact / Vite / Fastify

Proof of concept in an attempt to integrate NestJS, pReact, Vite, and Fastify.

Ideas :

  • Serving React apps from NestjS
  • Benefits from SSR for the initial page load and have SEO capabilities
  • Hydrate the app in the front-end
  • Hot-reload of the UI/JSX in the front-end for improved DX
  • Vite for front-end build
  • Keeping NestJS infrastructure for serving pages & proposing an API
  • Session-based Auth instead of JWTs
  • Multiple-Page Apps, no need for a client-side Router
  • Works with preact but can actually work with any front-end mechanism (Vue, Svelte, Qwik...)

How it works

  • The client folder contains the front-end code
  • It is built with Vite
  • It's not invoked by any of the src code
  • The client and src folder are built using different build tools
  • @fastify/vite relies on convention, but I believe it can be tweaked

Getting Started

Simply run pnpm dev to start developing. You can integrate any vite-compliant component in the front-end. Sass, Stylus, PostCSS, etc.

To render a page, return a Page object from the controller. This will trigger the rendering of the page in the front-end. This page object can pass props to the front-end.

Run pnpm build to build the app and pnpm start to start the production server.

Details

Setting up Vite

You must register a vite app and create a vite.config.js file. The structure mandate the root of your app to live in a subfolder of the root, such as client.

This folder must contain at least three files :

  • A client entry file (for example, entry-client.ts) that must be invoked by the index.html file
  • A server entry file (for example, entry-server.ts) that will be invoked by the server app.
  • An index.html file serving as the template for the app.

index.html

It must looks like this :

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title><!-- title --></title>
  <!-- hydration -->
</head>
<body>
<div id="root"><!-- element --></div>
<script type="module" src="/entry-client.ts"></script>
</body>
</html>

It contains comments serving as templating points for insertion :

  • title contains the title of the page as provided by the Route component
  • hydration contains the data required to hydrate the app
  • element contains the HTML of the page generated by the server

Client file

The client file must re-hydrate the app in the front-end. The data used to generate the HTML on the server is available under window.__INITIAL_STATE__.

Server file

The server file must generate the HTML of the page. It receives the same props as the front-end, including the request and response objects. This file MUST export a render method that is expected and will be called by the server to render the page.

Routing

No routing convention is imposed, you can follow your own routing convention. In this example we use a folder-based structure à la NextJS.

Page

A page is the root component rendered on the server and hydrated on the app. It must be exposed as a default export from the file.

It can also include a metadata function to provide metadata to the page. This method receives the exact same props as the page itself.

Build

The build process of the front-end is separated between the client and server. So two commands must be run :

  • vite build -c vite.config.js --outDir dist/client --ssrManifest to build the client
  • vite build -c vite.config.js --outDir dist/server --ssr entry-server.ts to build the server

These commands will build the files under the root directory of your client. So if your client is inside client, the result we live in client/dist/client and client/dist/server. This is perfectly normal and expected by the underlying plugin @fastify/vite.

TODO

  • Richer metadata system
  • Testability

About

A simple PoC to distribute (p)react apps from a NestJS backend

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published