From 004439b7364f987bde84971c2d29696b278e3f86 Mon Sep 17 00:00:00 2001 From: "2569718930@qq.com" <2569718930@qq.com> Date: Wed, 24 Jun 2026 16:25:49 +0800 Subject: [PATCH] Add Microsoft Clarity tracking --- frontend/app/layout.tsx | 2 ++ .../observability/MicrosoftClarity.tsx | 23 +++++++++++++ .../__tests__/microsoftClarity.test.ts | 34 +++++++++++++++++++ 3 files changed, 59 insertions(+) create mode 100644 frontend/components/observability/MicrosoftClarity.tsx create mode 100644 frontend/components/observability/__tests__/microsoftClarity.test.ts diff --git a/frontend/app/layout.tsx b/frontend/app/layout.tsx index 4eca9acc..8769ee0f 100644 --- a/frontend/app/layout.tsx +++ b/frontend/app/layout.tsx @@ -1,6 +1,7 @@ import type { Metadata } from "next"; import { Inter, JetBrains_Mono } from "next/font/google"; import { RegisterSW } from "@/components/dashboard/RegisterSW"; +import { MicrosoftClarity } from "@/components/observability/MicrosoftClarity"; import "./globals.css"; const inter = Inter({ @@ -89,6 +90,7 @@ export default function RootLayout({
{children}
+ ); diff --git a/frontend/components/observability/MicrosoftClarity.tsx b/frontend/components/observability/MicrosoftClarity.tsx new file mode 100644 index 00000000..3f5e9200 --- /dev/null +++ b/frontend/components/observability/MicrosoftClarity.tsx @@ -0,0 +1,23 @@ +import Script from "next/script"; + +const MICROSOFT_CLARITY_PROJECT_ID = "xbydcq2lu2"; + +const MICROSOFT_CLARITY_SCRIPT = ` + (function(c,l,a,r,i,t,y){ + c[a]=c[a]||function(){(c[a].q=c[a].q||[]).push(arguments)}; + t=l.createElement(r);t.async=1;t.src="https://www.clarity.ms/tag/"+i; + y=l.getElementsByTagName(r)[0];y.parentNode.insertBefore(t,y); + })(window, document, "clarity", "script", "${MICROSOFT_CLARITY_PROJECT_ID}"); +`; + +export function MicrosoftClarity() { + if (process.env.NODE_ENV !== "production") { + return null; + } + + return ( + + ); +} diff --git a/frontend/components/observability/__tests__/microsoftClarity.test.ts b/frontend/components/observability/__tests__/microsoftClarity.test.ts new file mode 100644 index 00000000..6a22e38a --- /dev/null +++ b/frontend/components/observability/__tests__/microsoftClarity.test.ts @@ -0,0 +1,34 @@ +import fs from "node:fs"; +import path from "node:path"; + +function assert(condition: unknown, message: string) { + if (!condition) throw new Error(message); +} + +export function runTests() { + const projectRoot = process.cwd(); + const componentPath = path.join(projectRoot, "components", "observability", "MicrosoftClarity.tsx"); + const layoutPath = path.join(projectRoot, "app", "layout.tsx"); + + assert(fs.existsSync(componentPath), "Microsoft Clarity component must exist"); + + const component = fs.readFileSync(componentPath, "utf8"); + const layout = fs.readFileSync(layoutPath, "utf8"); + + assert( + component.includes('import Script from "next/script"') && + component.includes('strategy="afterInteractive"'), + "Microsoft Clarity must use next/script and load after hydration", + ); + assert( + component.includes("xbydcq2lu2") && + component.includes("https://www.clarity.ms/tag/") && + component.includes('window, document, "clarity", "script"'), + "Microsoft Clarity must use the configured PolyWeather project script", + ); + assert( + layout.includes("@/components/observability/MicrosoftClarity") && + layout.includes(""), + "root layout must render Microsoft Clarity globally", + ); +}