[Refactor/Chore] Improve vp check performance

该 Issue 不是运行时报错,而是 Dify 仓库在 Vite+ 迁移后 `vp check` 静态检查耗时过长(完整配置中位约 28.30 s)。优先排查 JavaScript 插件(尤其 eslint-react 、 eslint-plugin-better-tailwindcss )与 ty

快速结论:该 Issue 不是运行时报错,而是 Dify 仓库在 Vite+ 迁移后 `vp check` 静态检查耗时过长(完整配置中位约 28.30 s)。优先排查 JavaScript 插件(尤其 eslint-reacteslint-plugin-better-tailwindcss)与 type-aware tsgolint 的 TypeScript program 构建开销,而不是原生 Oxlint 规则。

适用环境:Issue 中确认的工具版本为 Vite+ 0.2.4、Oxlint 1.72.0、oxlint-tsgolint 0.24.0;涉及 Dify 仓库的 web/tsconfig.json 及 pnpm workspace 依赖;CI lint 作业使用 4 核 runner。Issue 未说明操作系统、Python、CUDA 或显卡环境。

最快修复方案:暂无确认的一步修复方案。Issue 中已实测有效的方向是移除 eslint-plugin-better-tailwindcss:在同一基准窗口下,完整仓库配置的中位 wall time 从 28.30 s 降至 22.75 s(约 -19.6%),中位 user CPU 从 61.34 s 降至 54.65 s(约 -10.9%);但这是以减少 lint 覆盖为代价的取舍项,需单独评审。

注意事项:各阶段耗时使用不同入口,可能存在重叠的 setup 工作,属于方向性指标,不能直接相加做精确核算。单插件 delta 也只是排序信号,不是可加总的账目。单独移除插件会降低 lint 覆盖率;内存收益在该次测量中不成立(区间重叠、中位数未改善)。compilerOptions.incremental 不适用于当前 tsgolint 路径。

问题场景

在 Dify 仓库完成 Vite+ 迁移(langgenius/dify#38833)之后,开发者在本地或 CI 中执行仓库的 Vite+ 静态检查(vp check / 直接 pnpm -w check),发现端到端耗时明显偏高。对迁移后配置做 profiling 后可以看到,成本主要来自两块:Oxlint 的 JavaScript 兼容插件,以及 tsgolint/type checking 使用的 type-aware TypeScript program。原生 Oxlint 规则本身开销很小。

报错原文

[Refactor/Chore] Improve vp check performance

该 Issue 属于 refactor/chore 类型,本身没有异常堆栈。核心现象是性能剖析数据:

| Scope | Wall time | Maximum RSS | Interpretation |
| Full configured lint | about 28.5 s | about 6.0-6.6 GB | JavaScript plugins, native rules, and type-aware work |
| JavaScript plugins with type-aware lint disabled | 20.93 s | 2.41 GB | Dominant wall-time layer |
| Type-aware tsgolint phase | 6.6-7.0 s | 1.42 GB live heap | Most of the remaining runtime |
| Native rules with type-aware lint disabled | 0.16 s | 97 MB | Not the bottleneck |

Type-aware 阶段中,web/tsconfig.json 对应的 program 包含 11,924 个源文件,占该阶段 6.99 s 中的约 6.07 s(约 87%)。

原因分析

可能原因集中在以下几层:

  • JavaScript 插件开销大且受主线程制约。Oxlint 的 JavaScript 插件仍处于 alpha 阶段,其回调在 Node.js 主线程执行,Rust lint worker 需要等待 JavaScript 侧;只要注册了任意 JavaScript 插件,Oxlint 就会为 service 处理的已解析文件启用共享 token/allocator 工作。因此文件/规则 override 可以减少回调次数,但无法在仍注册 JavaScript 插件时消除全部进程级 external-linter 开销。
  • Type-aware 检查始终构建完整 program。即使只传入一个变更的 TS/TSX 文件,tsgolint 仍会按匹配的 tsconfig 构建完整 program,只是限制最终上报的诊断范围。一次针对单个 Web TSX 文件的本地 debug 运行仍创建了含 11,938 个源文件的 web/tsconfig.json program,program 创建本身约 0.53 s。
  • compilerOptions.incremental 不是可用的优化手段。tsgolint 每次都创建新 program,不读取也不写入项目的 .tsbuildinfo
  • Oxlint 与 tsgolint 并发域独立。Oxlint 的 worker 数与 tsgolint 的 Go GOMAXPROCS 需要分别调优;当 JavaScript 插件回调在主线程串行化时,增加 Oxlint 线程未必有效,激进组合还可能加剧争用并抬高峰值 RSS。
  • 诊断输出路径本身计入用户可见耗时。Vite+ 0.2.4 的 check 命令需要选择 reporter、捕获命令输出并解析诊断信息。现有 --silent 基准只隔离了 lint 引擎,刻意省略了产生和处理数千条 warning 的成本。
  • Task 结果缓存当前未被使用。直接执行 pnpm -w check 不会获得 Vite Task 的结果缓存,setup-vp 搭配 cache: true 缓存的是包管理器数据而非任务结果。Vite Task 结果缓存只能通过 vp run 获得,且跨次 GitHub Actions 任务缓存目前仍被文档标记为实验性。

单插件移除的 wall-time delta 排序为:eslint-react -5.93 s、eslint-plugin-better-tailwindcss -5.45 s、eslint-plugin-jsdoc -3.00 s、eslint-plugin-regexp -2.77 s、@tanstack/eslint-plugin-query -0.54 s、eslint-plugin-perfectionist -0.37 s。四个高 delta 插件同时运行时复现出 19.45 s,约占 JavaScript 插件单独 wall time 的 93%。

环境排查

  • Dify 仓库中 vp check / pnpm -w check 的实际执行方式,以及是否经由 vp run
  • Vite+ 版本(Issue 基于 0.2.4)。
  • Oxlint 版本(Issue 基于 1.72.0)。
  • oxlint-tsgolint 版本(Issue 基于 0.24.0)。
  • 当前注册的 JavaScript 插件清单,重点核对 eslint-reacteslint-plugin-better-tailwindcsseslint-plugin-jsdoceslint-plugin-regexp
  • web/tsconfig.jsoninclude/exclude 与 project 边界,以及 pnpm 依赖与 workspace 包被纳入 program 的规模。
  • Oxlint worker 数与 GOMAXPROCS 设置,以及运行环境的 CPU 核数(CI 为 4 核 runner,本地 profiling 为 12 核)。
  • 是否使用 --silent,以区分引擎耗时与诊断输出耗时。
  • 若考虑引入 Vite Task 缓存,先确认 setup-vpcache 配置项与 CI 上的缓存命中率。

解决步骤

Issue 未提供单一确认的修复步骤,以下为按证据可执行、且每一项都应独立评审覆盖度取舍的排查顺序:

  1. 先固定两条测量通道:一条 engine-only 的 silent 运行,一条与本地/CI 完全一致的仓库命令,避免把诊断输出成本混入引擎对比。
  2. 按插件逐个移除并测量 wall time,优先从高 delta 的 eslint-reacteslint-plugin-better-tailwindcss 开始。注意单次 delta 只能用于排序,不可加总。
  3. 评估是否接受移除 eslint-plugin-better-tailwindcss 带来的覆盖度下降。Issue 实测完整配置下中位 wall time 28.30 s → 22.75 s,中位 user CPU 61.34 s → 54.65 s,注册规则 401 → 399,可见 warning 2,599 → 2,439。
  4. 针对 type-aware 阶段,从 tsconfig 的 include/exclude、project 边界和依赖面入手。拆分 project 必须做端到端基准测试,因为多个 program 可能重复解析依赖。不要尝试依赖 compilerOptions.incremental
  5. 分别调整 Oxlint worker 数与 tsgolint 的 GOMAXPROCS,并在 4 核 CI runner 上重新跑线程矩阵,不要用 12 核本地结果外推。
  6. 若评估 Vite Task 缓存,先确认第二次本地 vp run check --cache 是真正的缓存命中,再测量 CI 上的缓存传输时间与命中率;跨次 GitHub Actions 任务缓存仍属实验性,改动 CI 前需谨慎。

验证方法

以相同入口、相同仓库配置重复运行,比较中位 wall time 与中位 user CPU,并同时记录注册规则数与可见 warning 数,确认性能收益没有以不可接受的 lint 覆盖度下降为代价。内存指标需关注多次运行的区间是否重叠,区间重叠时不应当作改善结论。线程与缓存相关改动必须在 4 核 CI runner 上复测后才能确认。

参考来源

langgenius/dify #38865

Issue 中引用的上游资料:Oxlint JavaScript plugin guidetype-aware linting guideVite+ task cacheVite+ CI guide

GamsGo AI

AI 工具推荐

想把多个 AI 模型放在一个入口?

GamsGo AI 集成 ChatGPT、DeepSeek、Gemini、Claude、Midjourney、Veo 等常用模型,适合写作、绘图、视频和日常 AI 工作流。

了解 GamsGo AI

推广链接:通过此链接购买,我可能获得佣金,不影响你的价格。

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 24906

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注