perf(monitoring): read the monitoring switches in the root layout

Every document load, the sign-in page included, mounted a client
effect that asked `/api/monitoring/settings` for three instance-wide
values (false, null, false on a default install) before it mounted the
analytics script or the error reporter. The root layout is a server
component and now reads them while it renders and passes them in, so
the request and the effect go. The key-mismatch page reads nothing, as
before. The route stays for other callers.
This commit is contained in:
Marc-André Bombeck committed 2026-11-11 22:05:48 +01:00
1 parent d2ac3b91bd
commit ea6e94adcf
3 files changed
+80 -39

No files matched your search

+16 -2
View File
@@ -8,6 +8,7 @@ import "./globals.css";
import { Providers } from "@/components/providers";
import { AuthShell } from "@/components/layout/auth-shell";
import { MonitoringBootstrap } from "@/components/monitoring/bootstrap";
import { getPublicMonitoringSettings } from "@/lib/monitoring-settings";
import { WebVitalsReporter } from "@/components/monitoring/web-vitals-reporter";
import { resolveInitialLocale } from "@/lib/i18n/resolve-initial-locale";
import { isKeyMismatch } from "@/lib/boot/key-mismatch-state";
@@ -86,7 +87,12 @@ export default async function RootLayout({
? ((await headers()).get("x-nonce") ?? undefined)
: undefined;
const initialLocale = await resolveInitialLocale();
// The monitoring switches ride the document render instead of a request
// from every page load; the key-mismatch page reads no data.
const [initialLocale, monitoring] = await Promise.all([
resolveInitialLocale(),
isKeyMismatch() ? null : getPublicMonitoringSettings(),
]);
return (
<html lang={initialLocale} suppressHydrationWarning>
@@ -139,7 +145,15 @@ export default async function RootLayout({
<KeyMismatchPage locale={initialLocale} />
) : (
<Providers initialLocale={initialLocale}>
<MonitoringBootstrap />
<MonitoringBootstrap
settings={
monitoring && {
umamiEnabled: monitoring.umamiEnabled,
umamiWebsiteId: monitoring.umamiWebsiteId,
glitchtipEnabled: monitoring.glitchtipEnabled,
}
}
/>
<WebVitalsReporter />
{/* `DEMO_MODE` is a server-only env var; the proxy uses it to
block mutations. Resolve it here (server component) and
@@ -0,0 +1,49 @@
import { describe, expect, it, vi } from "vitest";
import { renderToStaticMarkup } from "react-dom/server";
/**
* The monitoring switches come from the root layout's render, not from a
* request every page load sent to `/api/monitoring/settings` for three
* instance-wide values. The first render already mounts what they turn on.
*/
const apiGet = vi.fn();
vi.mock("@/lib/api/api-fetch", () => ({
apiGet: (...args: unknown[]) => apiGet(...args),
}));
vi.mock("@/components/monitoring/umami-script", () => ({
UmamiScript: (props: { enabled: boolean; websiteId: string | null }) => (
<i data-umami={`${props.enabled}:${props.websiteId}`} />
),
}));
vi.mock("@/components/monitoring/glitchtip-reporter", () => ({
GlitchtipReporter: (props: { enabled: boolean }) => (
<i data-glitchtip={String(props.enabled)} />
),
}));
import { MonitoringBootstrap } from "../bootstrap";
describe("MonitoringBootstrap", () => {
it("mounts what the layout's switches turn on, without asking the server", () => {
const html = renderToStaticMarkup(
<MonitoringBootstrap
settings={{
umamiEnabled: true,
umamiWebsiteId: "site-1",
glitchtipEnabled: true,
}}
/>,
);
expect(html).toContain('data-umami="true:site-1"');
expect(html).toContain('data-glitchtip="true"');
expect(apiGet).not.toHaveBeenCalled();
});
it("mounts nothing without settings", () => {
expect(renderToStaticMarkup(<MonitoringBootstrap settings={null} />)).toBe(
"",
);
});
});
+15 -37
View File
@@ -1,43 +1,21 @@
"use client";
import { useEffect, useState } from "react";
import { UmamiScript } from "@/components/monitoring/umami-script";
import { GlitchtipReporter } from "@/components/monitoring/glitchtip-reporter";
import { apiGet } from "@/lib/api/api-fetch";
interface MonitoringSettings {
umamiEnabled: boolean;
umamiWebsiteId: string | null;
glitchtipEnabled: boolean;
}
export function MonitoringBootstrap() {
const [settings, setSettings] = useState<MonitoringSettings | null>(null);
useEffect(() => {
let active = true;
apiGet<MonitoringSettings | undefined>("/api/monitoring/settings", {
cache: "no-store",
})
.then((data) => {
if (!active || !data) return;
setSettings(data);
})
.catch(() => {
if (!active) return;
setSettings({
umamiEnabled: false,
umamiWebsiteId: null,
glitchtipEnabled: false,
});
});
return () => {
active = false;
};
}, []);
import type { PublicMonitoringSettings } from "@/lib/monitoring-settings";
/**
* Mounts the operator's analytics script and error reporter. The root layout
* reads the instance-wide switches on the server and passes them in, so no
* page load asks `/api/monitoring/settings` for three values the document
* render already had. `null` (the key-mismatch page) mounts nothing.
*/
export function MonitoringBootstrap({
settings,
}: {
settings: Pick<
PublicMonitoringSettings,
"umamiEnabled" | "umamiWebsiteId" | "glitchtipEnabled"
> | null;
}) {
if (!settings) return null;
return (