dev-resources.site
for different kinds of informations.
Create an SSR Application with Vite, React, React Query and React Router
Create an SSR Application with Vite, React, React Query and React Router
In this tutorial, we will create a server-side rendered (SSR) application using Vite, React, React Query, React Bootstrap, and React Router. We'll also configure the vite-plugin-ssr-kit
plugin to handle SSR rendering.
Prerequisites
Before starting, ensure you have:
- Node.js installed (version 20 or higher)
- Yarn package manager
- Basic knowledge of React and vite ecosystem
1. Create the Application
First, create a new Vite project with the React template:
yarn create vite my-ssr-app --template react
cd my-ssr-app
2. Install Required Libraries
Install the following dependencies:
yarn add react-router-dom@^6.28.0 react-bootstrap react-query vite-plugin-ssr-kit vite-plugin-pages
Let's understand what each package does:
-
react-router-dom@^6.28.0: Handles routing in React applications. We use version 6.28.0 specifically because version 7.x requires Remix framework.
- Provides components like
Route
,Link
, and routing hooks - Enables client-side navigation
- Manages URL parameters and query strings
- Provides components like
-
react-bootstrap: React components that implement Bootstrap's design system.
- Provides pre-built, responsive UI components
- Includes navigation, forms, cards, and other UI elements
- No need to write Bootstrap classes manually
-
react-query: Powerful data synchronization library for React.
- Manages server state in React applications
- Provides hooks for data fetching, caching, and updates
- Handles loading and error states automatically
-
vite-plugin-ssr-kit: Plugin that enables server-side rendering in Vite applications.
- Handles SSR configuration and setup
- Provides utilities for SSR lifecycle management
- Manages client/server code splitting
-
vite-plugin-pages: File system based routing plugin for Vite.
- Creates routes based on file structure
- Supports dynamic routes
- Integrates with react-router-dom
3. Configure Project Structure
3.1 Move the Index File
Move the /index.html
file to /spa/index.html
. This separation allows us to maintain both SSR and SPA versions of the application:
mkdir spa
mv index.html spa/
Note: The /spa/index.html file will serve as the entry point for the SPA version, while SSR will use a different entry point.
3.2 Create SSR Directory Structure
Create the necessary directories for SSR:
mkdir -p ssr/pages/posts/$id
4. Create the Root Document
Create /ssr/root.jsx
to define the root document structure for server-side rendering:
import { LiveReload } from "@ssr/liveReload.jsx";
import { ViteScripts } from "@ssr/viteScripts.jsx";
import { Container, Nav, Navbar } from "react-bootstrap";
import { Link, Outlet } from "react-router-dom";
export const RootDocument = () => {
return (
<html lang="en">
<head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React SSR</title>
<link rel="icon" href="vite.svg" type="image/svg" />
<link
href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"
rel="stylesheet"
/>
<LiveReload />
</head>
<body>
<Container>
<Navbar bg="light" expand="lg">
<Navbar.Brand href="/myapp/">Vite SSR</Navbar.Brand>
<Navbar.Toggle aria-controls="navbarNav" />
<Navbar.Collapse id="navbarNav">
<Nav className="me-auto">
<Nav.Link to="/" as={Link}>
Home
</Nav.Link>
<Nav.Link to="/posts" as={Link}>
Posts
</Nav.Link>
<Nav.Link href="/myapp/spa">Vite SPA Entry</Nav.Link>
</Nav>
</Navbar.Collapse>
</Navbar>
</Container>
<Container>
<Outlet />
</Container>
<ViteScripts />
</body>
</html>
);
};
Important Note: PageServer uses
suspense: true
in all requests to ensure proper SSR rendering. On the other hand, PageBrowser usessuspense: false
to allow smooth client-side navigation. This setup guarantees correct SSR rendering while preventing flickering and inconsistencies between the server-rendered content and the client-side state during hydration.
5. Create Application Pages
5.1 Home Page
Create /ssr/pages/index.jsx
:
import { Container, Button } from "react-bootstrap";
import { Link } from "react-router-dom";
export default function HomePage() {
return (
<Container>
<h1>Welcome to the Vite + React SSR App</h1>
<Button as={Link} to="/posts">
Go to Posts
</Button>
</Container>
);
}
5.2 Posts List Page
Create /ssr/pages/posts/index.jsx
:
import { Card, Col, Row } from "react-bootstrap";
import { useQuery } from "react-query";
import { Link } from "react-router-dom";
const getPosts = () =>
fetch("https://jsonplaceholder.typicode.com/posts")
.then((r) => r.json())
.catch((e) => {
throw e;
});
export default function PostsPage() {
const { data = [] } = useQuery("posts", getPosts);
return (
<div>
<Row>
{data.map((post) => (
<Col key={post.id} sm={12} md={6} lg={4} className="mb-4">
<Card>
<Card.Body>
<Card.Title>{post.title}</Card.Title>
<Card.Text>{post.body}</Card.Text>
<Card.Link as={Link} to={`/posts/${post.id}`}>
Read More
</Card.Link>
</Card.Body>
</Card>
</Col>
))}
</Row>
</div>
);
}
5.3 Single Post Page
Create /ssr/pages/posts/$id/index.jsx
: (Note: Using $id for Remix-style routing)
import { Card } from "react-bootstrap";
import { useQuery } from "react-query";
import { Link, useParams } from "react-router-dom";
const getPost = (id) =>
fetch("https://jsonplaceholder.typicode.com/posts/" + id)
.then((r) => r.json())
.catch((e) => {
throw e;
});
export default function PostPage() {
const { id } = useParams();
const { data = {} } = useQuery(["posts", id], () => getPost(id));
return (
<Card>
<Card.Header>{data.title}</Card.Header>
<Card.Body>
<Card.Text>{data.body}</Card.Text>
<Card.Link as={Link} to="/posts">
Back to Posts
</Card.Link>
</Card.Body>
</Card>
);
}
6. Configure Vite
Modify the existing vite.config.js
file:
import react from "@vitejs/plugin-react";
import { defineConfig } from "vite";
import pages from "vite-plugin-pages";
import ssr from "vite-plugin-ssr-kit";
export default defineConfig({
base: "/myapp",
plugins: [
react(),
pages({
routeStyle: "remix", // Important: This enables Remix-style routing ($id instead of [id])
dirs: "ssr/pages",
}),
ssr({
rootDocument: "ssr/root.jsx",
}),
],
build: {
rollupOptions: {
input: {
spa: "spa/index.html", // Include the original React SPA entry point
},
},
},
});
7. Development and Production
7.1 Development Server
Run the development server:
yarn dev
Access your application at:
- SSR version:
http://localhost:5173/myapp
- SPA version:
http://localhost:5173/myapp/spa
7.2 Production Build
Build the application:
yarn build
You should see output similar to this:
yarn run v1.22.22
$ vite build
vite v6.0.7 building for production...
CLIENT BUILD
vite v4.5.5 building for production...
β 396 modules transformed.
dist/client/spa/index.html 0.64 kB β gzip: 0.35 kB
dist/client/manifest.json 1.49 kB β gzip: 0.38 kB
dist/client/assets/react-35ef61ed.svg 4.13 kB β gzip: 2.05 kB
dist/client/assets/index-a36d8b68.css 1.39 kB β gzip: 0.72 kB
dist/client/chunks/index-600303c7.js 0.46 kB β gzip: 0.32 kB
dist/client/chunks/index-ef84de97.js 0.55 kB β gzip: 0.37 kB
dist/client/assets/spa-dc418d3e.js 0.94 kB β gzip: 0.50 kB
dist/client/chunks/preload-753c2a40.js 1.70 kB β gzip: 0.89 kB
dist/client/assets/main-79767691.js 2.74 kB β gzip: 1.16 kB
dist/client/chunks/vendor-d8646257.js 240.50 kB β gzip: 75.98 kB
β built in 1.33s
SERVER BUILD
vite v4.5.5 building SSR bundle for production...
β 13 modules transformed.
dist/bin/index-066b4199.js 0.81 kB
dist/bin/index-b8b66606.js 0.92 kB
dist/bin/virtual-6df6f849.js 0.98 kB
dist/app.js 1.22 kB
dist/bin/ssr-27500c0d.js 4.52 kB
β built in 52ms
β 31 modules transformed.
β built in 1.92s
Done in 2.43s.
The build will generate:
/dist/
βββ app.js # Application runtime
βββ client/ # SSR public assets
βββ client/spa/ # SPA public assets
7.3 Sanbox Production Server Configuration
For production deployment, you can configure sanbox server settings using a private directory:
- Create
/private/package.json
for server-specific dependencies
{
"name": "app",
"private": true,
"type": "module",
"scripts": {
"start": "node app.js"
},
"dependencies": {
"react": "^18.3.1",
"react-bootstrap": "^2.10.7",
"react-dom": "^18.3.1",
"react-query": "^3.39.3",
"react-router-dom": "^6.28.0"
}
}
- Create
/private/.env
for server configuration:
SERVER_HOST=127.0.0.1
SERVER_PORT=4000
To start the production server:
cd dist
yarn start
or
cd dist # The directory is a Sandbox project
yarn install
yarn start
Note: The server will be running at: http://127.0.0.1:4000/myapp
Additional Resources
- For a complete working example, visit the GitHub repository and check the
packages/examples/my-ssr-app
directory. - For more information about the SSR Kit plugin, refer to the vite-plugin-ssr-kit documentation.
Summary
This tutorial has shown you how to:
- Set up a Vite project with SSR capabilities
- Integrate React Query, React Bootstrap, and React Router
- Create both SSR and SPA versions of your application
- Configure development and production environments
- Handle server-side rendering of React components
The resulting application provides a solid foundation for building performant, server-rendered React applications while maintaining the option to serve a traditional SPA version when needed.
Additional Resources
For more detailed information and resources related to vite-plugin-ssr-kit
, please refer to the following:
- npm Package: vite-plugin-ssr-kit
- GitHub Repository: yracnet/vite-plugin-ssr-kit
Featured ones: