diff --git a/next.config.ts b/next.config.ts
index b6c8d96..274b130 100644
--- a/next.config.ts
+++ b/next.config.ts
@@ -7,6 +7,13 @@ const nextConfig: NextConfig = {
unoptimized: true,
deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
+ formats: ['image/webp'],
+ },
+ compress: true,
+ poweredByHeader: false,
+ reactStrictMode: true,
+ experimental: {
+ optimizePackageImports: ['lucide-react', 'framer-motion'],
},
};
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index 0dc1e35..0c3ec9b 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -1,23 +1,29 @@
-import type { Metadata } from "next";
+import type { Metadata, Viewport } from "next";
import { Geist, Geist_Mono, Noto_Sans_SC } from "next/font/google";
import "./globals.css";
import { ThemeProvider } from "@/contexts/theme-context";
+import { WebVitals } from "@/components/analytics/web-vitals";
const geistSans = Geist({
variable: "--font-geist-sans",
subsets: ["latin"],
+ display: "swap",
+ preload: true,
});
const geistMono = Geist_Mono({
variable: "--font-geist-mono",
subsets: ["latin"],
+ display: "swap",
+ preload: true,
});
-// 思源黑体 - 中文字体
const notoSansSC = Noto_Sans_SC({
weight: ["400", "500", "700"],
variable: "--font-noto-sans-sc",
subsets: ["latin"],
+ display: "swap",
+ preload: true,
});
export const metadata: Metadata = {
@@ -52,6 +58,16 @@ export const metadata: Metadata = {
},
};
+export const viewport: Viewport = {
+ width: "device-width",
+ initialScale: 1,
+ maximumScale: 5,
+ themeColor: [
+ { media: "(prefers-color-scheme: light)", color: "#FFFFFF" },
+ { media: "(prefers-color-scheme: dark)", color: "#0A0A0A" },
+ ],
+};
+
export default function RootLayout({
children,
}: Readonly<{
@@ -79,6 +95,7 @@ export default function RootLayout({
className={`${geistSans.variable} ${geistMono.variable} ${notoSansSC.variable} font-sans antialiased`}
style={{ fontFamily: "'Noto Sans SC', 'Geist', -apple-system, BlinkMacSystemFont, sans-serif" }}
>
+
{children}
diff --git a/src/components/analytics/web-vitals.tsx b/src/components/analytics/web-vitals.tsx
new file mode 100644
index 0000000..8dfd445
--- /dev/null
+++ b/src/components/analytics/web-vitals.tsx
@@ -0,0 +1,33 @@
+'use client';
+
+import { useReportWebVitals } from 'next/web-vitals';
+
+export function WebVitals() {
+ useReportWebVitals((metric) => {
+ if (process.env.NODE_ENV === 'development') {
+ console.log('[Web Vitals]', metric);
+ }
+
+ if (process.env.NODE_ENV === 'production') {
+ const body = JSON.stringify({
+ name: metric.name,
+ value: metric.value,
+ rating: metric.rating,
+ delta: metric.delta,
+ id: metric.id,
+ });
+
+ if (navigator.sendBeacon) {
+ navigator.sendBeacon('/api/analytics', body);
+ } else {
+ fetch('/api/analytics', {
+ body,
+ method: 'POST',
+ keepalive: true,
+ }).catch(() => {});
+ }
+ }
+ });
+
+ return null;
+}