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...)
- The
clientfolder contains the front-end code - It is built with Vite
- It's not invoked by any of the
srccode - The
clientandsrcfolder are built using different build tools @fastify/viterelies on convention, but I believe it can be tweaked
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.
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 theindex.htmlfile - A server entry file (for example,
entry-server.ts) that will be invoked by the server app. - An
index.htmlfile serving as the template for the app.
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 :
titlecontains the title of the page as provided by the Route componenthydrationcontains the data required to hydrate the appelementcontains the HTML of the page generated by the server
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__.
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.
No routing convention is imposed, you can follow your own routing convention. In this example we use a folder-based structure à la NextJS.
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.
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 --ssrManifestto build the clientvite build -c vite.config.js --outDir dist/server --ssr entry-server.tsto 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.
- Richer metadata system
- Testability