前端构建链路日常巡检要点大型项目的构建时间和产物体积会随着依赖、代码组织和构建配置逐步变化。与其依赖一次性优化不如保存可比较的基线并在合并请求中展示变化。构建变慢不必然意味着首屏变差两类指标应分别观察。本文给出一个巡检思路检查依赖和产物变化超过团队约定范围时附上报告交给人工判断。阈值需要按应用规模、压缩方式和访问路径设定。1. 巡检痛点重复依赖包Duplicate Packages默默拖垮体积在日常巡检中最常抓到的构建隐形杀手就是重复依赖。例如项目里同时存在lodash和lodash-es或者不同微前端子包依赖了axios0.21.1与axios1.6.0。多个版本的同一依赖可能增加安装体积并可能进入多个输出 chunk是否真的重复打包取决于入口、依赖图和 Rollup 的去重结果需要结合产物分析确认。// 巡检脚本中检测 package-lock.json / pnpm-lock.yaml 重复依赖的核心逻辑 import fs from fs; import path from path; export interface DuplicateDependencyReport { packageName: string; versions: string[]; } export function scanDuplicateDependencies(lockfilePath: string): DuplicateDependencyReport[] { if (!fs.existsSync(lockfilePath)) { throw new Error([Inspection Error] 未找到 Lock 文件: ${lockfilePath}); } const content fs.readFileSync(lockfilePath, utf-8); // 简化的 lockfile 版本匹配提取逻辑 const packageVersionMap new Mapstring, Setstring(); // 假设为 pnpm-lock 语法解析范例 const regex /^\/([a-z0-9-./])([0-9.]):/gm; let match; while ((match regex.exec(content)) ! null) { const [, pkgName, version] match; if (!packageVersionMap.has(pkgName)) { packageVersionMap.set(pkgName, new Set()); } packageVersionMap.get(pkgName)!.add(version); } const duplicates: DuplicateDependencyReport[] []; packageVersionMap.forEach((versions, packageName) { if (versions.size 1) { duplicates.push({ packageName, versions: Array.from(versions) }); } }); return duplicates; }2. 确定性巡检方案编写 Vite 构建增量漂移诊断器除了依赖扫描日常巡检还需要精准比对构建产物体积与构建耗时的增量漂移Incremental Drift。如果单次 PR 导致打包产物增量超过 50KB巡检脚本应立即发出预警。我们实现了一套自动化巡检探针import { build, type InlineConfig } from vite; import { performance } from node:perf_hooks; export interface BuildInspectionMetrics { durationMs: number; totalBundleSizeBytes: number; chunkCount: number; } export class ViteBuildInspector { private baselineMetrics: BuildInspectionMetrics | null null; public async runInspection(viteConfig: InlineConfig): PromiseBuildInspectionMetrics { const startTime performance.performance.now(); // 触发打包构建 const output (await build({ ...viteConfig, build: { ...viteConfig.build, write: false }, // 不实际写入磁盘加速巡检 })) as any; const durationMs performance.performance.now() - startTime; let totalSizeBytes 0; let chunkCount 0; if (output output.output) { for (const item of output.output) { if (item.type chunk) { chunkCount; totalSizeBytes Buffer.byteLength(item.code, utf8); } } } const currentMetrics: BuildInspectionMetrics { durationMs: Number(durationMs.toFixed(2)), totalBundleSizeBytes: totalSizeBytes, chunkCount, }; this.auditMetrics(currentMetrics); this.baselineMetrics currentMetrics; return currentMetrics; } private auditMetrics(current: BuildInspectionMetrics): void { console.log([Vite Daily Inspection] 构建耗时: ${current.durationMs}ms, 总体积: ${(current.totalBundleSizeBytes / 1024).toFixed(2)}KB, Chunk 数: ${current.chunkCount}); if (this.baselineMetrics) { const sizeDriftRatio (current.totalBundleSizeBytes - this.baselineMetrics.totalBundleSizeBytes) / this.baselineMetrics.totalBundleSizeBytes; if (sizeDriftRatio 0.05) { console.warn([Inspection Warning] 产物体积比上次基准增长了 ${(sizeDriftRatio * 100).toFixed(2)}%! 请检查近期合并的 PR); } } } }3. 巡检落地时的注意点锁文件扫描可作为线索最终以构建产物和许可证、漏洞要求共同决定是否去重。体积预算应按资源类型设定超标时先附上 diff 和访问影响再决定是否阻断。报告要保留构建命令、依赖版本和基线来源才能让后续比较有意义。