diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 8388309570..27886bc7d3 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -60,6 +60,38 @@ export default async function RootLayout({ children }) { return (
+ {/* Pre-hydration cleanup: browser extensions (Bitdefender's + bis_skin_checked, Grammarly's data-gr-ext-installed, LanguageTool's + data-lt-installed, etc.) inject attributes into the DOM after SSR + but before React hydrates, causing hydration mismatch warnings in + dev. Strip them synchronously and observe for late injections; the + observer auto-disconnects after 5s (well past typical hydration). */} + {/* Material Symbols icon font is self-hosted via globals.css (@import "material-symbols/outlined.css") so icons render even when the Google Fonts CDN is unreachable (#3695). */} diff --git a/tests/unit/dashboard/hydration-extension-attrs.test.ts b/tests/unit/dashboard/hydration-extension-attrs.test.ts new file mode 100644 index 0000000000..4840761d95 --- /dev/null +++ b/tests/unit/dashboard/hydration-extension-attrs.test.ts @@ -0,0 +1,72 @@ +import test from "node:test"; +import assert from "node:assert/strict"; +import { readFileSync } from "node:fs"; +import { resolve, join } from "node:path"; + +// Regression guard for the browser-extension hydration-mismatch fix: extensions +// like Bitdefender (bis_skin_checked), Google Search (data-google-query-id), +// Grammarly (data-new-gr-c-s-check-loaded / data-gr-ext-installed) and +// LanguageTool (data-lt-installed / data-lt-tmp-id) inject attributes into the +// DOM after SSR but before React hydrates. React's suppressHydrationWarning on +// / only applies one level deep, so the mismatch still surfaces on +// Next.js's internal elements. The fix adds a synchronous pre-hydration