Something went wrong. Try again.
Monorepo for Tangled forked from tangled.org/core
Something went wrong. Try again.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364import { getContext, setContext } from "svelte";import type { FileOptions } from "@pierre/diffs";import type { MarkupContext } from "#lib/markup/paths.ts";
// past any of these limits the browser renders it insteadconst MAX_DOCUMENT_CHARS = 256 * 1024;const MAX_PAGE_CHARS = 1024 * 1024;// html gets its own cap because highlighted code comes out around 15x its sourceconst MAX_PAGE_HTML_CHARS = 1024 * 1024;// counts the wait for a worker too. a render past it gets its worker replacedconst RENDER_TIMEOUT_MS = 2_000;// the full source already ships in the page dataexport const PLAIN_PREVIEW_CHARS = 2 * 1024;export const RENDER_QUEUE_WAIT_MS = 500;export const MAX_RENDER_WORKERS = 4;export const RENDER_WORKER_HEAP_MB = 128;// in characters, which is 32 to 64 mib of heapexport const RENDER_CACHE_CHARS = 32 * 1024 * 1024;export const RENDER_CACHE_MAX_HEAP_SHARE = 0.7;// a document that hangs the renderer hangs it once per ttl, not once per requestexport const FAILED_RENDER_TTL_MS = 10 * 60 * 1000;
export type RenderTask = | { kind: "markup"; source: string; ctx: MarkupContext } | { kind: "file"; name: string; contents: string; options: FileOptions<undefined, undefined> };
export interface SsrBudget { chars: number; html: number;}
const BUDGET_KEY = Symbol("ssr-budget");
const freshBudget = (): SsrBudget => ({ chars: MAX_PAGE_CHARS, html: MAX_PAGE_HTML_CHARS });
export const setSsrBudget = (): void => { setContext<SsrBudget>(BUDGET_KEY, freshBudget());};
/** a tree rendered without the root layout, like a component test, gets a fresh budget */export const getSsrBudget = (): SsrBudget | undefined => import.meta.env.SSR ? (getContext<SsrBudget | undefined>(BUDGET_KEY) ?? freshBudget()) : undefined;
export const fitsServerRender = (size: number): boolean => size <= MAX_DOCUMENT_CHARS;
export const renderOnServer = async ( budget: SsrBudget, size: number, task: () => RenderTask): Promise<string | null> => { // keeps node:worker_threads out of the client bundle if (!import.meta.env.SSR || !fitsServerRender(size) || size > budget.chars) return null; budget.chars -= size; const { render } = await import("#lib/ssr/pool.ts"); // html rarely comes out shorter than its source. skip it once the budget can't fit that const html = await render(task(), RENDER_TIMEOUT_MS, budget, () => budget.html >= size); // which render gets dropped here depends on the order they finish in if (html === null || html.length > budget.html) return null; budget.html -= html.length; return html;};