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
375 Vorkommen in 210 Dateien. Betrifft Kommentare, Oberflaechentexte und die README; an keiner Stelle Bedeutung, nur Zeichensetzung.
80 lines
2.2 KiB
TypeScript
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)
|
|
}
|