From 67bba0c2078b86a6fb41e3262159a550a15a0874 Mon Sep 17 00:00:00 2001 From: mzaxd Date: Mon, 23 Feb 2026 23:08:01 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=8E=A5=E5=85=A5=20Vercel=20Analytics?= =?UTF-8?q?=20=E4=B8=8E=20Speed=20Insights=20=E5=B9=B6=E6=8E=A7=E5=88=B6?= =?UTF-8?q?=E9=87=87=E9=9B=86=E9=87=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 ++ pnpm-lock.yaml | 65 ++++++++++++++++++++++++++++++++++++++++++++++ src/app/layout.tsx | 24 +++++++++++++++++ 3 files changed, 91 insertions(+) diff --git a/package.json b/package.json index 3a38ff0..f0703dd 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,8 @@ "@radix-ui/react-navigation-menu": "^1.2.2", "@radix-ui/react-separator": "^1.1.1", "@radix-ui/react-slot": "^1.1.1", + "@vercel/analytics": "^1.6.1", + "@vercel/speed-insights": "^1.3.1", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "lucide-react": "^0.468.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6533e1e..bdf441d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -23,6 +23,12 @@ importers: '@radix-ui/react-slot': specifier: ^1.1.1 version: 1.2.4(@types/react@19.2.7)(react@19.2.3) + '@vercel/analytics': + specifier: ^1.6.1 + version: 1.6.1(next@15.1.11(@babel/core@7.28.5)(@playwright/test@1.57.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3) + '@vercel/speed-insights': + specifier: ^1.3.1 + version: 1.3.1(next@15.1.11(@babel/core@7.28.5)(@playwright/test@1.57.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3) class-variance-authority: specifier: ^0.7.1 version: 0.7.1 @@ -1586,6 +1592,55 @@ packages: cpu: [x64] os: [win32] + '@vercel/analytics@1.6.1': + resolution: {integrity: sha512-oH9He/bEM+6oKlv3chWuOOcp8Y6fo6/PSro8hEkgCW3pu9/OiCXiUpRUogDh3Fs3LH2sosDrx8CxeOLBEE+afg==} + peerDependencies: + '@remix-run/react': ^2 + '@sveltejs/kit': ^1 || ^2 + next: '>= 13' + react: ^18 || ^19 || ^19.0.0-rc + svelte: '>= 4' + vue: ^3 + vue-router: ^4 + peerDependenciesMeta: + '@remix-run/react': + optional: true + '@sveltejs/kit': + optional: true + next: + optional: true + react: + optional: true + svelte: + optional: true + vue: + optional: true + vue-router: + optional: true + + '@vercel/speed-insights@1.3.1': + resolution: {integrity: sha512-PbEr7FrMkUrGYvlcLHGkXdCkxnylCWePx7lPxxq36DNdfo9mcUjLOmqOyPDHAOgnfqgGGdmE3XI9L/4+5fr+vQ==} + peerDependencies: + '@sveltejs/kit': ^1 || ^2 + next: '>= 13' + react: ^18 || ^19 || ^19.0.0-rc + svelte: '>= 4' + vue: ^3 + vue-router: ^4 + peerDependenciesMeta: + '@sveltejs/kit': + optional: true + next: + optional: true + react: + optional: true + svelte: + optional: true + vue: + optional: true + vue-router: + optional: true + '@vitejs/plugin-react@4.7.0': resolution: {integrity: sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==} engines: {node: ^14.18.0 || >=16.0.0} @@ -5066,6 +5121,16 @@ snapshots: '@unrs/resolver-binding-win32-x64-msvc@1.11.1': optional: true + '@vercel/analytics@1.6.1(next@15.1.11(@babel/core@7.28.5)(@playwright/test@1.57.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3)': + optionalDependencies: + next: 15.1.11(@babel/core@7.28.5)(@playwright/test@1.57.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + react: 19.2.3 + + '@vercel/speed-insights@1.3.1(next@15.1.11(@babel/core@7.28.5)(@playwright/test@1.57.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3)': + optionalDependencies: + next: 15.1.11(@babel/core@7.28.5)(@playwright/test@1.57.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + react: 19.2.3 + '@vitejs/plugin-react@4.7.0(vite@5.4.21(@types/node@22.19.3))': dependencies: '@babel/core': 7.28.5 diff --git a/src/app/layout.tsx b/src/app/layout.tsx index fb157ed..51f1f2b 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,4 +1,6 @@ import type { Metadata } from "next" +import { Analytics } from "@vercel/analytics/next" +import { SpeedInsights } from "@vercel/speed-insights/next" import "./globals.css" export const metadata: Metadata = { @@ -6,6 +8,19 @@ export const metadata: Metadata = { description: "发现和探索全网优质 AI 项目", } +const isVercelProduction = process.env.VERCEL_ENV === "production" + +const isTrackablePath = (url: string): boolean => { + try { + const pathname = new URL(url).pathname + + // Only keep user-facing locale pages to control usage on the Hobby plan. + return pathname === "/zh" || pathname === "/en" || pathname.startsWith("/zh/") || pathname.startsWith("/en/") + } catch { + return false + } +} + export default function RootLayout({ children, }: Readonly<{ @@ -15,6 +30,15 @@ export default function RootLayout({ {children} + {isVercelProduction ? ( + <> + (isTrackablePath(event.url) ? event : null)} /> + (isTrackablePath(data.url) ? data : null)} + /> + + ) : null} )