docs: markdown-rendering aus snapshot in svelte-build verschoben

Der Snapshot liefert content_markdown, nicht content_html. Rendering
(marked + DOMPurify + highlight.js) passiert im SvelteKit-Prerender-
Schritt über das bereits existierende \$lib/render/markdown.ts —
keine Duplikation in Deno, kein gemeinsames Policy-Modul nötig.

Für Blaupausen-Nutzung ist rohes Markdown portabler: alternative
Renderer (Astro, Eleventy) bringen eigenen Markdown-Prozessor mit.

Konsequenz für Migration: Schritt 1 ist jetzt \"renderMarkdown
Node-kompatibel machen\" (isomorphic-dompurify) statt \"shared/
markdown-policy.ts ergänzen\".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jörg Lohrer 2026-04-21 17:08:10 +02:00
parent 48d05f8d2d
commit fd093dff5e
1 changed files with 24 additions and 19 deletions

View File

@ -139,15 +139,16 @@ Neues Deno-Modul. Verzeichnis: `snapshot/` als Geschwister zu `publish/`.
schreiben wenn verfügbar. Beide tot: primäre URL trotzdem schreiben + schreiben wenn verfügbar. Beide tot: primäre URL trotzdem schreiben +
Warnung loggen (Blossom ist content-addressed, URL wird später wieder Warnung loggen (Blossom ist content-addressed, URL wird später wieder
erreichbar sein). erreichbar sein).
7. **Markdown-zu-HTML-Rendering.** Body des Events wird mit `marked` 7. **Kein Markdown-Rendering im Snapshot.** Body des Events wird als
gerendert, dann mit `DOMPurify` gemäß gemeinsamer Policy sanitized, rohes `content_markdown` ins JSON geschrieben. Das Rendering zu HTML
dann Code-Blöcke mit `highlight.js` hervorgehoben. Gemeinsame übernimmt der SvelteKit-Prerender-Schritt mit dem bereits existierenden
Konfiguration (Allowlist, Syntax-Sprachen) liegt als Konstanten-Modul `$lib/render/markdown.ts`-Modul (marked + DOMPurify + highlight.js).
in `shared/markdown-policy.ts` und wird von Snapshot **und** SPA **Begründung:** Der SvelteKit-Build führt `renderMarkdown()` ohnehin
identisch importiert. Ergebnis wird als `content_html` ins JSON aus; eine Duplikation in Deno wäre doppelter Code-Pfad mit identischer
geschrieben. Das rohe `content_markdown` bleibt ebenfalls im JSON Policy. Für Blaupausen-Nutzung ist rohes Markdown zudem portabler —
(Debuggability, alternative Renderer, die der HTML-Sanitization nicht jeder andere Renderer (Astro, Eleventy, …) bringt seinen eigenen
trauen). Markdown-Prozessor mit und würde fertiges HTML eher als Bürde
empfinden.
8. **Fallback-Politik für fehlende Felder:** 8. **Fallback-Politik für fehlende Felder:**
- fehlt `summary` im Event → aus `content_markdown` die ersten 200 - fehlt `summary` im Event → aus `content_markdown` die ersten 200
Zeichen (Whitespace normalisiert, abgeschnitten an Wortgrenze, Zeichen (Whitespace normalisiert, abgeschnitten an Wortgrenze,
@ -198,8 +199,7 @@ Neues Deno-Modul. Verzeichnis: `snapshot/` als Geschwister zu `publish/`.
"alt": "Alt-Text", "alt": "Alt-Text",
"mime": "image/jpeg" "mime": "image/jpeg"
}, },
"content_html": "<p>…sanitized HTML with highlighted code blocks…</p>", "content_markdown": "…full markdown body, raw — Renderer sanitizes und rendert on demand…",
"content_markdown": "…full markdown, raw, for debugging or alternative renderers…",
"tags": ["Nostr", "Bibel"], "tags": ["Nostr", "Bibel"],
"naddr": "naddr1...", "naddr": "naddr1...",
"habla_url": "https://habla.news/a/naddr1...", "habla_url": "https://habla.news/a/naddr1...",
@ -290,8 +290,11 @@ Die Route rendert den Snapshot-Content statt Relay-Fetch. Im
- `<script type="application/ld+json">` mit `Article`-Schema - `<script type="application/ld+json">` mit `Article`-Schema
- `<html lang="...">` aus `snapshot.lang` (via Layout) - `<html lang="...">` aus `snapshot.lang` (via Layout)
Post-Body wird direkt aus `snapshot.content_html` eingesetzt Post-Body wird aus `snapshot.content_markdown` per `renderMarkdown()`
(`{@html …}`), da der HTML bereits im Snapshot-Schritt sanitized ist. zur Build-Zeit zu HTML gerendert und dann via `{@html …}` eingesetzt.
Die bestehende `$lib/render/markdown.ts` wird so angepasst, dass sie
im Node-Build-Kontext funktioniert (Umstellung auf
`isomorphic-dompurify` oder äquivalente Build-Zeit-DOM-Bereitstellung).
`ReplyList`/`ReplyComposer` bleiben clientseitig unverändert. `ReplyList`/`ReplyComposer` bleiben clientseitig unverändert.
Der SPA-interne Sprach-Switcher liest `snapshot.translations[]` direkt Der SPA-interne Sprach-Switcher liest `snapshot.translations[]` direkt
@ -369,17 +372,19 @@ Inkrementell, jeder Schritt einzeln testbar und rollback-bar. Jeder
Schritt hat eine eigene Rollback-Strategie, sodass die Gesamtänderung Schritt hat eine eigene Rollback-Strategie, sodass die Gesamtänderung
an keiner Stelle einen Big-Bang bildet: an keiner Stelle einen Big-Bang bildet:
1. **`shared/markdown-policy.ts` ergänzen.** Gemeinsame marked- + 1. **`renderMarkdown` Node-kompatibel machen.** DOM-Abhängigkeit auf
DOMPurify- + highlight.js-Konfiguration als importierbares Modul. `isomorphic-dompurify` umstellen, sodass das Modul sowohl im Browser
Rollback: Datei löschen. als auch im SvelteKit-Build-Node-Kontext funktioniert.
Unit-Test-Verhalten gegen Regression sichern. Rollback: Commit revert.
2. **Snapshot-Modul ergänzen.** `snapshot/` mit Deno-Task, CLI, Tests. 2. **Snapshot-Modul ergänzen.** `snapshot/` mit Deno-Task, CLI, Tests.
Keine Änderung an SPA. Rollback: Verzeichnis löschen. Schreibt JSON mit `content_markdown`, keine HTML-Erzeugung. Keine
Änderung an SPA. Rollback: Verzeichnis löschen.
3. **Snapshot in CI einbauen.** GitHub-Actions-Schritt vor SvelteKit-Build. 3. **Snapshot in CI einbauen.** GitHub-Actions-Schritt vor SvelteKit-Build.
Rollback: Workflow-Schritt entfernen. Rollback: Workflow-Schritt entfernen.
4. **SvelteKit-Route auf Prerender umstellen.** `[...slug]/+page.ts` 4. **SvelteKit-Route auf Prerender umstellen.** `[...slug]/+page.ts`
bekommt `prerender = true` + `entries()` + Load aus JSON. bekommt `prerender = true` + `entries()` + Load aus JSON.
`+page.svelte` rendert aus Snapshot. Rollback: Commit revert, alte `+page.svelte` rendert `content_markdown` per `renderMarkdown()` zur
Runtime-Logik kommt zurück. Build-Zeit. Rollback: Commit revert, alte Runtime-Logik kommt zurück.
5. **SPA-Relay-Fetch in Detail-Seite komplett abschalten.** Nur noch 5. **SPA-Relay-Fetch in Detail-Seite komplett abschalten.** Nur noch
Snapshot-Content. Rollback: Commit revert. Snapshot-Content. Rollback: Commit revert.
6. **Deploy-Script erweitern.** `lftp mirror --delete` mit 6. **Deploy-Script erweitern.** `lftp mirror --delete` mit