From 2ae30d70d5c2ea79a348fb6767d6c5eb9404de70 Mon Sep 17 00:00:00 2001 From: Patrick Erichsen Date: Fri, 19 Jun 2026 11:36:01 -0700 Subject: [PATCH] feat: add Vercel Speed Insights --- bun.lock | 3 +++ package.json | 1 + src/__tests__/ui-design-contract.test.ts | 12 ++++++++++++ src/routes/__root.tsx | 10 +++++++++- 4 files changed, 25 insertions(+), 1 deletion(-) diff --git a/bun.lock b/bun.lock index 345c980c..0dedebb7 100644 --- a/bun.lock +++ b/bun.lock @@ -30,6 +30,7 @@ "@tanstack/react-router": "1.170.16", "@tanstack/react-start": "1.168.26", "@vercel/analytics": "2.0.1", + "@vercel/speed-insights": "2.0.0", "class-variance-authority": "0.7.1", "clawhub-schema": "workspace:0.0.2", "clsx": "2.1.1", @@ -924,6 +925,8 @@ "@vercel/analytics": ["@vercel/analytics@2.0.1", "", { "peerDependencies": { "@remix-run/react": "^2", "@sveltejs/kit": "^1 || ^2", "next": ">= 13", "nuxt": ">= 3", "react": "^18 || ^19 || ^19.0.0-rc", "svelte": ">= 4", "vue": "^3", "vue-router": "^4" }, "optionalPeers": ["@remix-run/react", "@sveltejs/kit", "next", "nuxt", "react", "svelte", "vue", "vue-router"] }, "sha512-MTQG6V9qQrt1tsDeF+2Uoo5aPjqbVPys1xvnIftXSJYG2SrwXRHnqEvVoYID7BTruDz4lCd2Z7rM1BdkUehk2g=="], + "@vercel/speed-insights": ["@vercel/speed-insights@2.0.0", "", { "peerDependencies": { "@sveltejs/kit": "^1 || ^2", "next": ">= 13", "nuxt": ">= 3", "react": "^18 || ^19 || ^19.0.0-rc", "svelte": ">= 4", "vue": "^3", "vue-router": "^4" }, "optionalPeers": ["@sveltejs/kit", "next", "nuxt", "react", "svelte", "vue", "vue-router"] }, "sha512-jwkNcrTeafWxjmWq4AHBaptSqZiJkYU5adLC9QBSqeim0GcqDMgN5Ievh8OG1rJ6W3A4l1oiP7qr9CWxGuzu3w=="], + "@vitejs/plugin-react": ["@vitejs/plugin-react@6.0.2", "", { "dependencies": { "@rolldown/pluginutils": "^1.0.0" }, "peerDependencies": { "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0", "babel-plugin-react-compiler": "^1.0.0", "vite": "^8.0.0" }, "optionalPeers": ["@rolldown/plugin-babel", "babel-plugin-react-compiler"] }, "sha512-DlSMqo4WhThw4vB8Mpn0Woe9J+Jfq1geJ61AKW0QEgLzGMNwtIMdxbDUzLxcun8W7NbJO0e2Jg/Nxm3cCSVzzg=="], "@vitest/coverage-v8": ["@vitest/coverage-v8@4.1.9", "", { "dependencies": { "@bcoe/v8-coverage": "^1.0.2", "@vitest/utils": "4.1.9", "ast-v8-to-istanbul": "^1.0.0", "istanbul-lib-coverage": "^3.2.2", "istanbul-lib-report": "^3.0.1", "istanbul-reports": "^3.2.0", "magicast": "^0.5.2", "obug": "^2.1.1", "std-env": "^4.0.0-rc.1", "tinyrainbow": "^3.1.0" }, "peerDependencies": { "@vitest/browser": "4.1.9", "vitest": "4.1.9" }, "optionalPeers": ["@vitest/browser"] }, "sha512-G9/lgqibheLVBDRuya45EbsEXTYcWoSG+TLg7i2axuzx0Eq62eXn+aWXyaVdV5vKvFSWd6ywcX8hA7la9Pvu8g=="], diff --git a/package.json b/package.json index bee0b48a..27660498 100644 --- a/package.json +++ b/package.json @@ -96,6 +96,7 @@ "@tanstack/react-router": "1.170.16", "@tanstack/react-start": "1.168.26", "@vercel/analytics": "2.0.1", + "@vercel/speed-insights": "2.0.0", "class-variance-authority": "0.7.1", "clawhub-schema": "workspace:0.0.2", "clsx": "2.1.1", diff --git a/src/__tests__/ui-design-contract.test.ts b/src/__tests__/ui-design-contract.test.ts index 4dd5ad21..1933e4cf 100644 --- a/src/__tests__/ui-design-contract.test.ts +++ b/src/__tests__/ui-design-contract.test.ts @@ -60,6 +60,7 @@ function contrastRatio(foreground: string, background: string) { } describe("restored UI design contract", () => { + const rootRoute = () => read("src/routes/__root.tsx"); const header = () => read("src/components/Header.tsx"); const footer = () => read("src/components/Footer.tsx"); const home = () => read("src/routes/index.tsx"); @@ -68,6 +69,17 @@ describe("restored UI design contract", () => { const styles = () => read("src/styles.css"); const theme = () => read("src/lib/theme.ts"); + it("keeps Vercel browser instrumentation mounted outside local dev", () => { + const rootSource = rootRoute(); + + expect(rootSource).toContain('import { Analytics } from "@vercel/analytics/react";'); + expect(rootSource).toContain('import { SpeedInsights } from "@vercel/speed-insights/react";'); + expect(rootSource).toContain('!["localhost", "127.0.0.1", "::1"].includes'); + expect(rootSource).toContain("{showAnalytics ? ("); + expect(rootSource).toContain(""); + expect(rootSource).toContain(""); + }); + it("requires the responsive header rail, search overlay, and theme controls", () => { const headerSource = header(); const navSource = navItems(); diff --git a/src/routes/__root.tsx b/src/routes/__root.tsx index 2fc29e91..cf4ac66a 100644 --- a/src/routes/__root.tsx +++ b/src/routes/__root.tsx @@ -6,6 +6,7 @@ import { useLocation, } from "@tanstack/react-router"; import { Analytics } from "@vercel/analytics/react"; +import { SpeedInsights } from "@vercel/speed-insights/react"; import { useEffect } from "react"; import { Toaster } from "sonner"; import { AppProviders } from "../components/AppProviders"; @@ -196,7 +197,14 @@ function RootDocument({ children }: { children: React.ReactNode }) { }, }} /> - {showAnalytics ? : null} + + {showAnalytics ? ( + <> + + + + ) : null} +