Skip to content

Build Your Own SSR/SSG From Scratch with Vite and React

Published:

Today, we’ll try to uncover how NextJS, RemixJS and many other SSR frameworks work under the hood. Even though they are very complicated frameworks the fundamental idea is in fact very straightforward. As an end-user, we can’t really see the simple steps - building SSR out of React components or just simple HTML and JS - due to lots of abstraction in the frameworks to make our lives easier. But, today we will try to deep dive and see what hides beneath all the abstraction and explore the concept itself.

Table of Contents

Open Table of Contents

SSG on top of SSR

Since we already know the concepts by now this will be a walk in the park.

prerender.js

import fs from "node:fs";
import path from "node:path";
import { fileURLToPath } from "url";

const __dirname = path.dirname(fileURLToPath(import.meta.url));
const toAbsolute = p => path.resolve(__dirname, p);

const template = fs.readFileSync(toAbsolute("dist/static/index.html"), "utf-8");
const render = (await import("./dist/server/entry-server.js")).SSRRender;

// determine routes to pre-render from src/pages
const routesToPrerender = fs.readdirSync(toAbsolute("src/pages")).map(file => {
  const name = file.replace(/\.tsx$/, "").toLowerCase();
  return name === "home" ? `/` : `/${name}`;
});

(async () => {
  // pre-render each route...
  for (const url of routesToPrerender) {
    const appHtml = render(url);

    const html = template.replace(`<!--app-html-->`, appHtml);

    const filePath = `dist/static${url === "/" ? "/index" : url}.html`;
    fs.writeFileSync(toAbsolute(filePath), html);
  }
})();

This function uses the same logic as SSR and creates separate files for each page that are known ahead of time, but we won’t be able to change anything after the build phase. That’s why it is called ‘Static’. Following that approach is extremely valuable for sites like blogs, documentation sites, E-commerce product listings. Basically, things that do not change often.

To run this code,

npm run generate

Then, use a tool like Serve to run generated code,

serve dist/static

I hope we’ve uncovered some of the underlying logic of SSR and SSG and helped you understand the thought processes better.

Stay tuned.