Server side rendering
EffCSS allows to create stylesheets on the server side. You can serialize styles and metadata and use it for Server-side rendering (SSR) or Static site generation (SSG).
Serialization
EffCSS offers two utilities for serializing stylesheets:
serializereturns an HTML string that contains<style>tags with CSS styles,serializeMetareturns an HTML string that contains<script type="application/json">tags with metadata.
Typically, using only the serialize utility is sufficient; these styles will be reused on the client side. However, the contract utilities (classNames and attributes) will still execute their code to calculate contract selectors. If you find these calculations resource-intensive, use serializeMeta; then the classNames and attributes utilities will use selectors from the metadata without additional calculations.
Thus, for SSG and simple SSR it is enough to use serialize, and serializeMeta is needed for advanced SSR.
Example
Below is a simplified React SSR example:
import { StrictMode } from 'react';
import { renderToString } from 'react-dom/server';
import App from './App';
import { serialize, serializeMeta } from 'effcss';
export function render(_url) {
const html = renderToString(
<StrictMode>
<App />
</StrictMode>
);
const styles = serialize();
const metadata = serializeMeta();
const head = styles + metadata;
return { html, head };
}import { StrictMode } from "react";
import { hydrateRoot } from "react-dom/client";
import App from "./App";
hydrateRoot(
document.getElementById("root"),
<StrictMode>
<App />
</StrictMode>
);import fs from "node:fs/promises";
import express from "express";
const app = express();
// There should be constants and server settings here,
// but rendering is more important for this example
// Serve HTML
app.use("*all", async (req, res) => {
try {
const url = req.originalUrl.replace(base, "");
let template;
let render;
if (!isProduction) {
template = await fs.readFile("./index.html", "utf-8");
template = await vite.transformIndexHtml(url, template);
render = (await vite.ssrLoadModule("/src/entry-server.tsx")).render;
} else {
template = templateHtml;
render = (await import("./dist/server/entry-server.js")).render;
}
const rendered = await render(url);
const source = template.replace(`<!--app-html-->`, rendered.html ?? "");
const html = source.replace(`<!--app-head-->`, rendered.head ?? "");
res.status(200).set({ "Content-Type": "text/html" }).send(html);
} catch (e) {
vite?.ssrFixStacktrace(e);
res.status(500).end(e.stack);
}
});
// Start http server
app.listen(port, () => {
console.log(`Server started at http://localhost:${port}`);
});