Server-Side Rendering (SSR)
Server-Side Rendering (SSR) means rendering front-end frameworks(for example React, Vue, Solid, etc) to html
in Node.js(Server Side), and hydrating the rendered html
on the client.
This document describes how to built a SSR application on top of Farm from scratch.
Example Projects
Farm provides a list of SSR examples for popular frameworks:
Project Structure
A SSR typical application often have the following source file structure:
index.html
: Entry html of the application that running on the client(browser)farm.config.ts
: farm config that builds the project to clientfarm.config.server.ts
: Farm config that builds the project to Node.js(server)server.js
: Server script that should be deployed for productionsrc/index-client.tsx
: Client entry scriptssrc/index-server.tsx
: Server entry scriptssrc/main.tsx
: Application code shared for both client and server
index.html
need to reference index-client.tsx
and include a placeholder where the server-rendered markup
should injected:
You should replace <div>app-html-to-replace</div>
to the server-rendered markup
.
We have to build the SSR application twice, one for client
(browser) and one for server
(Node.js). So farm.config.ts
and farm.config.server.ts
are needed, we'll discuss the details in later sections.
Setting up Dev Server
For above example, farm.config.ts
is used to build the project for browser and setting up DevServer for server rendering. The content of farm.config.ts
normally would be:
In above example, a middleware
is required for rendering the application to markup and serve it as html. Normal workflow for SSR in the middleware
:
- Load compiled server entry: A
index-server
entry which exports arender
function is required, we need toimport(server_entry_path)
to get therender
function. - Get compiled client index.html: All client bundles and Farm runtime are injected to
index.html
, so the client canhydrate
successfully. - Replace the placeholder to rendered markup: Replace the placeholder and return the
final html
.
In this example, we are building a SPA
SSR application with if (ctx.path === '/' || ctx.status === 404) {
, if you are building a MPA
SSR application, guard ctx.path
to your pages.
Building for Node.js
farm.config.server.ts
is used to build the project for Node.js, producing the compiled server entry which can be used to rendering the application to markup on the server side.
For farm.config.server.ts
, we set input
to server entry and output.targetEnv
to node
.
By default, Farm compiles server entry script to esm
, if you want to compile it to cjs
, try set output.format
.
Develop SSR Project
You have start compilation for both client
and server
, for example, you may have following scripts
in package.json
:
When starting your SSR project, you should run both npm run start
and npm run start:server
in different terminal.
Building for Production
You have build both client
and server
, for example, you may add following command to scripts
:
When building for production, you should run both npm run build
and npm run build:server
, the client bundles will be emitted to build
dir, and the server bundles will be emitted to dist
dir.
For production, you need a node server
for rendering
and serving rendered html
, in this example, we provide a server.js
as production server:
We use express
as server here, but you can use whatever server frameworks you want. The rendering process are the same:
- Loading client compiled html
- Loading
render
function from compiled server script - Call
const markup = render(url)
function to get the server-side rendered markup of your application - Replace the
placeholder
inclient index.html
to therendered markup
and return the replaced html as final result
Static-Site Generation(SSG)
The same flow of SSG is the same as SSR, the difference is SSG that emits to replaced html
to the final resources. Example scripts for SSG: