如何基于parcelwatcher打造文件双版本备份的工具?
摘要:背景 在日常使用AI进行开发和工作中,经常遇到以下场景: AI修改代码后发现改错了,想回退到之前的版本 AI上下文溢出导致文件被删除或内容被清空 重要文档被AI误删或误改,找不到历史版本 虽然 Git 可以解决代码版本问题,但是实际工作中是
背景
在日常使用AI进行开发和工作中,经常遇到以下场景:
AI修改代码后发现改错了,想回退到之前的版本
AI上下文溢出导致文件被删除或内容被清空
重要文档被AI误删或误改,找不到历史版本
虽然 Git 可以解决代码版本问题,但是实际工作中是不可能将每次修改都commit,不仅费时费力而且不规范,此时需要一个更轻量的解决方案。
FileBackupGuardian 就是为解决这些问题而设计的桌面应用,它可以:
实时监听指定目录的文件变更
自动创建备份,保留修改前后两个版本
提供差异对比功能,直观查看修改内容
支持一键恢复到任意历史版本
技术选型
类别
技术
选择理由
桌面框架
Electron 29
跨平台支持,生态成熟
前端框架
Vue 3 + TypeScript
组合式 API,类型安全
状态管理
Pinia
轻量,与 Vue 3 深度集成
构建工具
Vite 5
开发体验好,构建速度快
文件监听
@parcel/watcher
性能优异,原生支持递归监听
差异计算
diff-match-patch
Google 开源,算法成熟
核心功能实现
1. 实时文件监听
文件监听是整个应用的核心。使用 @parcel/watcher 替代 Node.js 原生的 fs.watch,因为它:
基于 native 实现,性能更好
支持递归监听,无需手动遍历子目录
事件去重机制,避免重复触发
// watcher-manager.ts
import * as parcelWatcher from '@parcel/watcher';
async startWatching(watchPath: WatchPath): Promise<void> {
const subscription = await parcelWatcher.subscribe(
watchRoot,
async (error, events) => {
if (error) {
this.updateStatus(watchPath.id, { error: error.message });
return;
}
await this.handleParcelEvents(watchPath, events);
}
);
this.watchers.set(watchPath.id, subscription);
}
2. 双版本备份机制
这是本工具的特色功能。当文件被修改时,我们需要:
变更前备份:在文件写入前,保存原始内容
变更后备份:文件写入完成后,保存新版本
这样用户可以对比任意修改前后差异,而不仅仅是对比当前版本和备份版本。
实现的关键是利用文件内容缓存:
// 使用 LRU 缓存存储文件内容(100MB)
private fileContentCache = new LRUCache<string, CacheEntry>(100 * 1024 * 1024);
// 文件变更前,从缓存获取原始内容
private async handleFileChange(filePath, watchPathId, eventType) {
if (eventType === 'change') {
const cachedContent = this.fileContentCache.get(filePath);
if (cachedContent) {
// 使用缓存内容创建"变更前备份"
await this.backupManager.createBackupWithContent(filePath, cachedContent);
}
}
// 文件变更后,创建"变更后备份"
await this.backupManager.createPostChangeBackup(filePath, preBackupId);
}
3. Worker 线程优化
大文件的差异计算和文件计数是耗时操作,如果在主线程执行会阻塞 UI。
