SSG and SSR
Sercrod is a small runtime that works directly on DOM elements and attributes. This makes it easy to use in static site generation (SSG) and server-side rendering (SSR) pipelines: any environment that can load HTML, run JavaScript, and serialize the DOM can pre-render Sercrod hosts.
This page describes patterns and considerations for using Sercrod in SSG / SSR. It does not depend on any particular build tool, but some sections mention the official Playwright-based renderer used for this site.
Client-only rendering
The simplest way to use Sercrod is to load sercrod.js in the browser
and let it run on the client only. In that case:
- your HTML is served as-is from the server,
- the browser downloads
sercrod.js, - Sercrod scans the DOM, creates hosts, and applies directives,
- and the final result exists only in the browser.
This mode is enough for small sites, prototypes, and internal tools where search engine indexing and first-paint speed are not critical.
Pre-rendering with a headless browser
For SSG and SSR, you can run the same Sercrod code in a headless browser (such as Chromium via Playwright) or in a DOM implementation that supports the required APIs. At a high level, a build step looks like this:
- Load an HTML file that includes your Sercrod templates.
- Run
sercrod.jsso that directives expand into normal HTML. - Optionally remove Sercrod directives and event handlers from the DOM.
- Serialize the DOM and write out the result as static HTML.
You can use this pattern with a single page, or loop over many input files to generate an entire static site.
Layout template and partials (official renderer)
The official Sercrod site uses a small renderer based on Node, Playwright, and Chromium. It separates the layout template from per-page content:
-
A layout template such as
template.htmlthat contains the common<head>, header, and footer. It also contains a placeholder element where the page content is inserted. -
Per-page partials that define
<main>...and an optional data block (for example, title and description).
Template example
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title *print="title"></title>
<meta name="description" :content="description">
</head>
<body>
<header>
<!-- shared header / navigation -->
</header>
<!-- partial content will be inserted here -->
<template data-sercrod-runtime="partial"></template>
<footer>
<!-- shared footer -->
</footer>
</body>
</html>
Partial example
<script type="application/sercrod-partial">
partial.data = {
title: "Example page",
description: "One page rendered through a shared template.",
terminator: null
};
</script>
<main id="example">
<section>
<h1>Example</h1>
<p>This content is inserted into the layout template.</p>
</section>
</main>
The renderer does the following for each requested page:
- Read the partial file and evaluate the
application/sercrod-partialscript to getpartial.data. - Strip that script from the partial HTML and keep the remaining
<main>...markup. - Open
template.htmlin a headless browser and injectpartial.dataas the host data for the template. - Run Sercrod in the headless browser to expand directives in the template.
- Replace the placeholder in the template with the partial HTML.
- Serialize the final DOM and write it to the output directory as static HTML.
Rendered output (static HTML)
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Example page</title>
<meta name="description" content="One page rendered through a shared template.">
</head>
<body>
<header>
<!-- shared header / navigation -->
</header>
<main id="example">
<section>
<h1>Example</h1>
<p>This content is inserted into the layout template.</p>
</section>
</main>
<footer>
<!-- shared footer -->
</footer>
</body>
</html>
This pattern keeps the layout in one place while letting each page define its own content and metadata.
builder and server roles
In the official setup, the build pipeline is split into two small programs:
-
builder (for example,
builder.js) Receives a URL or path (such as/docs/guide/first-page.html), normalizes it, and sends an HTTP request to the local build server. -
server (for example,
server.js) Listens on a local port, maps the URL to a partial file and output file, runs the Playwright + Sercrod build step, and writes the result.
This separation makes it easy to trigger builds from an editor, from a command line, or from other tools, without duplicating the rendering logic.
The full example code for the builder and server lives in the repository and can be reused or adapted for other sites.
Cleaning up directives in SSR
In many SSG / SSR setups you will want the final HTML to contain no Sercrod directives or event attributes. Instead, you only keep the expanded HTML.
Sercrod exposes cleanup options through
window.__Sercrod.config.cleanup. When enabled, Sercrod removes
its directive attributes and event handlers from the DOM after they are
applied.
The official Playwright-based renderer configures these cleanup settings
on the server side during the build step, so you do not need to add
anything special to template.html or your partials. If you
build your own SSR pipeline, see the Config
reference for the exact flags and their behavior.
Notes and limitations
- Make sure the headless environment supports the DOM APIs you use inside Sercrod handlers and filters.
-
Avoid relying on
window-specific features (such as layout measurements) during the build step, unless your SSR tool provides them. -
If you keep
sercrod.jsin the final HTML, the page can stay interactive after hydration. If you omit it, the pre-rendered HTML will be static. - For Node and Playwright setup (installation and basic commands), see the environment setup guide in the documentation.
Sercrod itself stays agnostic of which SSG or SSR tool you use. The only requirement is that the tool can execute JavaScript and give you back the resulting HTML.