fix(build): disable prerender crawl so build stops OOMing

`/hikes` is `prerender = true` and carries the global nav, so the
prerender crawler followed those links and tried to statically render
the whole dynamic, DB-/ML-backed app. SvelteKit prerenders inside a
heap-capped worker_threads worker, so this exhausted its heap
(ERR_WORKER_OUT_OF_MEMORY) and failed the build.

- svelte.config.js: prerender.crawl = false. The intended static set is
  fully described by `prerender = true` (/hikes) + the /errors/[status]
  EntryGenerator, so crawling is unneeded. Add a defensive
  handleHttpError that ignores /hikes/*/images/* 404s (those binaries
  live in hikes-assets/, served by nginx/dev-middleware, not /static).
- hooks.server.ts: skip init when `building` so builds don't connect to
  Mongo, start the payment scheduler, or warm the romcal cache.
- hikes/[slug]: set `prerender = false`, enforcing the intent its
  comment already stated.

Version 1.86.1 -> 1.86.2.
This commit is contained in:
2026-05-24 15:41:39 +02:00
parent c155fc33b4
commit 530308033b
4 changed files with 35 additions and 2 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "homepage",
"version": "1.86.1",
"version": "1.86.2",
"private": true,
"type": "module",
"scripts": {
+10
View File
@@ -1,6 +1,7 @@
import type { Handle, HandleServerError, ServerInit } from "@sveltejs/kit"
import { redirect } from "@sveltejs/kit"
import { sequence } from "@sveltejs/kit/hooks"
import { building } from "$app/environment"
import * as auth from "./auth"
import { initializeScheduler } from "./lib/server/scheduler"
import { dbConnect } from "./utils/db"
@@ -122,6 +123,15 @@ async function timing({ event, resolve }: Parameters<Handle>[0]) {
}
export const init: ServerInit = async () => {
// SvelteKit runs prerendering/analysis inside a worker_threads worker (see
// @sveltejs/kit utils/fork.js) whose JS heap is capped well below the main
// thread's. `init` fires there too, so warming the romcal cache during a
// build exhausts that worker's heap → ERR_WORKER_OUT_OF_MEMORY and a failed
// build. None of it is needed at build time: no prerendered route touches the
// DB, and connecting to Mongo / starting the payment scheduler from a build
// is undesirable regardless. Skip startup work while building.
if (building) return;
console.log('🚀 Server starting - initializing database connection...');
try {
await dbConnect();
+5 -1
View File
@@ -4,7 +4,11 @@ import type { PageLoad } from './$types';
// Not prerendered: the page needs the live session so private images can be
// gated behind login. Performance hit is small — the page is mostly hashed
// static assets (track JSON, image variants).
// static assets (track JSON, image variants). Without this flag the prerender
// crawler still followed the overview's hike links and rendered every detail
// page at build time, which exhausted the prerender worker's heap
// (ERR_WORKER_OUT_OF_MEMORY); `false` keeps the crawler from prerendering them.
export const prerender = false;
// Glob the .svx modules so Vite can pre-bundle them and we can resolve
// the matching one synchronously at load time.
+19
View File
@@ -21,6 +21,25 @@ const config = {
adapter: adapter({
precompress: true // Enable brotli and gzip compression
}),
prerender: {
// The only intentionally-static pages are /hikes (prerender=true) and
// the /errors/[status] set (via that route's EntryGenerator). With the
// crawler on, it follows the global nav out of /hikes and tries to
// prerender the whole dynamic, DB-/ML-backed app — which runs the
// forked prerender worker out of heap (ERR_WORKER_OUT_OF_MEMORY) and
// fails the build. Disable crawling: the prerendered set is then driven
// entirely by `prerender = true` + EntryGenerator.
crawl: false,
handleHttpError: ({ path, message }) => {
// Defensive: hike image binaries live in `hikes-assets/`, outside
// `/static` (nginx serves them in prod, a Vite middleware in dev —
// see vite.config.ts), so the crawler can't fetch them. Harmless
// while crawl is off, but keeps a 404 from failing the build if
// crawling is ever re-enabled.
if (/^\/hikes\/[^/]+\/images\//.test(path)) return;
throw new Error(message);
}
},
alias: {
$models: 'src/models',
$utils: 'src/utils',