资讯动态

HyperFrames v0.7.89:缓存目录的 Watch 过滤与项目签名隔离——预览刷新循环的根治方案

发布时间:2026/9/10 3:53:51 来源:尧图企业网站定制
HyperFrames v0.7.89缓存目录的 Watch 过滤与项目签名隔离——预览刷新循环的根治方案【免费下载链接】hyperframesWrite HTML. Render video. Built for agents.项目地址: https://gitcode.com/GitHub_Trending/hy/hyperframesHyperFrames v0.7.892026-08-02 发布解决了一个看似隐蔽却影响开发体验的问题由系统自身生成的波形waveform、缩略图thumbnail与转码transcode缓存会反过来触发 Studio 项目重载甚至作为“项目文件”出现在文件树中。本文基于发布说明 releases/v0.7.89.md 展开结合 CLI 文件监听器与 studio-server 项目签名project signature的源码实现完整还原该问题的成因、修复的两条主线CLI 递归 watcher 过滤 Studio 签名/文件树隔离以及“真实源文件编辑仍然正常失效预览”这一兼容性约束是如何通过测试用例固化的。读完后你将理解 HyperFrames 中“生成物与源文件”的边界是如何在三处机制watcher 过滤、签名排除、目录遍历排除中保持一致的。版本发布说明v0.7.89 的官方发布说明见 releases/v0.7.89.md原文要点如下Stops generated waveform, thumbnail, and transcode caches from retriggering Studio project reloads or appearing as project files. Real source edits still invalidate previews normally.FixesCLI:Ignore generated cache directories in the recursive project watcher, preventing preview refresh loops during cache generationStudio:Keep generated caches out of Storyboard signatures and the project file tree while retaining invalidation for real source edits一句话概括这是一个纯修复版本两条修复线分别落在CLI 侧的项目文件监听器与Studio 侧的项目签名/文件树上目标是切断“生成缓存 → 监听/签名变化 → 预览重载 → 再次生成缓存”的自激循环同时保留“真实源码编辑 → 预览失效”的正常行为。问题背景三类生成缓存目录从何而来要理解修复的必要性先看 HyperFrames 在预览/播放过程中会在项目目录下自动生成哪三类缓存。从源码可以确认它们各自的产生位置缓存目录产生者源码位置.waveform-cache波形peaks计算路由用于时间轴波形绘制waveform.ts 中join(projectDir, .waveform-cache).transcode-cache代理转码器对远程/大体积媒体转码出轻量代理proxyTranscoder.ts 中CACHE_DIR_NAME .transcode-cache.thumbnails缩略图/海报帧抓取路由Storyboard 每个帧的缩略图都写在这里thumbnail.ts 及测试 thumbnail.test.ts关键在于这些写入恰恰发生在预览请求的处理链路上。projectSignature.ts的注释里把这一点说得很直白——.thumbnails/目录由缩略图路由在每次抓取时写入而每次抓取又要读取预览如果一个不加过滤的 watcher 对一切文件变化都响应失效就会“丢弃它本该保护的 memo而且恰好丢弃在最需要 memo 的那类负载的几乎每个请求上”。于是形成循环预览/Storyboard 加载 → 触发波形、缩略图、转码缓存写入缓存文件变化 → 项目文件监听器上报 → 项目签名变化 → 浏览器预览整体重载重载后重新请求 → 回到第 1 步。v0.7.89 之前的表现即“preview refresh loops during cache generation”缓存生成期间的预览刷新循环。修复线一CLI 递归 watcher 的排除目录过滤CLI 侧的项目监听器实现在 fileWatcher.ts。核心是一个维护着 15 个排除目录名的常量集合fileWatcher.ts#L13-L28const WATCHER_EXCLUDED_DIRS new Set([ .cache, .git, .hyperframes, .next, .thumbnails, .transcode-cache, .vite, .waveform-cache, build, coverage, dist, node_modules, outputs, renders, ]); const DEBOUNCE_MS 300;注意三类生成缓存目录.thumbnails、.transcode-cache、.waveform-cache都在其中。判断逻辑是逐段检查相对路径的每个目录段而不只是父目录fileWatcher.ts#L31-L35export function shouldWatchProjectFile(filename: string): boolean { if (!filename) return false; const parts filename.split(/[\\/]/); return !parts.some((part) WATCHER_EXCLUDED_DIRS.has(part)); }逐段匹配意味着连“对排除目录本身的目录级事件”如unlinkDir .thumbnails也能被过滤掉。createProjectWatcher内部用fs.watch(projectDir, { recursive: true }, ...)做递归监听fileWatcher.ts#L44并对回调做了 300ms 的防抖与去重同一时间窗口内的多个变化事件合并成一次批量通知fileWatcher.ts#L59-L70。一个关键例外两个 Studio 清单文件必须“豁免”排除列表里还有一个容易被忽略的细节。.hyperframes/整体在排除集合中但该目录下的两个文件会直接影响预览签名Studio 会在运行时写入其中之一fileWatcher.ts#L47-L57.hyperframes/studio-manual-edits.json.hyperframes/studio-motion.json这两个路径定义在 projectSignature.ts#L35-L38 的STUDIO_SIGNATURE_MANIFEST_PATHS中。如果 watcher 在入口就把它们丢弃CLI 服务端的 ETag 会在重启前一直保持过期状态因此监听器对“命中这两个清单文件的写入”做了显式豁免if ( !shouldWatchProjectFile(relativePath) !affectsProjectSignature(projectDir, join(projectDir, relativePath)) ) { return; }也就是说只有“既不是生成缓存、又与项目签名无关”的变化才被丢弃触发浏览器重载的判定仍由下游的 reload 监听器自行完成行为保持不变。防御性细节watcher 自身的降级递归监听在真实环境里可能异步失败典型如 watch 句柄耗尽导致的EMFILE。这类失败会以error事件形式出现而非抛出异常EventEmitter上无监听器的error会直接打崩进程所以代码显式挂了一个静默降级监听器关闭 watcher 并置空fileWatcher.ts#L72-L80。同步失败try/catch包裹watch调用与异步失败都遵循同一“优雅降级”原则最坏情况是失去自动刷新而不是进程崩溃。修复线二Studio 项目签名与文件树的缓存隔离Studio 侧的修复对应发布说明中的第二条“Keep generated caches out of Storyboard signatures and the project file tree”。它由两个正交部分组成。2.1 项目签名排除生成目录但保留真实源编辑的失效能力预览缓存破坏cache-busting签名由createProjectSignature生成projectSignature.ts#L201-L233算法是递归遍历项目目录跳过SIGNATURE_EXCLUDED_DIRS与 watcher 的排除集字符级相同见 projectSignature.ts#L18-L33符号链接跳过文本类文件.cjs/.css/.html/.js/.json/.jsx/.mjs/.svg/.ts/.tsx且不超过 2MB见 projectSignature.ts#L6-L17 与MAX_SIGNATURE_TEXT_BYTES 2_000_000参与内容哈希二进制文件只取 mtime对收集结果先算一个轻量“指纹”fingerprint与上次缓存相同则直接复用已算好的签名避免每次请求都重读全部文本文件projectSignature.ts#L162-L176。签名之外还有一个配套的判定函数affectsProjectSignatureprojectSignature.ts#L60-L68用于回答“某次写入是否可能改变签名”。它的注释明确解释了为什么这个职责必须收敛在签名模块内而不能复制一份过滤逻辑到 watcher 里“一旦任一集合发生变化两份推理就会漂移”a second copy of that reasoning drifts the moment either set changes。这也是修复线一中 watcher 豁免逻辑调用它的根源。注意签名排除集与 watcher 排除集看似相同实则语义不同签名排除集虽然也包含.hyperframes但签名会额外读取上面提到的两个清单文件STUDIO_SIGNATURE_MANIFEST_PATHS——affectsProjectSignature对这两条路径直接返回true。源码注释特别警告如果错误地用 watcher 那套“整个.hyperframes/都排除”的逻辑来过滤签名motion-state 的保存就永远不会触发失效projectSignature.ts#L50-L58。2.2 项目文件树遍历层级的目录剪枝“不出现为项目文件”由目录遍历层的剪枝保证涉及两处实现文件树遍历safePath.ts 中的IGNORE_DIRS集合.thumbnails、.transcode-cache、.waveform-cache、node_modules、.git被walkDir在递归时直接跳过safePath.ts#L34-L46另通过shouldIgnoreDir单独隐藏.hyperframes/backupStudio 自身备份快照不进入文件树。重命名引用扫描files.ts 中walkFiles对node_modules、.thumbnails、renders、.transcode-cache做同样的目录剪枝保证 Studio 的引用更新扫描不会把生成物当成项目文件处理。一个值得注意的设计边界过滤是分层的。isInHiddenOrVendorDirsafePath.ts#L28-L31只把点目录/node_modules下的 HTML 挡在“composition 发现”合成入口列表之外而不挡文件树——vendored 在点目录里的文件仍然可以浏览只有生成缓存与备份快照被文件树隐藏。2.3 测试固化缓存写入不改签名源编辑必须改签名v0.7.89 的行为契约由 projects.test.ts 中的用例明确固化值得完整引用其断言逻辑const generatedFiles [ [.transcode-cache, proxy.mp4], [.thumbnails, frame.jpg], [.waveform-cache, peaks.json], ] as const; // 依次写入三类缓存文件每次都重新请求 /projects/:id/signature expect(generatedSignatures).toEqual([initial, initial, initial]); // 签名不变 mkdirSync(join(projectDir, src)); writeFileSync(join(projectDir, src, scene.ts), export const scene true;); expect(await getSignature()).not.toBe(initial); // 真实源编辑必须改变签名同一测试文件还断言了文件树不返回生成缓存路径projects.test.ts#L167-L181payload.files中不含.transcode-cache/proxy.mp4与.waveform-cache/peaks.json。CLI 侧对应的回归测试在 fileWatcher.test.ts#L22-L39它断言.transcode-cache/proxy.mp4、.thumbnails/frame.jpg、.waveform-cache/peaks.json一律shouldWatchProjectFile(...) false同时index.html、src/scene.tsx、assets/hero.png等真实源文件仍为true另外两个用例分别验证了 300ms 防抖窗口内的事件去重同窗口多次变化合并为一次批量回调以及EMFILE类error事件不会击穿进程。签名模块自身的行为测试在 projectSignature.test.ts其中专门断言了.thumbnails/frame-0.jpg与目录级事件.thumbnails都不影响签名。设计要点小结v0.7.89 表面上是两个 bugfix实际上确立了 HyperFrames 中“生成物 vs 源文件”边界的三处一致性约定理解它有助于后续维护或二次开发时不踩同样的坑watcher 过滤fileWatcher.ts决定“什么文件系统事件值得上报”。排除集 逐段匹配 300ms 防抖外加两个 Studio 清单文件的签名豁免。签名排除projectSignature.ts决定“什么变化会让预览签名ETag/缓存键变化”。排除集与 watcher 保持一致但通过affectsProjectSignature单点维护判定逻辑避免复制漂移。遍历剪枝safePath.ts、files.ts决定“什么文件会出现在 Studio 文件树与合成发现里”。生成缓存目录在递归入口处被跳过。三层的排除集合必须保持同步——这也是为什么发布说明强调 “Real source edits still invalidate previews normally”任何一侧过度过滤都会破坏缓存失效的正确性例如把.hyperframes/studio-motion.json误排除会导致 motion-state 保存后预览不再刷新任何一侧过滤不足都会重新引入刷新循环。适用前提与验证方式本文所有机制描述基于当前仓库源码对应 v0.7.89 及之后的代码状态行为说明以 releases/v0.7.89.md 的发布说明为准。若你想自行验证CLI 侧可运行packages/cli下 vitest 套件中fileWatcher.test.ts相关用例studio-server 侧可运行projects.test.ts与projectSignature.test.ts其中“生成缓存写入不改变签名”与“真实源编辑改变签名”是对称的两组断言正是本版本修复契约的直接体现。从源码结构看该隔离方案是白名单豁免 黑名单剪枝的组合而非全量白名单项目目录下任何不在排除集中的文件包括非标准扩展名都会进入签名哈希因此自定义资源目录的增删改仍会正常触发预览更新。【免费下载链接】hyperframesWrite HTML. Render video. Built for agents.项目地址: https://gitcode.com/GitHub_Trending/hy/hyperframes创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价