feat: 添加面包屑导航组件并优化页面布局

refactor: 重构页面结构和导航逻辑

fix: 修复移动端菜单导航和滚动行为

perf: 优化图片加载性能和资源请求

test: 添加端到端测试和性能测试用例

docs: 更新.gitignore文件

chore: 更新依赖和配置

style: 优化代码格式和类型安全

ci: 调整Playwright测试超时时间

build: 更新Next.js配置和构建选项
This commit is contained in:
张翔
2026-02-28 09:09:04 +08:00
parent 9d01e0982f
commit 9451814ca4
60 changed files with 4078 additions and 148 deletions
+15 -14
View File
@@ -4,7 +4,6 @@ import { PerformanceMetrics, PerformanceThresholds } from '../types';
export class PerformanceMonitor {
private page: Page;
private metrics: PerformanceMetrics;
private startTime: number;
constructor(page: Page) {
this.page = page;
@@ -16,12 +15,9 @@ export class PerformanceMonitor {
cumulativeLayoutShift: 0,
firstInputDelay: 0,
};
this.startTime = 0;
}
async startMonitoring(): Promise<void> {
this.startTime = Date.now();
await this.page.evaluate(() => {
window.performance.clearResourceTimings();
});
@@ -86,7 +82,7 @@ export class PerformanceMonitor {
const entries = list.getEntries();
const longTasks = entries.filter((e) => e.duration > 50);
if (longTasks.length > 0) {
resolve(longTasks[0].startTime);
resolve(longTasks[0]?.startTime || 0);
}
});
observer.observe({ entryTypes: ['longtask'] });
@@ -103,7 +99,8 @@ export class PerformanceMonitor {
const observer = new PerformanceObserver((list) => {
const entries = list.getEntries();
if (entries.length > 0) {
resolve(entries[0].processingStart - entries[0].startTime);
const entry = entries[0] as any;
resolve((entry?.processingStart || 0) - (entry?.startTime || 0));
}
});
observer.observe({ entryTypes: ['first-input'] });
@@ -176,7 +173,7 @@ export class PerformanceMonitor {
const entries = list.getEntries();
const longTasks = entries.filter((e) => e.duration > 50);
if (longTasks.length > 0) {
resolve(longTasks[0].startTime);
resolve(longTasks[0]?.startTime || 0);
}
});
observer.observe({ entryTypes: ['longtask'] });
@@ -196,7 +193,8 @@ export class PerformanceMonitor {
const observer = new PerformanceObserver((list) => {
const entries = list.getEntries();
if (entries.length > 0) {
resolve(entries[0].processingStart - entries[0].startTime);
const entry = entries[0] as any;
resolve((entry?.processingStart || 0) - (entry?.startTime || 0));
}
});
observer.observe({ entryTypes: ['first-input'] });
@@ -211,12 +209,15 @@ export class PerformanceMonitor {
async measureResourceTiming(): Promise<any[]> {
const resources = await this.page.evaluate(() => {
return performance.getEntriesByType('resource').map((r) => ({
name: r.name,
duration: r.duration,
size: (r as any).transferSize,
type: r.initiatorType,
}));
return performance.getEntriesByType('resource').map((r) => {
const resource = r as any;
return {
name: resource.name,
duration: resource.duration,
size: resource.transferSize,
type: resource.initiatorType,
};
});
});
return resources;
}