博客秒级排序升级与代码质量清理记录
起因:同一分钟内的排序混乱
用 npm run new 快速连续创建文章时,发现一个隐患:原文件名格式 YY-MM-DD-HH-MM.md 只精确到分钟,同一分钟内创建的两篇文章排序顺序不确定。排序逻辑散布在前端工具 src/utils/sortPosts.ts、文章创建脚本 tools/scripts/new-post.js 和 Admin 后台 tools/admin/server.js 三处,需要同步升级。
文件名格式升级到秒级
新格式 YY-MM-DD-HH-MM-SS.md 在原有基础上追加秒字段。解析器用可选匹配组处理向后兼容,旧文件无需改动:
// src/utils/sortPosts.ts
export function getTimestampFromFilename(id: string): number {
const filename = id.split('/').pop() || id;
const match = filename.match(/^(\d{2})-(\d{2})-(\d{2})-(\d{2})-(\d{2})(?:-(\d{2}))?/);
if (!match) return 0;
const [, yy, month, day, hour, minute, second] = match;
const year = 2000 + parseInt(yy, 10);
return new Date(
year,
parseInt(month, 10) - 1,
parseInt(day, 10),
parseInt(hour, 10),
parseInt(minute, 10),
parseInt(second || '0', 10) // 秒默认为 00,旧格式自动兼容
).getTime();
}
(?:-(\d{2}))? 让秒成为可选项,second || '0' 处理旧格式的降级。Admin 后台的同名函数逻辑完全一致,文章创建脚本则在生成文件名时补上秒字段。
代码质量:从 119 个错误到 40 个
趁着改排序逻辑,顺手跑了一遍 ESLint 和 TypeScript 检查,结果是 8 个 ESLint 警告和 119 个 TypeScript 错误。修完这轮后,ESLint 清零,TypeScript 降到约 40 个。
全局类型声明解决了不少重复错误。项目里 Mermaid、KaTeX、ECharts 都通过 CDN 动态加载,挂在 window 上,TypeScript 不认识这些属性,导致 30 多个重复报错。在 src/env.d.ts 里统一声明 Window 接口扩展后,这批错误一次性消失:
/// <reference types="astro/client" />
interface Window {
mermaid?: {
initialize: (config: Record<string, unknown>) => void;
render: (id: string, code: string) => Promise<{ svg: string }>;
};
katex?: {
renderToString: (formula: string, options: { throwOnError?: boolean; displayMode?: boolean }) => string;
};
echarts?: {
init: (container: HTMLElement) => EChartsInstance;
};
}
ESLint 警告主要是两类。一是箭头函数参数缺括号,项目配置了 arrow-parens: always,post => post.id 要改成 (post) => post.id,涉及五六个页面文件。二是未使用的变量,catch (e) 里的 e 没用到,改成 catch (_e) 或加 eslint-disable-next-line 注释;未使用的导入直接删掉。
TypeScript 类型错误里比较典型的是泛型约束问题。sortPostsByTime 原来写成 <T extends CollectionEntry<'blog'>>(posts: T[]): T[],泛型约束反而让编译器无法确认 a.data 的类型,改成直接用 CollectionEntry<'blog'>[] 就解决了。另一类是 getCollection 回调参数的隐式 any,加上 ({data}: CollectionEntry<'blog'>) 类型注解即可。
剩余 40 个错误主要集中在 Mermaid 和 BlogGalaxy 组件里,ECharts 的事件参数类型需要更细致的定义,还有一些 DOM 操作缺少 null 检查,留待后续处理,不影响运行。
几点收获
向后兼容的重点在于”可选而非强制”,正则里一个 (?:...)? 就能让新旧格式共存,不需要迁移脚本。全局类型声明文件也应该集中管理,把散落在各组件里的 declare global 统一到 src/env.d.ts,既消除了重复,也让类型定义有了明确的归属。大规模修复时先清 ESLint、再处理 TypeScript 的顺序是对的,语法层面干净之后,类型错误的信噪比会高很多,更容易判断哪些值得修、哪些可以暂缓。