Worker-thread SSR and SSG for the Scratchy framework. Manages a Piscina worker pool for server-side rendering, exposes a Fastify plugin, an SSR route handler factory, an SSG pipeline, and low-level SharedArrayBuffer / Redis communication helpers for main-thread ↔ worker data exchange.
pnpm add @scratchyjs/rendererimport rendererPlugin from "@scratchyjs/renderer/plugin";
import { resolve } from "node:path";
await server.register(rendererPlugin, {
worker: resolve(import.meta.dirname, "worker.js"),
minThreads: 2,
maxThreads: 8,
taskTimeout: 30_000,
});
// Now available:
// server.piscina — the Piscina pool
// server.runTask() — dispatch a render taskimport { createSSRHandler } from "@scratchyjs/renderer";
fastify.get(
"/*",
createSSRHandler({
getProps: (request) => ({ user: request.user }),
}),
);import { runSsgPipeline } from "@scratchyjs/renderer";
const results = await runSsgPipeline({
routes: ["/", "/about", "/blog"],
runTask: server.runTask,
outputDir: "./dist",
});import {
BufferStatus,
createSharedBuffer,
readFromBuffer,
writeToBuffer,
} from "@scratchyjs/renderer";
// Main thread — create and write
const shared = createSharedBuffer(64 * 1024); // 64 KB payload area
writeToBuffer(shared, { route: "/about", user: null });
// Worker thread — read
const data = readFromBuffer<{ route: string }>(shared);import {
cleanupRenderContext,
getRenderContext,
storeRenderContext,
storeRenderResult,
} from "@scratchyjs/renderer";
// Main thread
await storeRenderContext(redis, requestId, { route, props });
// Worker thread
const context = await getRenderContext(redis, requestId);
const html = await render(context);
await storeRenderResult(redis, requestId, html);
// Cleanup
await cleanupRenderContext(redis, requestId);import { wrapInShell } from "@scratchyjs/renderer";
const fullHtml = wrapInShell(renderedBody, {
title: "My App",
lang: "en",
head: '<meta name="description" content="My App">',
});Registers a Piscina pool and decorates the server with fastify.piscina and
fastify.runTask(). The pool is closed automatically on server shutdown.
Options (RendererPluginOptions)
| Option | Default | Description |
|---|---|---|
worker |
— | Absolute path to the worker entry file |
minThreads |
2 |
Minimum live worker threads |
maxThreads |
max(4, cpus) |
Maximum worker threads |
idleTimeout |
60000 |
ms before an idle worker is terminated |
taskTimeout |
30000 |
ms before a task is aborted |
maxOldGenerationSizeMb |
512 |
V8 heap limit per worker (MB) |
Returns a Fastify route handler that dispatches an SSR task via
fastify.runTask() and sends the resulting HTML.
Generates static HTML for a list of routes and writes them to outputDir.
Creates a SharedArrayBuffer-backed buffer for zero-copy inter-thread
communication.
Serialises data to JSON, writes it into the shared buffer, and signals
DATA_READY.
Waits for DATA_READY, deserialises, and returns the payload. Throws on timeout
or error status.
Constants: IDLE, DATA_READY, CONSUMED, ERROR.
Redis helpers for distributed main-thread ↔ worker communication with configurable TTLs.
Wraps a rendered HTML body in a full HTML shell.