Logo

dev-resources.site

for different kinds of informations.

Create an SSR Application with Vite, React, React Query and React Router

Published at
1/10/2025
Categories
vitejs
ssr
react
reactquery
Author
yracnet
Categories
4 categories in total
vitejs
open
ssr
open
react
open
reactquery
open
Author
7 person written this
yracnet
open
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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
  • 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/
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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>
  );
};
Enter fullscreen mode Exit fullscreen mode

Important Note: PageServer uses suspense: true in all requests to ensure proper SSR rendering. On the other hand, PageBrowser uses suspense: 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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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
      },
    },
  },
});
Enter fullscreen mode Exit fullscreen mode

7. Development and Production

7.1 Development Server

Run the development server:

yarn dev
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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.
Enter fullscreen mode Exit fullscreen mode

The build will generate:

/dist/
  β”œβ”€β”€ app.js           # Application runtime
  β”œβ”€β”€ client/          # SSR public assets
  └── client/spa/      # SPA public assets
Enter fullscreen mode Exit fullscreen mode

7.3 Sanbox Production Server Configuration

For production deployment, you can configure sanbox server settings using a private directory:

  1. 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"
  }
}
Enter fullscreen mode Exit fullscreen mode
  1. Create /private/.env for server configuration:
SERVER_HOST=127.0.0.1
SERVER_PORT=4000
Enter fullscreen mode Exit fullscreen mode

To start the production server:

cd dist
yarn start
Enter fullscreen mode Exit fullscreen mode

or

cd dist # The directory is a Sandbox project
yarn install
yarn start
Enter fullscreen mode Exit fullscreen mode

Note: The server will be running at: http://127.0.0.1:4000/myapp

Additional Resources

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:

ssr Article's
30 articles in total
Favicon
Custom builder for Angular: My way
Favicon
Setting Up Dual Compilation (SSR + CSR) in ViteJS with vite-plugin-builder
Favicon
# Key New Features in React Router 7: Embracing the Remix Future
Favicon
Beginner SEO in React JS - React Helmet
Favicon
Setting up partial SSR for a React + TypeScript + webpack app from scratch
Favicon
Create an SSR Application with Vite, React, React Query and React Router
Favicon
Understanding Web Rendering: Performance Implications and Use Cases
Favicon
Make EditorJS work in Svelte(kit) SSR
Favicon
Client-side Rendering & Server-side Rendering
Favicon
A Practical Guide to CSR and SSR with React 19 and esbuild
Favicon
Fixing SSR Rendering Issues with Angular Resolver for Async Pipe Data
Favicon
Choosing Remix as a Server-Side Rendering (SSR) Framework
Favicon
Implementing Server-Side Rendering (SSR) with Next.js and Firebase for SEO-Friendly React Apps πŸš€
Favicon
Do You Need to SSR Your Web Components?
Favicon
Web Components and SSR - 2024 Edition
Favicon
Dark side of Next.js - App Router
Favicon
How to achieve unified management of four types of global state data in Vue3?
Favicon
What do SSR, CSR, ISR and SSG mean? A complete guide for web developers
Favicon
Vue 3.5 β€œTengen Toppa Gurren Lagann” Innovations: Advanced Features and Most Powerful Updates πŸš€
Favicon
Inertiajs Server-side Rendering (SSR) For React (ViteΒ Setup)
Favicon
Vaadin, the battery-included server-side AJAX framework
Favicon
How to add Supabase Auth to Astro
Favicon
Dive into Next.js Server-Side Rendering (SSR): From SPA to ISR
Favicon
Why do client components render as SSR in nextjs, marking components as "use client" still render its html as SSR why?
Favicon
Augmenting the client with Alpine.js
Favicon
Augmenting the client with Vue.js
Favicon
Server-Side Rendering (SSR): Uma Solução para SEO e Performance em Aplicaçáes React
Favicon
SSR and CSR Explained
Favicon
A short history of AJAX and SSR
Favicon
How to Do Server-Side Rendering (SSR) in Next.js

Featured ones: