fix: disable Vercel analytics outside Vercel

This commit is contained in:
kuekhaoyang
2026-07-09 15:07:34 +08:00
parent 89d1d7268b
commit 93e6699937
8 changed files with 80 additions and 25 deletions
+1 -1
View File
@@ -765,7 +765,7 @@ ALLOW_LAN_ACCESS=true LAN_ALLOWED_DEV_ORIGINS="kvideo.lan,192.168.50.10" npm run
- **ESLint 10**:代码质量检查
- **PostCSS 8**CSS 处理器
- **Vercel Analytics**:性能监控和分析
- **Vercel Analytics**仅在 Vercel 部署中启用的性能监控和分析
- **Cloudflare Pages**:边缘部署支持
### 架构特点
+11 -1
View File
@@ -4,8 +4,18 @@
"name": "KVideo",
"branch": "main"
},
"currentVersion": "4.9.4",
"currentVersion": "4.9.5",
"releases": [
{
"version": "4.9.5",
"publishedAt": "2026-07-09",
"title": "修复 Docker 登录页 Analytics 404",
"notes": [
"Vercel Analytics 现在只会在真实 Vercel 部署中注入,Docker、自托管和 Cloudflare Pages 不再请求 /_vercel/insights/script.js。",
"Cloudflare 部署环境判定优先于 Vercel 风格环境变量,避免适配器环境被误判为 Vercel。",
"新增部署环境单元测试,覆盖自托管、Vercel、Cloudflare 和混合环境变量场景。"
]
},
{
"version": "4.9.4",
"publishedAt": "2026-07-08",
+3 -1
View File
@@ -16,6 +16,7 @@ import { ScrollPositionManager } from "@/components/ScrollPositionManager";
import { LocaleProvider } from "@/components/LocaleProvider";
import { RuntimeFeaturesProvider } from "@/components/RuntimeFeaturesProvider";
import { VideoTogetherController } from '@/components/VideoTogetherController';
import { shouldEnableVercelAnalytics } from '@/lib/config/deployment';
import { getRuntimeFeatures } from "@/lib/server/runtime-features";
import { resolveSiteIconSrc } from '@/lib/server/site-icon';
import fs from 'fs';
@@ -86,6 +87,7 @@ export default async function RootLayout({
process.env.VIDEOTOGETHER_SCRIPT_URL?.trim() || DEFAULT_VIDEOTOGETHER_SCRIPT_URL;
const videoTogetherSettingUrl = process.env.VIDEOTOGETHER_SETTING_URL?.trim();
const videoTogetherEnvEnabled = process.env.VIDEOTOGETHER_ENABLED !== 'false';
const vercelAnalyticsEnabled = shouldEnableVercelAnalytics();
return (
<html lang="zh-CN" suppressHydrationWarning>
@@ -136,7 +138,7 @@ export default async function RootLayout({
<ScrollPositionManager />
</PasswordGate>
</TVProvider>
<Analytics />
{vercelAnalyticsEnabled ? <Analytics /> : null}
<ServiceWorkerRegister />
</RuntimeFeaturesProvider>
</ThemeProvider>
+19
View File
@@ -0,0 +1,19 @@
type EnvLike = Record<string, string | undefined>;
export function isVercelDeployment(env: EnvLike = process.env): boolean {
return env.VERCEL === '1' || Boolean(env.VERCEL_ENV);
}
export function isCloudflareDeployment(env: EnvLike = process.env): boolean {
return (
env.CF_PAGES === '1' ||
Boolean(env.CF_PAGES_URL) ||
Boolean(env.CLOUDFLARE_ACCOUNT_ID) ||
Boolean(env.CF_ACCOUNT_ID) ||
Boolean(env.WORKERS_CI)
);
}
export function shouldEnableVercelAnalytics(env: EnvLike = process.env): boolean {
return isVercelDeployment(env) && !isCloudflareDeployment(env);
}
+5 -19
View File
@@ -1,20 +1,7 @@
import 'server-only';
import type { RuntimeFeatures } from '@/lib/config/runtime-features';
function isVercelDeployment(): boolean {
return process.env.VERCEL === '1' || Boolean(process.env.VERCEL_ENV);
}
function isCloudflareDeployment(): boolean {
return (
process.env.CF_PAGES === '1' ||
Boolean(process.env.CF_PAGES_URL) ||
Boolean(process.env.CLOUDFLARE_ACCOUNT_ID) ||
Boolean(process.env.CF_ACCOUNT_ID) ||
Boolean(process.env.WORKERS_CI)
);
}
import { isCloudflareDeployment, isVercelDeployment } from '@/lib/config/deployment';
function getRestrictedFeatures(
deploymentProvider: RuntimeFeatures['deploymentProvider'],
@@ -31,14 +18,14 @@ function getRestrictedFeatures(
}
export function getRuntimeFeatures(): RuntimeFeatures {
if (isVercelDeployment()) {
return getRestrictedFeatures('vercel', 'Vercel');
}
if (isCloudflareDeployment()) {
return getRestrictedFeatures('cloudflare', 'Cloudflare');
}
if (isVercelDeployment()) {
return getRestrictedFeatures('vercel', 'Vercel');
}
return {
deploymentProvider: 'self-hosted',
deploymentProviderLabel: '自托管',
@@ -48,4 +35,3 @@ export function getRuntimeFeatures(): RuntimeFeatures {
restrictionSummary: null,
};
}
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "kvideo",
"version": "4.9.4",
"version": "4.9.5",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "kvideo",
"version": "4.9.4",
"version": "4.9.5",
"dependencies": {
"@dnd-kit/core": "^6.3.1",
"@dnd-kit/sortable": "^10.0.0",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "kvideo",
"version": "4.9.4",
"version": "4.9.5",
"private": true,
"scripts": {
"dev": "node scripts/next-with-lan-access.mjs dev",
+38
View File
@@ -0,0 +1,38 @@
import test from 'node:test';
import assert from 'node:assert/strict';
import {
isCloudflareDeployment,
isVercelDeployment,
shouldEnableVercelAnalytics,
} from '@/lib/config/deployment';
test('self-hosted deployments do not enable Vercel Analytics', () => {
const env = {};
assert.equal(isVercelDeployment(env), false);
assert.equal(isCloudflareDeployment(env), false);
assert.equal(shouldEnableVercelAnalytics(env), false);
});
test('Vercel deployments enable Vercel Analytics', () => {
assert.equal(shouldEnableVercelAnalytics({ VERCEL: '1' }), true);
assert.equal(shouldEnableVercelAnalytics({ VERCEL_ENV: 'production' }), true);
});
test('Cloudflare deployments do not enable Vercel Analytics', () => {
assert.equal(shouldEnableVercelAnalytics({ CF_PAGES: '1' }), false);
assert.equal(shouldEnableVercelAnalytics({ CF_PAGES_URL: 'https://kvideo.pages.dev' }), false);
});
test('Cloudflare wins when adapter environments expose Vercel-like variables', () => {
const env = {
VERCEL: '1',
VERCEL_ENV: 'production',
CF_PAGES: '1',
};
assert.equal(isVercelDeployment(env), true);
assert.equal(isCloudflareDeployment(env), true);
assert.equal(shouldEnableVercelAnalytics(env), false);
});