39 KiB
39 KiB
DiffLens 应用开发与版本迭代规范
适用项目:DiffLens(MetonaTeam / thzxx) 文档维护:随应用版本同步更新
1. 版本号总规范
版本号遵循 语义化版本(SemVer)三段式:x.y.z
x = 主版本号(Major)
y = 次版本号(Minor)
z = 补丁版本号(Patch)
本项目最重要的约束:
x永远是0,永远不要提升到1.0.0。 版本迭代只允许修改y和z,x保持0不变。
当前基线版本:0.10.3
2. x / y / z 各自的含义与规则
| 段位 | 值 | 何时提升 | 举例 |
|---|---|---|---|
x 主版本 |
恒为 0 |
永不提升 | 不生效 |
y 次版本 |
0, 1, 2, 3 … |
新增功能 / 界面较大调整 / 构建方式变更 | 0.1.0 → 0.2.0 |
z 补丁 |
0, 1, 2, 3 … |
Bug 修复 / 样式微调 / 文档 / 依赖小升级 | 0.1.0 → 0.1.1 |
何时走 y(次版本升级 0.x.z → 0.(x+1).0)
- 新增用户可见的功能特性
- UI / 交互有较大调整
- 引入新的差异能力(如导出报告、文件夹对比)
- 内部引擎算法 / 数据结构的兼容性变更
何时走 z(补丁升级 0.x.z → 0.x.(z+1))
- 修复 Bug、崩溃、显示异常
- 细微的样式 / 文案优化
- 文档补充、依赖补丁级升级
- 非功能性重构(不改变用户可见行为)
反例(禁止)
- ❌ 直接跳到
1.0.0或更高 - ❌ 只升
x不升y/z - ❌ 同时改
y与z(一次发布只应改动一段)
3. 版本演进示意
0.1.0 ← 初始版本(已发布)
0.1.1 ← 体验打磨补丁(已发布):拖拽编码识别 · 行级右键菜单 · 尾部换行显示修正
0.2.0 ← 导出差异报告(已发布):HTML / 纯文本 / Markdown 三种格式
0.2.1 ← 建立测试体系(已发布):Vitest 单元+组件测试 · 测试策略文档
0.2.2 ← 体验打磨(已发布):拖拽处处可用 · 手动粘贴对比 · 导出后一键定位 · 报告/可读性增强 · 仅限文本文件
0.2.3 ← 安装器优化(已发布):NSIS 向导式安装,支持手动选择安装目录
0.2.4 ← 健壮性与体验打磨(已发布):读取容错与 10MB 大文件防护 · 横向滚动同步 · 下拉点击外部/Esc 关闭 · 二进制误判预警
0.2.5 ← 一致性与边角修复(已发布):右键菜单边缘防溢出 · 粘贴入口 10MB 防护 · 拖拽读取失败提示 · 多文件拖拽提示 · 剪贴板统一走主进程 · 主进程异步读取
0.2.6 ← 主进程异步收尾与边角防护(已发布):保存报告异步写盘 · 拖拽解码 handler 异步化 · 空白粘贴拦截 · 超多行卡顿预警 · 清理 mac 无效签名配置 · 文档与测试同步
0.3.0 ← 大文件性能与差异导航增强(已发布):自研虚拟滚动 · 仅看差异过滤(折叠提示行) · F7/Shift+F7 导航快捷键 · 交换左右侧 · 忽略空行
0.3.1 ← 稳健性与测试补强(已发布):超长单行词级 diff 防护 · 打开对话框补“所有文件”筛选 · 虚拟滚动 minWidth 测试覆盖 · 滚动同步去锁化重构
0.3.2 ← 报告对齐与性能收尾(已发布):纯文本报告行号右对齐 · 超长行列宽封顶防卡顿 · 对话框与拖拽扩展名清单对齐 · 右键菜单打开时导航快捷键守卫 · 清理导出死属性
0.4.0 ← 差异计算 worker 化(已发布):大文件 diff 移入 Worker 后台计算不阻塞界面 · 输入去抖与过期任务丢弃(终止重建实现取消) · 小输入同步快路径 · 无 Worker 环境回退 · 计算中遮罩与导出禁用
0.4.1 ← worker 创建开销优化与文档对齐(已发布):worker 延迟至去抖到期才创建(去抖期内取消零创建开销,无 Worker 回退同样走去抖) · 质量门禁文档补 npm test · README 架构树补 hooks · Markdown 报告标题移出引用块 · 安装包排除开发期文件
0.4.2 ← 导出菜单溢出修复与报告可读性重设计(已发布):底部工具栏导出菜单改向上弹出(修复超出窗口底边选不到) · HTML 报告全新设计(Hero 概览/人话结论/文件卡片/统计卡/图例/差异分块目录/相同段折叠可展开/打印亮色/窄屏适配,零 JS) · TXT 与 Markdown 报告头部补人话结论
0.4.3 ← 忽略所有空白比较选项与报告选项说明(已发布):新增“忽略所有空白”开关(行内空格/制表符/全角空格不参与判等,展示仍为原文,换行结构仍参与对比) · 三种报告头部新增“比较选项”说明行(HTML 为 Hero 区徽标)
0.5.0 ← 字符级对比模式(已发布):新增“字符级对比”开关(空白与换行结构全部不参与判等,两侧归一化为字符流 diff,跨行重组也能判等) · 字符差异回映射到行(跨界行配对、单侧行回拉、锚行 zip 配对,输出仍为 DiffRow,视图/报告/导航零改动) · 归一化流超 20 万字符自动降级行级对比并提示(报告头部按实际语义描述) · 字符级开启时三个空白选项置灰(语义已包含)
0.5.1 ← 字符级同行多块变更重复输出修复(已发布):字符换位专项测试暴露并修复两处回映射缺陷——同行内多处变更(ne-eq-ne 同行,如换位、同行两处替换)不再重复输出多个 modified · 回拉跨界判定与对齐行判定锚定同一 eq 块,多行换位不再把全 common 行误判为 added · 新增字符换位专项测试组(对齐任意性下的不变量固化)
0.5.2 ← 稳健性收尾与偏好记忆(已发布):diff worker 运行崩溃 onerror 兜底(终止实例回退主线程同步计算,effect 取消/jobId 已推进的迟到错误不回填) · 主进程 will-navigate 导航白名单加固(仅放行回到应用首页) · nativeTheme 暗色主题(Windows 标题栏等系统控件跟随应用风格) · 比较选项与仅看差异开关持久化(localStorage 记忆用户偏好,损坏数据防御性回退默认) · 字符级降级报告选项构造与引擎降级分支对齐(补 trimWhitespace 置否)
0.5.3 ← 稳健性补漏与偏好记忆收尾(已发布):字符级对比少行大字符量输入改走 worker 后台计算(重输入判定补入字符量维度,行数防不住 diffChars O(ND) 耗时失控) · toast 队列化(最多 3 条堆叠、各自独立计时,二进制预警不再被行数预警顶掉) · 清空按钮二次确认(toast 提示 + 3 秒确认窗口,超时自动复位) · 窗口尺寸/位置记忆(关闭保存 bounds,启动恢复并钳制回工作区,损坏数据回退默认) · 文件对话框记忆上次打开目录 · 状态栏显示两侧行数 · 偏好读取挂载期单次化 · 主进程测试基建建立(windowState 纯逻辑模块 + vitest include 扩展至 src/main)
0.5.4 ← 比较选项联动可视化与状态透明(已发布):修复禁用开关零视觉反馈的样式缺陷(原 CSS 仅有 button:disabled,checkbox 禁用后外观不变,用户不知哪些可选) · 字符级开启时三个空白选项灰显勾选(循系统惯例表达“语义已包含且生效”,仅为视觉呈现不改写用户原状态,关闭字符级即复原) · 常显“已包含”徽标(原仅 hover title 可知禁用原因) · 点击被包含选项弹 toast 解释而非无反应 · 字符级因内容超限自动降级时开关旁常显“已降级”标记(状态透明)
0.5.5 ← 字符级对比无界计算卡死修复(已发布):diffChars 携 maxEditLength=3000 封顶 Myers 迭代轮数(编辑距离超限立即放弃并降级行级,根治大字符量+大差异输入 O(ND) 无界计算导致遮罩永久卡死——实测 3 万字符全不同无上限需数十分钟) · 字符量降级阈值 20 万收紧至 3 万(双限配合将最坏耗时锁在约 2 秒,worker 内计算界面不冻结) · 重输入 worker 派发阈值随动收紧(原始字符 7500,同步快路径最坏冻结压至 0.5 秒内) · 降级提示文案改“内容或差异过大”覆盖两种降级原因 · DiffOptions 增内部测试参数 charDiffMaxEdit(测试以小阈值毫秒级构造降级场景)
0.6.0 ← 解码 worker 化 · Playwright E2E · 文件夹对比(已发布):
- 主进程解码 worker 化:≥256KB 缓冲移入 worker_threads 后台解码(GBK 纯 JS 解码大文件可达数百毫秒,不再阻塞主进程事件循环) · 解码与编码探测抽为纯逻辑模块 decode.ts(Uint8Array 入参,主进程同步路径与 worker 克隆路径共用) · worker 单例管理(崩溃拒绝在途任务并销毁重建,创建/运行失败回退主进程同步解码,行为不降级) · 构建改双入口(index + decodeWorker,iconv-lite 打包进产物) · out/main 整体 asarUnpack(Electron 的 asar 补丁不覆盖 worker 线程,unpacked 路径下无法解析 asar 内 node_modules)
- Playwright E2E 测试体系建立:对 build 产物启动真实 Electron 验收(复用项目自带 Electron,无需下载浏览器) · 首批 11 用例覆盖 jsdom 无法触达的主进程真实链路(GBK/BOM/大文件 worker 解码、报告写盘、剪贴板、偏好跨实例重启、文件夹真实扫描) · 主进程 dialog stub(showOpenDialog/showSaveDialog 可自动化) · 用例间清空 localStorage 隔离偏好污染 · npm run test:e2e 一键构建+验收,纳入发布 checklist
- 文件夹对比(MVP):新增「对比文件夹」入口(依次选择两侧目录) · 递归扫描按相对路径对齐,文件级状态判定(相同/不同/仅左/仅右;大小不同即不同,大小一致做字节级全量比对,超 10MB 采样头部 8KB 近似判定并标注 ≈) · symlink 跳过防环,单侧文件数上限 10000(超限截断提示) · FolderView 虚拟滚动列表(统计徽章/仅看差异默认开/大小列示) · 双击条目进入单文件对比复用全部 diff 能力,一键返回文件夹列表(扫描结果保留) · file:open 与 file:read-by-path 共用同一读取管线(10MB 上限/编码探测/二进制预警一致)
0.6.1 ← 文件夹对比收尾打磨(已发布):文件夹扫描内容比对受控并发化(大小一致条目按 16 并发分批读取比对,批内 Promise.all 批间串行,大目录不再逐文件串行等 IO,输出与失败语义和串行实现完全一致) · 「返回文件对比」清空两侧面板(修复先有文件对比再进文件夹退出后残留旧对比,对齐文档的单文件空态) · 两次选择同一文件夹防呆提示(不进入扫描) · ScanResult.total 注释修正(真实枚举总数,原注释误写为上限值) · README 版本号补同步 0.6.0 遗漏(元信息维护表要求随版本同步)
0.6.2 ← 文件夹对比稳健性与性能修复(已发布):双击文件夹条目任一侧读取失败时清空该侧面板(修复失败侧残留旧对比内容与旧文件名组成“名不符实”对比的缺陷,readByPath 异常/空返回/error 三条失败路径全覆盖) · 文件夹枚举改手写 BFS 遍历凑满即停(替换 readdir recursive 无法提前终止的实现,误选超大目录如 node_modules 不再枚举耗时数秒;截断时 total 为已遍历下限,界面提示改“文件过多(N+)”)
0.7.0 ← 文件夹对比增强 · 字符级分块与滚动回弹修复(已发布):
- 语义判等:字节级判“不同”的文本文件(≤2MB)二次判等——剔除全部空白(换行符 CRLF/LF、缩进、空行、排版重排)后一致计为“语义同”(大小写敏感,大小写差异仍为实质差异),消除换行符误报;解码复用解码 worker(大缓冲后台解码不阻塞),与文件打开共用同一管线;开关默认开启并持久化,切换即重扫;语义同不计入差异(仅看差异过滤),双击仍可查看明细
- 子目录树形展示:条目按路径聚合为目录树(folderTree 纯逻辑模块:建树/状态聚合/扁平化/过滤),目录行展示子树聚合状态(different > unreadable > only > 语义同 > 相同 优先级)与文件计数,点击折叠/展开(默认全展开);树形扁平化行数组保持虚拟滚动;过滤/搜索后无文件的目录自动剪枝
- 搜索与状态过滤:文件名搜索框(相对路径子串、不区分大小写,命中路径强制展开);统计徽章可点击作状态精确过滤(可多选,与“仅看差异”互斥联动)
- 文件夹报告导出:HTML/纯文本/Markdown 三格式(folderReport 模块),HTML 延续单文件报告主题(目录卡/统计卡/条目表/打印适配),报告含全量条目与判定口径说明,与界面过滤无关
- 差异文件导航:从文件夹进入单文件对比后 header 出现“差异文件 x/y”导航(Alt+↓/Alt+↑ 快捷键,不循环),语义同不计入序列;批量审查无需反复返回双击
- 大目录单点失败降级:单文件读取失败(Windows 文件锁/Defender 占用)标记“无法读取”状态(琥珀警示徽章,默认显示),单目录不可读跳过——不再整体失败丢弃全部结果(万级目录真机冒烟验证:被锁的 electron asar 正确降级,其余 9999 项正常判定)
- 字符级对比分块锚定(恢复 0.6.3 算法):行归一化锚定 + 变更组分块字符流两阶段——相同内容不进入 diffChars,大文件字符级不再整篇受限(组上限 5 万字符/编辑距离 5000/组总流 10 万,任一超限降级行级);引擎输出经真机验证精确无误(0.6.3 事故根因不在引擎)
- 滚动回弹修复(0.6.3 事故真因,0.5.3 起即存在):worker 重路径计算期间保留旧结果撑住虚拟滚动容器高度(快路径结果兜底首次重算),items 不再塌陷——scrollTop 不被浏览器钳制归零;文本变化(打开新文件/交换左右)仍清空防过期差异误导;E2E 新增滚动稳定性回归锚(真实文件+行数不等+开字符级+切选项重算断言位置保持)
0.7.1 ← 文件夹扫描竞态守卫与边角修复(已发布):文件夹扫描会话序号丢弃过期结果(语义切换触发重扫与重新选择新目录的并发扫描按序号判定,慢的旧扫描后完成不再覆盖新扫描的目录与条目、不误弹失败提示、不误清扫描态;退出文件夹对比作废在途扫描,迟到的结果不把界面拉回文件夹模式、遮罩不残留) · FolderView 补窗口尺寸变化监听(拉伸窗口变高后虚拟滚动窗口即时补齐,底部不再出现空白区,对齐 DiffView 行为) · 行号列改不透明等效合成背景(真机证实横向滚动时行文字透过 sticky 半透明行号列叠印,修复后完全遮盖,视觉色值为原叠加的预合成) · 最大化/全屏关闭改存 getNormalBounds 普通状态(本次会话调整过的窗口位置不因最大化关闭丢失,最小化仍不记录) · 行 id 生成统一为 rows.length(消除 flushRemoved 与 commitModified 双轨) · fmtSize 收敛为 folderReport 导出的单一实现(报告与列表共用) · 文档与版本号同步
0.8.0 ← 文件夹对比深度增强 · 字符级逐组预算制 · 拖拽 E2E(已发布):
- 按扩展名过滤:folderTree 纯逻辑层增 relExt/EntryFilter.exts(第四维过滤,与其他条件取交集;无扩展名文件归空串类目) · FolderView 扩展名多选下拉(动态收集全量条目 ext→count 字典序,chips 激活态、清除按钮、useDismiss 关闭) · 过滤激活时"共 N / 总数"计数切换,统计徽章口径保持全量不变
- 目录行双击聚合对比:双击目录行进入该子树的差异文件批量审查(导航序列限定子树内,语义同不计入;标签标注当前范围,Alt+↓/Alt+↑ 在范围内不漂移) · 双击任意文件条目回全局序列 · 目录内无差异文件 toast 提示不进入 · 双击前的两次单击 toggle 残留折叠态由进入时自动展开消除 · openFolderEntry 增 navScope 参数(导航与聚合入口保持范围,手动双击清除)
- 增量重扫:folderScan 枚举 stat 保留 size+mtimeMs 指纹,扫描结果携带增量缓存(ScanCacheEntry:双侧指纹 + 状态 + semSame 语义判定参与记录) · 重扫携带上次缓存时指纹一致的条目零 IO 沿用;语义判等开关翻转按 semSame 纯内存组合(different ↔ semantic-same 零 IO),仅"上次未参与语义而本次需要"的条目读内容补判 · unreadable 不进缓存(重扫重试)、截断忽略缓存且 cache 产出为空(条目不完整不可信) · IPC folder:scan 增 previous 参数(主进程防御性校验数组形态) · FolderView 增「重新扫描」按钮(不重选目录直接刷新) · 已知取舍:mtime 未变视为内容未变(rsync/make 同款,手动改回时间戳不防)
- 字符级逐组预算制(变更组粒度放宽):第二阶段从"任一超限整体降级"改为逐组判定——组流 ≤ 5 万且编辑距离 ≤ 5000 且在总预算(10 万字符)内的组走字符级,超限/预算耗尽的组仅按行级配对输出(emitGroupLineLevel:行归一化 LCS + 相邻块配 modified 词级高亮 + 多余侧 removed/added,与行级路径同构含超长行词级防护) · DiffResult 增 charModePartial 部分降级标志(与 charModeDowngraded 互斥:全部组降级仍整体降级) · Toolbar「部分降级」标记、toast 提示、报告头部选项说明(plainOptions 增 partial 描述) · 行为变更:0.7.x 整体降级的多组混合输入在 0.8.0 为部分降级(特性而非回归,测试固化新行为)
- 拖拽导入 E2E:helpers 增 dropFiles(真实 Chromium DataTransfer/DragEvent 合成拖放,覆盖 dropPane → file.arrayBuffer → decodeBuffer IPC → 编码探测全链路) · 4 用例:空面板拖入渲染、双侧拖入对比、非文本扩展名拒绝、多文件提示取首个
0.9.0 ← 忽略规则 · 增量缓存跨会话持久化 · 快照基线 · 字符级预算自适应 · 性能基准 E2E(已发布):
- 忽略规则:ignoreRules 纯逻辑模块(gitignore 简化子集——`dir/` 目录名匹配整树剪枝(不枚举不计数,不占用 maxFiles)、`*.ext` 扩展名通配、`name` 名字精确匹配;大小写不敏感;`#` 注释与空白行跳过;多段路径与非法通配整体忽略;上限 50 条/单条 500 字符双重防御) · folderScan listFiles BFS 内剪枝(双侧共用同一 matcher) · 被忽略项不进结果/缓存/total/truncated,规则变化后缓存按指纹自然失效(未命中走全量判定) · FolderView「忽略规则」下拉(每行一条文本域草稿、应用并重扫、清空规则,入口标注规则数) · 规则随偏好 localStorage 持久化(启动恢复并随扫描下发,损坏字段防御性过滤) · IPC folder:scan 增 ignoreRules 参数(isIgnoreRulesArray 校验)
- 增量缓存跨会话持久化:scanCacheStore 纯数据模块(userData/scan-cache.json 落盘;目录对键归一化——反斜杠转斜杠/去尾分隔符/Windows 盘符小写;LRU 上限 8 对按 savedAt 淘汰,当前写入对永不淘汰;解析全部防御性校验——JSON 非法/版本不符整体回退空存储,单条 entry 异常仅丢弃该条) · 主进程 folder:scan 渲染端未携带内存缓存时自动注入盘上缓存(跨会话首次扫描增量),扫描成功且未截断异步落盘(读-改-写,失败静默) · 渲染端链路零改动(内存缓存优先逻辑保留)
- 快照基线:snapshotDiff 纯逻辑模块(快照结构 version/leftDir/rightDir/semantic/truncated/total/entries/savedAt,parseSnapshot 全字段防御校验绝不部分加载;diffSnapshot 按 rel 对齐产出六类变迁——fixed/regressed/new/gone/changed/stable,以 isDiffStatus 为主轴;snapshotDirsMatch 目录对一致性校验) · 「保存快照」复用报告保存管线落盘 JSON(默认名带时间戳) · 「加载快照」走打开文件对话框读取(目录对不一致/文件无效/读取失败/无当前结果四类拦截提示) · 对照模式接管 FolderView 列表渲染:变迁统计徽章(点击单选过滤)替换常规统计行、平铺全路径行 + 变迁徽章(gone 回退快照数据展示)、默认隐藏 stable、搜索共用、退出对照恢复 · 对照随重扫自动刷新(目录对仍一致时),退出文件夹对比清空 · 对照模式导出报告附「快照对照」口径行(三格式)
- 字符级预算自适应:charGroupBudget(totalGroupChars) = clamp(总组流/2, 下限 10 万, 上限 100 万)——下限与 0.8.0 固定值一致(小输入行为与已固化测试零变化),大输入但变更组普遍较小的场景按比例放宽(上限封顶最坏总耗时仍有界,单组 5 万/编辑距离 5000 不变) · plainOptions 字案与 Toolbar title 同步("预算随规模自适应") · 行为固化测试:400 组跨行重组总流 48 万 → 预算 24 万 → 200 组字符级(固定预算仅 83 组)
- 性能基准 E2E:5 万行双文件 20 处差异——打开右侧到「有差异」出现耗时 < 15s(万级行实测秒级,慢机 4 倍余量防 flaky,断言失败即性能回归) · 300KB GBK 15000 行——打开到状态栏行数渲染 < 10s · 新功能 E2E:忽略规则目录剪枝重扫、增量缓存跨重启(scan-cache.json 落盘断言 + 第二实例重扫正确)、快照保存→修复差异→加载对照变迁
0.9.1 ← 快照收尾修复 · IPC 校验单测化 · 对照报告变迁明细 · 渲染兜底(已发布):
- 快照目录对归一化匹配(修复):snapshotDirsMatch 此前逐字符比较,Windows 下 C:\Foo 与 c:/Foo 同目录异写会被误判"目录对不一致"而拦截对照——归一化(反斜杠→斜杠/去尾分隔符/盘符小写)后比较,与主进程 scanCacheStore.pairKey 同款逻辑(两进程无法共享模块,双向同步标注);大小写敏感文件系统的路径段大小写差异仍正确判不一致
- 截断结果保存快照拦截(修复):扫描结果截断时条目不完整(仅前 1 万个),此前可照常保存快照——日后对照时快照缺失的文件被全部误判为"新文件";现保存前检查 truncated,toast 拦截提示"快照不完整无法对照"(对齐同目录防呆、目录不一致拦截的既有防呆风格)
- folder:scan IPC 校验单测化:此前 handler 内联的 previous 形态校验 / ignoreRules 校验 / 盘上缓存注入组合逻辑位于覆盖率排除的主进程入口(零单测),抽为 scanIpc 纯逻辑模块(isScanCacheEntries 形态校验 + resolveScanArgs 缓存源选择——内存缓存优先含空数组、非法回退盘上缓存、惰性读盘保证携带有效缓存时不产生读盘 IO),index.ts 变薄壳,单测全覆盖(测试策略第 9 节演进方向落地)
- 对照模式导出报告附变迁明细:此前对照模式导出只附一行变迁统计说明,条目表仍是普通扫描结果(看不出逐条变迁)——现提供 snapshotEntries 时三格式条目表整体替换为变迁对照表(变迁/相对路径/当前状态/基线状态/双侧大小,gone 回退基线大小;HTML 按变迁配色含打印适配),全量含 stable(报告信息零丢失口径);变迁标签收敛为 snapshotDiff 导出的 SNAPSHOT_CHANGE_LABEL 共享映射(FolderView 徽章与报告共用单一实现);E2E 快照用例补对照导出真实写盘断言
- 顶层 ErrorBoundary 防白屏:任何组件渲染期抛错由边界捕获,显示错误信息(可复制)+ 一键重载按钮,替代整窗白屏死机;事件回调内异常不属于 ErrorBoundary 捕获范围(由各回调自身 try/catch 防御,注释标注边界)
0.9.2 ← 快照对照对称缺陷修复 · 扫描中交互防抖 · 右键菜单键盘导航(已发布):
- 快照对照对称缺陷修复(快照基线稳健性收尾):加载快照拦截当前扫描结果截断(0.9.1 只拦了保存侧——当前条目不完整时对照会把截断缺失的文件误报为"已移除",与保存侧"快照缺失误报新文件"对称的同类误报;拦截发生在文件选择之前不弹对话框) · 对照模式中重扫触发截断自动退出对照并提示(不残留过期对照) · 快照语义判等口径与当前开关不一致时加载提示"对照结果含口径差异"(口径变化不再被静默当成内容变化——原语义同文件换口径重判后显示"新增差异"类误导;提示不拦截对照,基线行仍标注快照口径)
- 扫描中交互防抖:扫描进行中禁用语义判等开关与忽略规则入口(二者触发重扫——竞态守卫本已保证结果正确,防抖消除无谓的叠加扫描;仅看差异/搜索/扩展名过滤为纯视图过滤不禁用,与"重新扫描/保存快照/加载快照/导出报告"的既有 disabled 风格对齐)
- 右键菜单键盘导航:↑/↓ 在菜单项间移动高亮(跳过禁用项、首尾循环),Enter 触发高亮项,Esc 关闭不变;鼠标悬停与键盘高亮同步;全部禁用时方向键无操作不崩溃
- 微打磨与依赖:清理 CSS 孤儿变量(--pink/--panel-2 定义未消费) · 依赖 patch 级升级(npm update 语义化范围内,核心依赖 electron/vitest/vite 版本不变,仅间接依赖小幅更新)
0.9.3 ← 单文件视图搜索 · 扫描缓存落盘串行化 · 交互收尾(已发布):
- 单文件视图文本搜索(补齐文件夹模式有搜索而单文件模式没有的功能缺口):工具栏新增搜索框,Ctrl+F 聚焦(粘贴弹窗/右键菜单打开时不抢占)、大小写不敏感即时命中计数(x / y)、Enter/Shift+Enter 在命中行间循环跳转(复用差异导航的 activeRowId 受控定位,虚拟滚动下天然可用)、行内命中子串高亮(纯文本行与词级 segs 行均拆分标注,黄色系与增删改三色不冲突)、Esc 清空复位 · 搜索基于全量行(与"仅看差异"独立,被折叠的命中行仍计数;跳转目标被折叠时 toast 提示且不推进) · 线性扫描 5 万行毫秒级无需 worker,会话级临时状态不持久化
- 扫描缓存落盘串行化:persistScanCache 读-改-写经内存 promise 链按序执行(每次追加到链尾,失败静默不断链)——两次扫描近乎同时完成时不再后写整体覆盖先写丢 LRU 目录对
- 交互收尾:快照对照的变迁类型过滤在重扫刷新后计数归零时自动复位(残留过滤会让列表误显空态) · 「重新选择」扫描中保持可用并固化测试(与「返回文件对比」同类:发起新会话作废在途扫描,竞态守卫保证迟到结果丢弃;大目录扫描慢时允许用户放弃改选——曾考虑按防抖一致性禁用,经既有用例证伪后放弃)
- 测试与依赖:新增 21 用例(App 8 / Toolbar 7 / DiffView 4 / FolderView 2)与 E2E 搜索链路用例 · 依赖 patch 级升级(npm update 语义化范围内)
0.10.0 ← 快照内容级对照 · 忽略规则高级 glob · 扫描进度反馈(已发布):
- 快照内容级对照(快照功能链收官):快照结构升级 v2 可选携带差异条目的双侧文件内容(contents),对照模式双击含基线内容的变迁条目进入"快照基线 vs 当前文件"的单文件内容对比(左面板为基线内容并标注"快照 · 文件名",右面板为当前文件,完整复用比较选项/字符级/搜索/差异导航/导出全部能力) · 保存链路经新增 folder:read-batch 批量读取 IPC(受控并发复用单文件读取管线,单文件失败该条目降级不整体失败) · 体积双限:单文件 2MB(对齐语义判等上限,超限侧不存内容)、内容总量 32MB(超出整体降级为纯状态快照并提示,保存永不失败) · v1 旧快照兼容加载(无 contents 走纯状态对照,双击维持常规当前文件对比) · 既定取舍:仅保存差异条目内容,regressed 场景(基线一致→现在有差异)的基线内容不保存 · 解析校验 contents 任一条目形态异常整体拒绝(绝不部分加载的既有口径) · 保存期间"正在读取差异文件内容"遮罩
- 忽略规则高级 glob(匹配器重写):新增多段路径(src/temp 从根锚定)、前导 / 锚定(/build 仅根级,无前导单段名维持任意层级)、整段 ** 跨段通配(build/**/cache,尾部 ** 需至少一段与 gitignore 一致)、段内 * 通配放开位置限制、! 否定规则(同一路径最后一条匹配的规则生效,与 gitignore 语义一致;父目录被剪枝后子项无法反否定——BFS 剪枝语义与 gitignore 同款并文档化) · 匹配器从按名字匹配重构为按完整相对路径判定(matchesPath,含否定仲裁;预编译字面量/段正则/跨段三类段模式,DP 段序列匹配) · 无效规则不再静默丢弃:规则下拉实时提示"将被忽略的无效规则"(段内 ** / 空段 / ! 后为空等) · 纯逻辑模块迁移至 src/shared(主进程 folderScan 与渲染端 FolderView 共用同一源文件,消除双向同步负担;tsconfig 双端与 vitest include 同步扩展)
- 扫描进度反馈(首个 push 型 IPC):folder:scan 增 scanId 参数(复用渲染端扫描会话序号),比对阶段每并发批次完成经 event.sender.send 推送进度(isDestroyed + try/catch 防御窗口销毁) · preload 暴露 onScanProgress 订阅(返回取消函数) · 渲染端只显示与当前会话序号一致的进度事件(旧扫描迟到进度天然丢弃,与结果竞态守卫同一套序号,不引入新竞态面) · 扫描遮罩显示"已比对 N / M"(缓存命中的零 IO 条目不计入 total,增量重扫进度即时完成符合语义)
- 测试与文档:新增 33 单测(ignoreRules 30 全量重写 / folderScan glob 集成与 onProgress / snapshotDiff v2 / App 内容对照与进度 / FolderView 无效提示与进度)与 4 条 E2E(快照内容级对照全链路 / 高级 glob 含否定与无效提示 / 扫描进度轮询抓取),共 596 单测 + 27 E2E(此前文档误记 28,实际清点为 27)
0.10.1 ← 忽略规则字符通配 · 快照保存读取进度 · 差异导航游标修复(已发布):
- 忽略规则字符通配(段内通配子集扩展):段内模式新增 `?` 单字符通配(lo?g 命中 loog 不命中 log,不跨段)与 `[abc]`/`[a-z]`/`[!abc]` 字符类(*.[ch] 命中 .c/.h、log[0-9].txt 命中数字后缀、[!abc] 取反);未闭合 `[` 与空类体([]/[!])退化为字面量方括号(gitignore 同款语义),无法构成合法正则的类体(反转范围 [z-a])整段回退字面量匹配永不崩溃;大小写不敏感语义不变(模式与路径双侧小写化后匹配);既有 `*`/`**`/否定/多段锚定语义与段内 `**` 非法判定完全不变(回归锚固化);UI 忽略规则下拉的提示文案与 title 同步新语法
- 快照保存读取进度:保存快照批量读取差异条目内容期间遮罩显示"已读取 N / M"(文件数口径:去重后双侧路径总数,按 200/批推进,与扫描进度反馈对称,大差异目录不再无反馈干等);保存结束/失败进度随遮罩复位
- 差异文件导航游标修复:导航游标不在差异序列时导航组直接隐藏——此前显示"—"计数且"下一个"按钮可点无响应(goDiffFile 静默 return);触发路径为双击 same/语义同条目进入对比(0.7.0 遗留)与快照对照模式双击 fixed/regressed/new 等当前无差异条目进入内容对照(0.10.0 放大暴露面);双击差异条目即回序列、导航恢复
- 测试与文档:新增 16 用例(ignoreRules 字符通配 12 / folderScan 字符通配集成 1 / App 导航隐藏 2 与读取进度 1)并修复 0.10.0 遗留的 snapshotDiff.test 版本号类型错误(makeSnapshot 传 3/0 违反 1|2 字面量联合,改展开构造),共 612 单测 + 27 E2E
0.10.2 ← 大快照加载修复 · 快照保存防抖 · 关于弹框(已发布):
- 大快照加载修复(保存/加载上限不对称):保存侧快照内容总量上限 32M 字符(中文 JSON 化可达 ~96MB),但加载走 file:open 通用通道被 10MB 上限拦截——大差异目录的快照"保存成功却永远无法加载";新增 snapshot:read 专用 IPC(JSON 过滤对话框 + 128MB 读取上限 + UTF-8 直读不做编码探测),顺带消除快照加载污染文件对话框 lastDir 记忆的副作用
- 快照保存中防抖:保存遮罩为纯视觉反馈(computing-overlay 的 pointer-events:none 不拦截交互),此前保存期间可再点"保存/加载快照"并发触发两轮保存对话框——现 FolderView 保存/加载按钮随 saving 禁用(与扫描中禁用同语言),App.loadSnapshot 增加保存中守卫双保险
- 同目录防呆归一化:两次选择同目录的判定从严格字符串比较改为路径归一化后比较(复用 snapshotDiff 导出的 normDir,与 scanCacheStore 同款逻辑)——Windows 异写路径(大小写/分隔符差异)不再绕过防呆
- 关于弹框:header 右侧常驻 ⓘ 图标按钮(两种模式可见)→ 弹框展示应用 Logo/介绍/版本号(app:get-version IPC 取 app.getVersion(),package.json 为唯一来源,dev 与打包一致)/作者 thzxx/邮箱(stinanimz@gmail.com、1440196015@qq.com)/组织 MetonaTeam/开源地址/许可证 MIT;Esc/遮罩/关闭按钮关闭,邮箱与开源地址点击复制(复用主进程剪贴板管线)
- 微清理:删除孤儿 CSS 类 .diff-empty-pane(0.9.2 清理孤儿变量的漏网);folderTree 聚合优先级注释补 unreadable
- 测试与文档:新增 14 单测(AboutModal 9 / App 4:关于打开关闭·复制·文件夹模式可见·异写防呆 / FolderView 1:saving 禁用)与 2 条 E2E(关于弹框真实链路含版本号与复制 / 11MB 大快照加载成功固化上限修复),共 626 单测 + 29 E2E
0.10.3 ← GB 大小显示修复 · 主进程同步 IO 异步化 · 双进程重复逻辑收敛(已发布):
- GB 级文件大小显示修复:fmtSize(文件夹列表与三格式报告共用实现)补 GB 档——文件夹对比无单文件大小上限(10MB 只是全量比对上限,更大文件采样判定但大小字段照常显示),GB 级文件(视频/镜像)此前显示为 1024.0 MB 甚至 512000.0 MB,现正确显示 1.0 GB 档
- 主进程同步 IO 异步化("主进程 IPC 全异步"原则补漏):loadScanCacheStore 的 readFileSync 改 fs.promises(缓存文件可达 MB 级——LRU 8 对 × 万级条目,此前在 folder:scan handler 内与落盘读-改-写中同步读盘阻塞事件循环) · scanIpc.resolveScanArgs 异步化(loadStored 接受同步/异步实现,惰性语义不变——渲染端携带有效缓存时仍零读盘) · saveState 拆分 sync(close 事件,保证退出前落盘)/ async(file:open 与 folder:pick 内)双版本
- 双进程重复纯逻辑收敛到 src/shared(沿 0.10.0 ignoreRules 迁移先例,消除"两进程无法共享模块"的过时注释约束):TEXT_EXTENSIONS 60 项清单(主进程对话框筛选与语义判等文本判定 ↔ 渲染端拖拽入口校验,双向同步负担清零) · normDir 路径归一化(主进程 scanCacheStore 目录对键 ↔ 渲染端 snapshotDiff 目录对匹配与 App 同目录防呆) · IGNORE_RULES_MAX 上限常量(shared 定义 + App/FolderView 改直接导入,三处同步收敛为一处)
- 安装包排除开发期文件补漏:electron-builder files 增 !e2e/* 与 !playwright.config.*(0.4.1 排除清单制定时 e2e 尚不存在,0.6.0 引入 E2E 后未补——E2E 源码与配置此前被打进 asar)
- 扫描进度 E2E 用例采样修稳(环境敏感型瞬态断言,非功能缺陷):快机上 2000 条目比对窗口仅 ~120ms,locator.textContent() 在遮罩消失后自动重试阻塞 10s 吞掉后续采样——改为 evaluate 直读 DOM + 条目增至 4000 拉长瞬态窗口 + intervals 前密采样;诊断实证进度事件链路正常(遮罩文本完整经历 272/976/1696 推进)
- 测试与文档:新增 8 单测(fmtSize 各档与 GB 修复锚 3 / scanIpc 异步 stub 兼容 1 / pathNorm 直接单测 4)与共 634 单测 + 29 E2E(进度用例采样方式修稳,语义不变)
...
0.y.z ← 长期停留,永不进入 1.x
4. 应用命名约束(三重一致)
交付给用户的所有可见名称必须统一为 DiffLens:
| 环节 | 名称 |
|---|---|
| 安装包文件名 | DiffLens-{version}-setup.exe |
| 安装后主程序 | DiffLens.exe |
| 开始菜单 / 桌面快捷方式 | DiffLens |
| 窗口标题 | DiffLens |
| 工程内部 name / productName | DiffLens |
注:
appId为内部安装标识(如com.metonateam.difflens),不展示给用户,不受此约束。
5. 开发流程
需求确认 → 方案权衡 → 开发实现 → 本地自测 → 类型检查 → 生产构建 → 代码评审 → 合并 → 发布
- 需求确认:明确目标,先梳理全貌,避免返工
- 方案权衡:涉及取舍时列出利弊,由负责拍板
- 开发实现:聚焦需求本身,不过度设计
- 本地自测:
npm run dev运行验证 - 质量门禁:见第 7 节
- 发布:见第 8 节
6. 分支与合并规范
main:唯一稳定主干,始终可运行、可发布- 功能分支:
feature/<功能名> - 修复分支:
fix/<问题描述>
main
└─ feature/xxx → (评审后合并回 main)
合并且无二次改动时,才允许 rebase 保持历史整洁;否则用普通合并提交。
7. 质量门禁(提交/推送前必须通过)
每次提交与推送前执行:
npm run typecheck # 类型检查(node + web 双端)
npm test # Vitest 单元 + 组件测试(覆盖率 80% 硬门禁)
npm run build # 生产构建(main/preload/renderer 三端)
任一命令失败则禁止提交;修复通过后再提交。与《测试策略与方案》第 7 节保持一致。
8. 发布流程
npm run build:win # Windows NSIS 安装包(在 Windows 上)
发布前 checklist:
- 更新
package.json的version到新的0.y.z - 更新本文件第 3 节演进记录
- 通过质量门禁(typecheck + test + build)
- 通过 E2E 验收(
npm run test:e2e,对 build 产物跑真实 Electron 主链路,0.6.0 起纳入发布必跑) - 打标签并推送到远程
git.metona.cn/MetonaTeam/DiffLens - 如需发布安装包,生成对应平台产物与 Release 说明
9. 元信息维护表
| 文件 | 维护内容 |
|---|---|
package.json |
version(唯一版本来源)、name、productName 保持 DiffLens |
electron-builder.yml |
productName / executableName / artifactName 保持 DiffLens |
README.md |
特性描述与发布版本号随版本同步 |
| 本文件 | 第 3 节演进记录同步补写 |
版本号只以
package.json的version为唯一来源,其余打包产物名由它派生。
附:提交信息格式
采用约定式提交:
<type>: <描述>
feat: 新增功能 (配 y 版本)
fix: 修复问题 (配 z 版本)
docs: 文档变更
build: 构建/依赖
refactor: 重构(不改行为,配 z 版本)
例如:
feat: 新增导出差异报告→0.2.0fix: 修复 GBK 文件乱码→0.1.1
© 2026 MetonaTeam · thzxx · DiffLens