Files
Harlekin e0b03ea336
Prüfung / Lint, Typen, Tests (push) Canceled after 0s
Prüfung / Images bauen (pdf) (push) Canceled after 0s
Prüfung / Images bauen (web) (push) Canceled after 0s
Prüfung / Images bauen (worker) (push) Canceled after 0s
Images / bauen (pdf, docker/pdf.Dockerfile) (push) Canceled after 0s
Images / bauen (web, docker/web.Dockerfile) (push) Canceled after 0s
Images / bauen (worker, docker/worker.Dockerfile) (push) Canceled after 0s
Gedankenstriche durch Bindestriche ersetzt
375 Vorkommen in 210 Dateien. Betrifft Kommentare, Oberflaechentexte und die
README; an keiner Stelle Bedeutung, nur Zeichensetzung.
2026-09-04 08:54:52 +02:00

80 lines
2.2 KiB
TypeScript

'use client'
import { useEffect } from 'react'
import { usePathname } from 'next/navigation'
/**
* Misst die Ladewerte und schickt sie an `/api/vitals`.
*
* Gesendet wird mit `sendBeacon`: das überlebt den Seitenwechsel, blockiert
* nichts und braucht keine offene Verbindung. Die Bibliothek wird erst
* geladen, wenn der Browser Zeit hat - die Messung darf nicht selbst zur
* Ladezeit beitragen.
*
* Übertragen wird das **Routenmuster**, nicht der konkrete Pfad: eine
* Messreihe soll sagen, ob Fallakten langsam sind, nicht welche.
*/
export function Vitals() {
const pathname = usePathname()
useEffect(() => {
let abgebrochen = false
const starten = () => {
void import('web-vitals').then(({ onLCP, onINP, onCLS, onTTFB, onFCP }) => {
if (abgebrochen) return
const senden = (metric: { name: string; value: number; rating: string }) => {
const nutzlast = JSON.stringify({
metric: metric.name,
value: metric.value,
rating: metric.rating,
route: routenMuster(pathname),
})
try {
navigator.sendBeacon?.('/api/vitals', new Blob([nutzlast], { type: 'application/json' }))
} catch {
// Messwerte sind kein Grund, irgendetwas scheitern zu lassen.
}
}
onLCP(senden)
onINP(senden)
onCLS(senden)
onTTFB(senden)
onFCP(senden)
})
}
if ('requestIdleCallback' in window) {
const id = requestIdleCallback(starten)
return () => {
abgebrochen = true
cancelIdleCallback(id)
}
}
const timer = setTimeout(starten, 2000)
return () => {
abgebrochen = true
clearTimeout(timer)
}
}, [pathname])
return null
}
/**
* Aus `/faelle/AfiS-2026-0042/dokumente` wird `/faelle/[caseNumber]/dokumente`.
*
* Die Kennungen dürfen nicht mit: sonst entstünde aus einer Messreihe eine
* Spur, wer wann welche Akte geöffnet hat.
*/
function routenMuster(pfad: string): string {
return pfad
.replace(/\/faelle\/[^/]+/, '/faelle/[caseNumber]')
.replace(/\/dokumente\/[^/]+/, '/dokumente/[documentNumber]')
.replace(/\/personalakten\/[^/]+/, '/personalakten/[id]')
.slice(0, 120)
}