@rshono/core 1.0.0-rc.22 → 1.0.0-rc.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"ssg.js","sourceRoot":"","sources":["../../src/server/ssg.ts"],"names":[],"mappings":"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","sourcesContent":["import { mkdirSync, writeFileSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { dirname, join, resolve, sep } from 'node:path';\nimport { isPageRoute, type PageRoute, type Route } from '../router.js';\nimport {\n createPageCache,\n PRERENDER_NONCE_HEADER,\n ssgFilePath,\n SSG_MANIFEST_FILE,\n toPrerenderedPage,\n VARIANTS,\n type PrerenderedPage,\n type PrerenderVariant,\n} from './prerendered.js';\n\n/**\n * Stand-in origin for a build that declared no `siteUrl`. Obviously wrong rather than a guess, so a page that\n * bakes it into a canonical tag is easy to spot; the build warns as well.\n */\nconst DEFAULT_SSG_ORIGIN = 'http://localhost';\n\n/**\n * Resolves `siteUrl` to the origin prerendering renders against. A path is rejected rather than dropped:\n * `'https://example.com/docs'` means the author expects a base path, which is not supported.\n */\nexport function resolveSiteOrigin(siteUrl: string | undefined): string {\n if (!siteUrl) return DEFAULT_SSG_ORIGIN;\n const parsed = URL.parse(siteUrl);\n if (!parsed || (parsed.protocol !== 'http:' && parsed.protocol !== 'https:')) {\n throw new Error(`[rshono] invalid siteUrl ${JSON.stringify(siteUrl)} — use a full origin, e.g. 'https://example.com'.`);\n }\n if (parsed.pathname !== '/' || parsed.search || parsed.hash) {\n throw new Error(`[rshono] siteUrl ${JSON.stringify(siteUrl)} must be a bare origin — a base path is not supported.`);\n }\n return parsed.origin;\n}\n\n/**\n * A route's path with its params filled in, ready to render and to store.\n *\n * Throws for a pattern `staticPaths` cannot fill and for a set that does not fill it. Both are warned about\n * and skipped by the caller, which already names the route — so these messages are the reason alone, written\n * to be read at the end of that line.\n */\nfunction interpolatePath(pattern: string, params: Record<string, string>): string {\n return pattern\n .split('/')\n .map((segment) => {\n if (!segment.startsWith(':')) {\n if (segment.includes('*')) {\n throw new Error(`wildcard segments are not supported by staticPaths`);\n }\n return segment;\n }\n const name = segment.slice(1);\n if (!/^\\w+$/.test(name)) {\n throw new Error(`optional/regex params are not supported by staticPaths`);\n }\n const value = params[name];\n if (value === undefined) {\n throw new Error(`staticPaths returned a param set without \"${name}\"`);\n }\n return encodeURIComponent(value);\n })\n .join('/');\n}\n\n/** Prerendered pages, keyed by the request that produced them (see {@link readPrerendered}). */\nconst pageCache = createPageCache();\n\n/** One in-flight or settled read of each store's {@link SSG_MANIFEST_FILE}; the file cannot change while the server is up. */\nconst storeIndexes = new Map<string, Promise<ReadonlySet<string> | null>>();\n\n/**\n * What `ssgDir` holds, as {@link ssgFilePath} names it — or `null` where the build left no manifest, which\n * is every build made before there was one. A `null` gates nothing, so those keep the behaviour they had.\n */\nfunction storeIndex(ssgDir: string): Promise<ReadonlySet<string> | null> {\n let pending = storeIndexes.get(ssgDir);\n if (!pending) {\n // One `catch` for both failures worth the same answer: no manifest, and a manifest that is not one.\n pending = readFile(join(ssgDir, SSG_MANIFEST_FILE), 'utf8')\n .then((text) => new Set((JSON.parse(text) as { files?: string[] }).files ?? []) as ReadonlySet<string>)\n .catch(() => null);\n storeIndexes.set(ssgDir, pending);\n }\n return pending;\n}\n\nexport async function readPrerendered(ssgDir: string, requestPath: string, variant: PrerenderVariant = 'html'): Promise<PrerenderedPage | null> {\n // Keyed by what the request carried rather than by the resolved filename, so a hit costs one Map lookup. Safe\n // because only *hits* are cached: an entry exists only if this exact key already passed the checks below.\n const key = `${ssgDir}\\0${variant}\\0${requestPath}`;\n const cached = pageCache.get(key);\n if (cached) return cached;\n\n const relPath = ssgFilePath(requestPath, variant);\n if (relPath === null) return null;\n\n // Before the store is touched: a `render: 'static'` route whose build wrote nothing — no `staticPaths`, a\n // param the build never saw, a page that did not render cleanly — falls through to SSR on every request,\n // and without this each of those pays a failed read first, forever.\n const index = await storeIndex(ssgDir);\n if (index && !index.has(relPath)) return null;\n // Belt and braces over the shared traversal guard: this proves the resolved file is under the root.\n const root = resolve(ssgDir);\n const file = resolve(root, relPath);\n if (!file.startsWith(root + sep)) return null;\n\n // No encoding argument: the bytes are what gets served. Copied out of the Buffer rather than kept as one,\n // because `readFile` can hand back a view into Node's shared pool and this is retained for the process.\n let body: Uint8Array<ArrayBuffer>;\n try {\n body = new Uint8Array(await readFile(file));\n } catch {\n return null;\n }\n\n const page = await toPrerenderedPage(body);\n pageCache.set(key, page);\n return page;\n}\n\ninterface PrerenderOptions {\n routes: readonly Route[];\n fetch: (request: Request) => Response | Promise<Response>;\n ssgDir: string;\n /** The origin absolute URLs in the output are built against — `siteUrl` from `rshono.config.ts`. */\n siteUrl?: string;\n}\n\nexport interface PrerenderResult {\n written: string[];\n skipped: string[];\n /**\n * The subset of {@link written} whose *document* the deployment will not serve, because the app mints a CSP\n * nonce on that path — see {@link PRERENDER_NONCE_HEADER}. Their flight payloads are served from disk like\n * any other, so these are half-prerendered pages rather than skipped ones, and the caller says so.\n */\n flightOnly: string[];\n}\n\n/**\n * Records what the pass wrote, beside what it wrote. Written by the same pass for the same reason\n * {@link ssgFilePath} is one function: an index that disagrees with the store is invisible, so the two are\n * produced together or not at all.\n */\nfunction writeManifest(ssgDir: string, files: readonly string[]): void {\n mkdirSync(ssgDir, { recursive: true });\n writeFileSync(join(ssgDir, SSG_MANIFEST_FILE), `${JSON.stringify({ files }, null, 2)}\\n`);\n}\n\n/**\n * How many paths are rendered at once.\n *\n * A prerender pass spends its time inside the app — a page's own data fetching is what each render awaits —\n * so a few hundred `staticPaths` entries rendered one at a time pay all of that latency in series.\n * Unbounded is the other wrong answer: it points the whole site at the app's database in one go. Eight keeps\n * a build's peak load recognisable while hiding most of the wait.\n */\nconst RENDER_CONCURRENCY = 8;\n\n/**\n * `items.map(run)` with at most `limit` running at once, results in input order.\n *\n * A worker pool rather than fixed batches: a batch is only as fast as its slowest member, so one slow page\n * would idle the rest of its batch.\n */\nasync function mapBounded<T, R>(items: readonly T[], limit: number, run: (item: T) => Promise<R>): Promise<R[]> {\n const results = new Array<R>(items.length);\n let next = 0;\n const worker = async (): Promise<void> => {\n for (let index = next++; index < items.length; index = next++) results[index] = await run(items[index]);\n };\n await Promise.all(Array.from({ length: Math.min(limit, items.length) }, worker));\n return results;\n}\n\n/**\n * One representation of a path, as the app answered for it at build time. Discriminated on `ok` because both\n * callers have to tell \"the app rendered this\" from \"it did not\", and only one cares why.\n *\n * `failed` splits the second case in two. A 404, a 3xx or a payload of the wrong type is a page this pass\n * cannot *store*, and it still serves per request — the skip is honest. A 5xx is the app throwing, and this\n * pass renders a page exactly as a request does, so per request it will throw again: skipping it prints\n * \"will SSR per request\" over a route that will 500 forever, and exits 0.\n */\ntype RenderedVariant = { ok: true; body: Uint8Array; nonced: boolean } | { ok: false; reason: string; failed: boolean };\n\nasync function renderVariant(fetch: PrerenderOptions['fetch'], url: string, variant: PrerenderVariant): Promise<RenderedVariant> {\n const response = await fetch(new Request(url, { headers: VARIANTS[variant].headers }));\n if (response.status !== 200) return { ok: false, reason: `${response.status}`, failed: response.status >= 500 };\n if (!(response.headers.get('Content-Type') ?? '').includes(VARIANTS[variant].contentType)) {\n return { ok: false, reason: `a non-${VARIANTS[variant].contentType} response`, failed: false };\n }\n // Bytes, not `response.text()`. That is a *non-fatal* UTF-8 decode, so every byte of a binary row in a\n // flight payload — `emitChunk` puts raw typed-array bytes on the wire — becomes U+FFFD, and writing the\n // string back out spends three real bytes on each one. The page is then prerendered and unparseable.\n // The header is the framework saying this render minted a CSP nonce; on a flight payload it is never set.\n return { ok: true, body: new Uint8Array(await response.arrayBuffer()), nonced: response.headers.get(PRERENDER_NONCE_HEADER) !== null };\n}\n\n/** A path the pass will render, resolved far enough that nothing left can fail the build. */\ninterface PrerenderTarget {\n path: string;\n /** Where a request for it will look — {@link ssgFilePath}, resolved before the render rather than after. */\n relPath: string;\n}\n\nexport async function prerenderStaticRoutes(options: PrerenderOptions): Promise<PrerenderResult> {\n const { routes, fetch, ssgDir } = options;\n const staticRoutes = routes.filter((r): r is PageRoute => isPageRoute(r) && r.render === 'static');\n const origin = resolveSiteOrigin(options.siteUrl);\n\n if (staticRoutes.length > 0 && !options.siteUrl) {\n console.warn(\n ` ⚠ No siteUrl in rshono.config — prerendered pages are built against ${DEFAULT_SSG_ORIGIN}, so any absolute URL\\n` +\n ` they derive from a page's \\`url\\` prop (canonical tags, og:url, absolute links) will point there.`,\n );\n }\n\n const written: string[] = [];\n const skipped: string[] = [];\n /** Pages whose document was written and will never be read — see {@link PrerenderResult.flightOnly}. */\n const flightOnly: string[] = [];\n /** Every file written, as the reader names it — {@link writeManifest}. */\n const files: string[] = [];\n\n /** Every path to render, in route order, each one once. Built before anything renders — see below. */\n const targets: PrerenderTarget[] = [];\n /** So a `staticPaths` entry that repeats — or that a second route also produces — is rendered once. */\n const queued = new Set<string>();\n\n for (const route of staticRoutes) {\n let paths: string[];\n if (!/[:*]/.test(route.path)) {\n paths = [route.path];\n } else {\n if (!route.staticPaths) {\n console.warn(` ⚠ Static route \"${route.path}\" has params but no staticPaths — will SSR per request.`);\n skipped.push(route.path);\n continue;\n }\n try {\n paths = (await route.staticPaths()).map((params) => interpolatePath(route.path, params));\n } catch (error) {\n // A route whose paths cannot be computed — a wildcard or a regex/optional param, which `staticPaths`\n // has no way to fill, or a set it filled wrongly — is unprerenderable, not unservable. It gets the\n // same answer as the branch above rather than killing a build the route would have survived: the\n // page is still there, rendered per request.\n const reason = error instanceof Error ? error.message : String(error);\n console.warn(` ⚠ Static route \"${route.path}\" will SSR per request — ${reason.replace(/\\.$/, '')}.`);\n skipped.push(route.path);\n continue;\n }\n }\n\n let duplicates = 0;\n for (const path of paths) {\n if (queued.has(path)) {\n duplicates++;\n continue;\n }\n queued.add(path);\n // Resolved *before* the render, so a path no file can hold fails the build naming the path, rather than\n // after the work and as a bare `join(dir, null)` TypeError. The same call answers for the reader, which\n // is the whole point: a page written under a name the request path never resolves to is a page the build\n // reports as prerendered and nothing ever serves. Resolved in this pass rather than the next one for a\n // second reason too: which of several bad paths fails the build should not depend on render order.\n const relPath = ssgFilePath(path, 'html');\n if (relPath === null) {\n throw new Error(\n `[rshono] Cannot prerender \"${path}\" for route \"${route.path}\": a path segment is \".\" or \"..\", or cannot be ` +\n 'one portable file name. It must not hold \\\\ / : * ? \" < > | or a control character, must not end in ' +\n '\".\" or a space (Windows stores the name without it, so the page lands where nothing looks for it), ' +\n 'and must not be a reserved device name — CON, PRN, AUX, NUL, COM0-9 or LPT0-9, with or without an extension.',\n );\n }\n targets.push({ path, relPath });\n }\n if (duplicates > 0) {\n console.warn(` ⚠ Static route \"${route.path}\" repeated ${duplicates} path${duplicates === 1 ? '' : 's'} — each page is prerendered once.`);\n }\n }\n\n const outcomes = await mapBounded(targets, RENDER_CONCURRENCY, async ({ path, relPath }) => {\n /** Buffered, so a concurrent pass logs in the same order a serial one did. */\n const warnings: string[] = [];\n const document = await renderVariant(fetch, origin + path, 'html');\n if (!document.ok) {\n // A 5xx fails the build instead of being warned about — see {@link RenderedVariant}.\n if (!document.failed) warnings.push(` ⚠ \"${path}\" rendered ${document.reason} at build time — skipping, will SSR per request.`);\n return { path, ok: false as const, files: [], warnings, failure: document.failed ? document.reason : undefined, nonced: false };\n }\n\n // Both representations of a page share its directory and differ only in the file name.\n const pageDir = join(ssgDir, dirname(relPath));\n const wrote: string[] = [];\n const write = (variant: PrerenderVariant, body: Uint8Array) => {\n mkdirSync(pageDir, { recursive: true });\n writeFileSync(join(pageDir, VARIANTS[variant].file), body);\n // `ssgFilePath` again rather than the `join` above: the manifest is read against what a *request*\n // resolves to, which is that function's output and not a filesystem path.\n wrote.push(ssgFilePath(path, variant)!);\n };\n write('html', document.body);\n\n // The soft-navigation representation of the same page. Best-effort: the document is valid on its own, and\n // serving falls back to rendering the flight payload per request.\n const flight = await renderVariant(fetch, origin + path, 'flight');\n if (flight.ok) {\n write('flight', flight.body);\n } else {\n // Not fatal the way a failed *document* is, even for a 5xx: the page is on disk and serves, and only\n // soft navigation to it degrades to rendering per request. The reason is named because the two cases\n // want different things done about them.\n warnings.push(` ⚠ \"${path}\" produced no flight payload (${flight.reason}) — soft navigations to it will render per request.`);\n }\n\n return { path, ok: true as const, files: wrote, warnings, failure: undefined, nonced: document.nonced };\n });\n\n // Folded back in target order rather than completion order, so a concurrent pass writes the same manifest\n // and prints the same log a serial one did.\n const failures: string[] = [];\n for (const outcome of outcomes) {\n for (const warning of outcome.warnings) console.warn(warning);\n if (outcome.failure !== undefined) failures.push(`\"${outcome.path}\" rendered ${outcome.failure}`);\n if (!outcome.ok) {\n skipped.push(outcome.path);\n continue;\n }\n files.push(...outcome.files);\n written.push(outcome.path);\n if (outcome.nonced) flightOnly.push(outcome.path);\n }\n\n // Raised together, and in target order, so which of several failing pages is reported does not depend on\n // which render finished first. The render's own error is already in the build log above: the framework's\n // `onError` reported it when it turned the throw into the 500 counted here.\n if (failures.length > 0) {\n throw new Error(\n `[rshono] ${failures.length} page${failures.length === 1 ? '' : 's'} failed to render while prerendering:\\n` +\n failures.map((failure) => ` • ${failure}`).join('\\n') +\n '\\n Prerendering renders a page the way a request does, so this is not a build-only failure — the route' +\n '\\n would answer the same status per request. The error it threw is logged above.',\n );\n }\n\n // After the failure check, so a build that is about to stop does not spend three lines on advice. Once\n // rather than per page: under a global nonce policy this is every static page in the app, and the same\n // sentence repeated a hundred times says no more than one does — the caller's summary line is what names\n // them, marked there.\n //\n // The documents are written all the same. Whether a nonce is minted is a request-time decision, and an\n // app is free to switch its policy on from the environment, so a build that saw one is not proof the\n // deployment has one — dropping the file would cost a page its prerender on the strength of a guess.\n if (flightOnly.length > 0) {\n console.warn(\n ` ⚠ ${flightOnly.length} page(s) mint a CSP nonce, so the framework re-renders their document per request:\\n` +\n ` only the flight payload is served from disk. The documents are written anyway, in case the policy is\\n` +\n ` off where this is deployed. Marked \"flight only\" in the summary below.`,\n );\n }\n\n // Only where the app has static routes at all: an empty manifest would be a store, and a build with\n // nothing to prerender should leave no `ssg/` directory for a preset to carry around.\n if (staticRoutes.length > 0) writeManifest(ssgDir, files);\n\n return { written, skipped, flightOnly };\n}\n"]}
1
+ {"version":3,"file":"ssg.js","sourceRoot":"","sources":["../../src/server/ssg.ts"],"names":[],"mappings":"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","sourcesContent":["import { mkdirSync, writeFileSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { dirname, join, resolve, sep } from 'node:path';\nimport { isPageRoute, type PageRoute, type Route } from '../router.js';\nimport {\n createPageCache,\n getPrerenderFlight,\n PRERENDER_NONCE_HEADER,\n ssgFilePath,\n SSG_MANIFEST_FILE,\n toPrerenderedPage,\n VARIANTS,\n type PrerenderedPage,\n type PrerenderVariant,\n} from './prerendered.js';\n\n/**\n * Stand-in origin for a build that declared no `siteUrl`. Obviously wrong rather than a guess, so a page that\n * bakes it into a canonical tag is easy to spot; the build warns as well.\n */\nconst DEFAULT_SSG_ORIGIN = 'http://localhost';\n\n/**\n * Resolves `siteUrl` to the origin prerendering renders against. A path is rejected rather than dropped:\n * `'https://example.com/docs'` means the author expects a base path, which is not supported.\n */\nexport function resolveSiteOrigin(siteUrl: string | undefined): string {\n if (!siteUrl) return DEFAULT_SSG_ORIGIN;\n const parsed = URL.parse(siteUrl);\n if (!parsed || (parsed.protocol !== 'http:' && parsed.protocol !== 'https:')) {\n throw new Error(`[rshono] invalid siteUrl ${JSON.stringify(siteUrl)} — use a full origin, e.g. 'https://example.com'.`);\n }\n if (parsed.pathname !== '/' || parsed.search || parsed.hash) {\n throw new Error(`[rshono] siteUrl ${JSON.stringify(siteUrl)} must be a bare origin — a base path is not supported.`);\n }\n return parsed.origin;\n}\n\n/**\n * A route's path with its params filled in, ready to render and to store.\n *\n * Throws for a pattern `staticPaths` cannot fill and for a set that does not fill it. Both are warned about\n * and skipped by the caller, which already names the route — so these messages are the reason alone, written\n * to be read at the end of that line.\n */\nfunction interpolatePath(pattern: string, params: Record<string, string>): string {\n return pattern\n .split('/')\n .map((segment) => {\n if (!segment.startsWith(':')) {\n if (segment.includes('*')) {\n throw new Error(`wildcard segments are not supported by staticPaths`);\n }\n return segment;\n }\n const name = segment.slice(1);\n if (!/^\\w+$/.test(name)) {\n throw new Error(`optional/regex params are not supported by staticPaths`);\n }\n const value = params[name];\n if (value === undefined) {\n throw new Error(`staticPaths returned a param set without \"${name}\"`);\n }\n return encodeURIComponent(value);\n })\n .join('/');\n}\n\n/** Prerendered pages, keyed by the request that produced them (see {@link readPrerendered}). */\nconst pageCache = createPageCache();\n\n/** One in-flight or settled read of each store's {@link SSG_MANIFEST_FILE}; the file cannot change while the server is up. */\nconst storeIndexes = new Map<string, Promise<ReadonlySet<string> | null>>();\n\n/**\n * What `ssgDir` holds, as {@link ssgFilePath} names it — or `null` where the build left no manifest, which\n * is every build made before there was one. A `null` gates nothing, so those keep the behaviour they had.\n */\nfunction storeIndex(ssgDir: string): Promise<ReadonlySet<string> | null> {\n let pending = storeIndexes.get(ssgDir);\n if (!pending) {\n // One `catch` for both failures worth the same answer: no manifest, and a manifest that is not one.\n pending = readFile(join(ssgDir, SSG_MANIFEST_FILE), 'utf8')\n .then((text) => new Set((JSON.parse(text) as { files?: string[] }).files ?? []) as ReadonlySet<string>)\n .catch(() => null);\n storeIndexes.set(ssgDir, pending);\n }\n return pending;\n}\n\nexport async function readPrerendered(ssgDir: string, requestPath: string, variant: PrerenderVariant = 'html'): Promise<PrerenderedPage | null> {\n // Keyed by what the request carried rather than by the resolved filename, so a hit costs one Map lookup. Safe\n // because only *hits* are cached: an entry exists only if this exact key already passed the checks below.\n const key = `${ssgDir}\\0${variant}\\0${requestPath}`;\n const cached = pageCache.get(key);\n if (cached) return cached;\n\n const relPath = ssgFilePath(requestPath, variant);\n if (relPath === null) return null;\n\n // Before the store is touched: a `render: 'static'` route whose build wrote nothing — no `staticPaths`, a\n // param the build never saw, a page that did not render cleanly — falls through to SSR on every request,\n // and without this each of those pays a failed read first, forever.\n const index = await storeIndex(ssgDir);\n if (index && !index.has(relPath)) return null;\n // Belt and braces over the shared traversal guard: this proves the resolved file is under the root.\n const root = resolve(ssgDir);\n const file = resolve(root, relPath);\n if (!file.startsWith(root + sep)) return null;\n\n // No encoding argument: the bytes are what gets served. Copied out of the Buffer rather than kept as one,\n // because `readFile` can hand back a view into Node's shared pool and this is retained for the process.\n let body: Uint8Array<ArrayBuffer>;\n try {\n body = new Uint8Array(await readFile(file));\n } catch {\n return null;\n }\n\n const page = await toPrerenderedPage(body);\n pageCache.set(key, page);\n return page;\n}\n\ninterface PrerenderOptions {\n routes: readonly Route[];\n fetch: (request: Request) => Response | Promise<Response>;\n ssgDir: string;\n /** The origin absolute URLs in the output are built against — `siteUrl` from `rshono.config.ts`. */\n siteUrl?: string;\n}\n\nexport interface PrerenderResult {\n written: string[];\n skipped: string[];\n /**\n * The subset of {@link written} whose *document* the deployment will not serve, because the app mints a CSP\n * nonce on that path — see {@link PRERENDER_NONCE_HEADER}. Their flight payloads are served from disk like\n * any other, so these are half-prerendered pages rather than skipped ones, and the caller says so.\n */\n flightOnly: string[];\n}\n\n/**\n * Records what the pass wrote, beside what it wrote. Written by the same pass for the same reason\n * {@link ssgFilePath} is one function: an index that disagrees with the store is invisible, so the two are\n * produced together or not at all.\n */\nfunction writeManifest(ssgDir: string, files: readonly string[]): void {\n mkdirSync(ssgDir, { recursive: true });\n writeFileSync(join(ssgDir, SSG_MANIFEST_FILE), `${JSON.stringify({ files }, null, 2)}\\n`);\n}\n\n/**\n * How many paths are rendered at once.\n *\n * A prerender pass spends its time inside the app — a page's own data fetching is what each render awaits —\n * so a few hundred `staticPaths` entries rendered one at a time pay all of that latency in series.\n * Unbounded is the other wrong answer: it points the whole site at the app's database in one go. Eight keeps\n * a build's peak load recognisable while hiding most of the wait.\n */\nconst RENDER_CONCURRENCY = 8;\n\n/**\n * `items.map(run)` with at most `limit` running at once, results in input order.\n *\n * A worker pool rather than fixed batches: a batch is only as fast as its slowest member, so one slow page\n * would idle the rest of its batch.\n */\nasync function mapBounded<T, R>(items: readonly T[], limit: number, run: (item: T) => Promise<R>): Promise<R[]> {\n const results = new Array<R>(items.length);\n let next = 0;\n const worker = async (): Promise<void> => {\n for (let index = next++; index < items.length; index = next++) results[index] = await run(items[index]);\n };\n await Promise.all(Array.from({ length: Math.min(limit, items.length) }, worker));\n return results;\n}\n\n/**\n * One representation of a path, as the app answered for it at build time. `failed` splits the failure case in\n * two: a 404, a 3xx or a payload of the wrong type is a page this pass cannot store, and it still serves per\n * request — the skip is honest. A 5xx is the app throwing, and this pass renders a page exactly as a request\n * does, so per request it will throw again: skipping it prints \"will SSR per request\" over a route that will\n * 500 forever, and exits 0.\n */\ntype RenderedVariant = { ok: true; body: Uint8Array; nonced: boolean; flight?: Promise<Uint8Array> } | { ok: false; reason: string; failed: boolean };\n\n/** A missing or failed capture degrades only soft navigation; the document remains a valid prerender. */\nasync function renderSharedFlight(capture: Promise<Uint8Array> | undefined): Promise<{ ok: true; body: Uint8Array } | { ok: false; reason: string }> {\n if (!capture) return { ok: false, reason: 'the shared Flight payload was unavailable' };\n try {\n return { ok: true, body: await capture };\n } catch (error) {\n const reason =\n error instanceof Error && error.message ? `the shared Flight capture failed: ${error.message}` : 'the shared Flight capture failed';\n return { ok: false, reason };\n }\n}\n\n/**\n * Makes the one build-time request for a concrete path and keeps the shared Flight branch with its document.\n *\n * The response body is still HTML; the optional branch is only consumed by the SSG writer. A missing or\n * rejected branch therefore degrades Flight to a request-time render without discarding the document.\n */\nasync function renderDocument(fetch: PrerenderOptions['fetch'], url: string): Promise<RenderedVariant> {\n const response = await fetch(new Request(url));\n const flight = getPrerenderFlight(response);\n if (response.status !== 200) {\n void response.body?.cancel().catch(() => {});\n return { ok: false, reason: `${response.status}`, failed: response.status >= 500 };\n }\n if (!(response.headers.get('Content-Type') ?? '').includes('text/html')) {\n void response.body?.cancel().catch(() => {});\n return { ok: false, reason: 'a non-text/html response', failed: false };\n }\n return {\n ok: true,\n body: new Uint8Array(await response.arrayBuffer()),\n nonced: response.headers.get(PRERENDER_NONCE_HEADER) !== null,\n flight,\n };\n}\n\n/** A path the pass will render, resolved far enough that nothing left can fail the build. */\ninterface PrerenderTarget {\n path: string;\n /** Where a request for it will look — {@link ssgFilePath}, resolved before the render rather than after. */\n relPath: string;\n}\n\nexport async function prerenderStaticRoutes(options: PrerenderOptions): Promise<PrerenderResult> {\n const { routes, fetch, ssgDir } = options;\n const staticRoutes = routes.filter((r): r is PageRoute => isPageRoute(r) && r.render === 'static');\n const origin = resolveSiteOrigin(options.siteUrl);\n\n if (staticRoutes.length > 0 && !options.siteUrl) {\n console.warn(\n ` ⚠ No siteUrl in rshono.config — prerendered pages are built against ${DEFAULT_SSG_ORIGIN}, so any absolute URL\\n` +\n ` they derive from a page's \\`url\\` prop (canonical tags, og:url, absolute links) will point there.`,\n );\n }\n\n const written: string[] = [];\n const skipped: string[] = [];\n /** Pages whose document was written and will never be read — see {@link PrerenderResult.flightOnly}. */\n const flightOnly: string[] = [];\n /** Every file written, as the reader names it — {@link writeManifest}. */\n const files: string[] = [];\n\n /** Every path to render, in route order, each one once. Built before anything renders — see below. */\n const targets: PrerenderTarget[] = [];\n /** So a `staticPaths` entry that repeats — or that a second route also produces — is rendered once. */\n const queued = new Set<string>();\n\n for (const route of staticRoutes) {\n let paths: string[];\n if (!/[:*]/.test(route.path)) {\n paths = [route.path];\n } else {\n if (!route.staticPaths) {\n console.warn(` ⚠ Static route \"${route.path}\" has params but no staticPaths — will SSR per request.`);\n skipped.push(route.path);\n continue;\n }\n try {\n paths = (await route.staticPaths()).map((params) => interpolatePath(route.path, params));\n } catch (error) {\n // A route whose paths cannot be computed — a wildcard or a regex/optional param, which `staticPaths`\n // has no way to fill, or a set it filled wrongly — is unprerenderable, not unservable. It gets the\n // same answer as the branch above rather than killing a build the route would have survived: the\n // page is still there, rendered per request.\n const reason = error instanceof Error ? error.message : String(error);\n console.warn(` ⚠ Static route \"${route.path}\" will SSR per request — ${reason.replace(/\\.$/, '')}.`);\n skipped.push(route.path);\n continue;\n }\n }\n\n let duplicates = 0;\n for (const path of paths) {\n if (queued.has(path)) {\n duplicates++;\n continue;\n }\n queued.add(path);\n // Resolved *before* the render, so a path no file can hold fails the build naming the path, rather than\n // after the work and as a bare `join(dir, null)` TypeError. The same call answers for the reader, which\n // is the whole point: a page written under a name the request path never resolves to is a page the build\n // reports as prerendered and nothing ever serves. Resolved in this pass rather than the next one for a\n // second reason too: which of several bad paths fails the build should not depend on render order.\n const relPath = ssgFilePath(path, 'html');\n if (relPath === null) {\n throw new Error(\n `[rshono] Cannot prerender \"${path}\" for route \"${route.path}\": a path segment is \".\" or \"..\", or cannot be ` +\n 'one portable file name. It must not hold \\\\ / : * ? \" < > | or a control character, must not end in ' +\n '\".\" or a space (Windows stores the name without it, so the page lands where nothing looks for it), ' +\n 'and must not be a reserved device name — CON, PRN, AUX, NUL, COM0-9 or LPT0-9, with or without an extension.',\n );\n }\n targets.push({ path, relPath });\n }\n if (duplicates > 0) {\n console.warn(` ⚠ Static route \"${route.path}\" repeated ${duplicates} path${duplicates === 1 ? '' : 's'} — each page is prerendered once.`);\n }\n }\n\n const outcomes = await mapBounded(targets, RENDER_CONCURRENCY, async ({ path, relPath }) => {\n /** Buffered, so a concurrent pass logs in the same order a serial one did. */\n const warnings: string[] = [];\n const document = await renderDocument(fetch, origin + path);\n if (!document.ok) {\n // A 5xx fails the build instead of being warned about — see {@link RenderedVariant}.\n if (!document.failed) warnings.push(` ⚠ \"${path}\" rendered ${document.reason} at build time — skipping, will SSR per request.`);\n return { path, ok: false as const, files: [], warnings, failure: document.failed ? document.reason : undefined, nonced: false };\n }\n\n // Both representations of a page share its directory and differ only in the file name.\n const pageDir = join(ssgDir, dirname(relPath));\n const wrote: string[] = [];\n const write = (variant: PrerenderVariant, body: Uint8Array) => {\n mkdirSync(pageDir, { recursive: true });\n writeFileSync(join(pageDir, VARIANTS[variant].file), body);\n // `ssgFilePath` again rather than the `join` above: the manifest is read against what a *request*\n // resolves to, which is that function's output and not a filesystem path.\n wrote.push(ssgFilePath(path, variant)!);\n };\n write('html', document.body);\n\n // The inline Flight reader captured these bytes from the same RSC evaluation. Best-effort: the document\n // remains valid if capture fails, and soft navigation then renders Flight per request.\n const flight = await renderSharedFlight(document.flight);\n if (flight.ok) {\n write('flight', flight.body);\n } else {\n // Not fatal: the page is on disk and serves, and only soft navigation to it degrades to rendering per\n // request. The reason is named because a missing shared branch is different from a failed document.\n warnings.push(` ⚠ \"${path}\" produced no flight payload (${flight.reason}) — soft navigations to it will render per request.`);\n }\n\n return { path, ok: true as const, files: wrote, warnings, failure: undefined, nonced: document.nonced };\n });\n\n // Folded back in target order rather than completion order, so a concurrent pass writes the same manifest\n // and prints the same log a serial one did.\n const failures: string[] = [];\n for (const outcome of outcomes) {\n for (const warning of outcome.warnings) console.warn(warning);\n if (outcome.failure !== undefined) failures.push(`\"${outcome.path}\" rendered ${outcome.failure}`);\n if (!outcome.ok) {\n skipped.push(outcome.path);\n continue;\n }\n files.push(...outcome.files);\n written.push(outcome.path);\n if (outcome.nonced) flightOnly.push(outcome.path);\n }\n\n // Raised together, and in target order, so which of several failing pages is reported does not depend on\n // which render finished first. The render's own error is already in the build log above: the framework's\n // `onError` reported it when it turned the throw into the 500 counted here.\n if (failures.length > 0) {\n throw new Error(\n `[rshono] ${failures.length} page${failures.length === 1 ? '' : 's'} failed to render while prerendering:\\n` +\n failures.map((failure) => ` • ${failure}`).join('\\n') +\n '\\n Prerendering renders a page the way a request does, so this is not a build-only failure — the route' +\n '\\n would answer the same status per request. The error it threw is logged above.',\n );\n }\n\n // After the failure check, so a build that is about to stop does not spend three lines on advice. Once\n // rather than per page: under a global nonce policy this is every static page in the app, and the same\n // sentence repeated a hundred times says no more than one does — the caller's summary line is what names\n // them, marked there.\n //\n // The documents are written all the same. Whether a nonce is minted is a request-time decision, and an\n // app is free to switch its policy on from the environment, so a build that saw one is not proof the\n // deployment has one — dropping the file would cost a page its prerender on the strength of a guess.\n if (flightOnly.length > 0) {\n console.warn(\n ` ⚠ ${flightOnly.length} page(s) mint a CSP nonce, so the framework re-renders their document per request:\\n` +\n ` only the flight payload is served from disk. The documents are written anyway, in case the policy is\\n` +\n ` off where this is deployed. Marked \"flight only\" in the summary below.`,\n );\n }\n\n // Only where the app has static routes at all: an empty manifest would be a store, and a build with\n // nothing to prerender should leave no `ssg/` directory for a preset to carry around.\n if (staticRoutes.length > 0) writeManifest(ssgDir, files);\n\n return { written, skipped, flightOnly };\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rshono/core",
3
- "version": "1.0.0-rc.22",
3
+ "version": "1.0.0-rc.23",
4
4
  "description": "Minimalist web framework — Hono + Rspack + React Server Components",
5
5
  "author": "Lasse <lasse@lassetange.com> (https://www.lassetange.com)",
6
6
  "license": "MIT",
@@ -52,7 +52,7 @@
52
52
  },
53
53
  "dependencies": {
54
54
  "@hono/node-server": "^2.1.1",
55
- "@rspack/core": "2.2.6",
55
+ "@rspack/core": "2.2.7",
56
56
  "@rspack/plugin-react-refresh": "2.0.2",
57
57
  "react-refresh": "0.18.0",
58
58
  "react-server-dom-rspack": "0.1.0"