From dc3865f77872ad3ece20717890b0b74d0d75b94a Mon Sep 17 00:00:00 2001 From: xingyu4j Date: Thu, 18 Jun 2026 16:35:27 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BC=98=E5=8C=96=20lint=20=E6=89=A7?= =?UTF-8?q?=E8=A1=8C=E7=AD=96=E7=95=A5=E5=B9=B6=E4=BF=AE=E5=A4=8D=20pre-co?= =?UTF-8?q?mmit=20=E4=BE=9D=E8=B5=96=E8=A7=A3=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - vsh lint 按硬件自适应:CPU<=4 核串行(汇总错误),>4 核并行; CPU>4 且空闲内存>8GB 时 oxfmt/oxlint 默认线程数提升至 4,否则维持 2 - lefthook pre-commit 改为串行执行,避免与 check:type 并行导致低配机资源飙升 - pre-commit 仅对暂存文件 lint 并自动修复回填(stage_fixed) - lint 命令统一加 pnpm exec 前缀,修复 lefthook 经 sh 调用时 oxlint 找不到 workspace 局部依赖(eslint-plugin-eslint-comments)的问题 --- lefthook.yml | 25 ++++++-- scripts/vsh/src/lint/index.ts | 107 ++++++++++++++++++++++++++-------- 2 files changed, 102 insertions(+), 30 deletions(-) diff --git a/lefthook.yml b/lefthook.yml index d1b08d763..14b582205 100644 --- a/lefthook.yml +++ b/lefthook.yml @@ -42,11 +42,26 @@ # runner: go run pre-commit: - parallel: true - commands: - lint: - run: pnpm lint - checkType: + # 串行执行(不设 parallel),避免与 check:type 同时运行导致低配机内存/CPU 瞬时飙升。 + # lint 仅检查暂存文件并自动修复后回填,大幅降低负载;check:type 仍需全量。 + jobs: + - name: oxlint + glob: '*.{js,jsx,ts,tsx,vue,cjs,mjs,cts,mts}' + run: pnpm exec oxlint --fix --type-aware --threads=4 --no-error-on-unmatched-pattern {staged_files} + stage_fixed: true + - name: oxfmt + glob: '*.{js,jsx,ts,tsx,vue,cjs,mjs,cts,mts,json,jsonc}' + run: pnpm exec oxfmt --threads=4 --no-error-on-unmatched-pattern {staged_files} + stage_fixed: true + - name: eslint + glob: '*.{js,jsx,ts,tsx,vue,cjs,mjs,cts,mts}' + run: pnpm exec eslint --fix {staged_files} + stage_fixed: true + - name: stylelint + glob: '*.{vue,css,less,scss}' + run: pnpm exec stylelint --fix {staged_files} + stage_fixed: true + - name: checkType run: pnpm check:type post-merge: diff --git a/scripts/vsh/src/lint/index.ts b/scripts/vsh/src/lint/index.ts index 5c927ac6c..fddb1a584 100644 --- a/scripts/vsh/src/lint/index.ts +++ b/scripts/vsh/src/lint/index.ts @@ -1,6 +1,7 @@ import type { CAC } from 'cac'; import { execSync } from 'node:child_process'; +import { availableParallelism, freemem } from 'node:os'; import { execaCommand } from '@vben/node-utils'; @@ -15,33 +16,49 @@ interface LintCommandOptions { threads?: number; } -async function runLint({ format, threads }: LintCommandOptions) { - // process.env.FORCE_COLOR = '3'; - const threadsArg = threads ? ` --threads=${threads}` : ` --threads=2`; +/** + * CPU 逻辑核心数阈值 4 核。 + * - 小于等于该值:视为低配机器,检查命令串行执行,避免瞬时占用飙升。 + */ +const CPU_CORE_THRESHOLD = 4; - if (format) { - await execaCommand(`stylelint "**/*.{vue,css,less,scss}" --cache --fix`, { - stdio: 'inherit', - }); - await execaCommand(`oxfmt${threadsArg}`, { - stdio: 'inherit', - }); - await execaCommand(`oxlint --fix --type-aware${threadsArg}`, { - stdio: 'inherit', - }); - await execaCommand(`eslint . --cache --fix`, { - stdio: 'inherit', - }); - return; +/** + * 可用内存阈值 8 GB。 + * 仅当空余内存大于阈值且当前可用内存大于该值时, + * oxfmt / oxlint 默认线程数才提升到 4,否则使用 2。 + */ +const FREE_MEMORY_THRESHOLD = 8 * 1024 ** 3; + +/** + * 串行执行所有命令:一次只运行一个进程。 + * 保证一次能看到所有工具的报错(配置低的机器更友好)。 + */ +async function runSerial(commands: string[]) { + const failed: string[] = []; + + for (const command of commands) { + try { + await execaCommand(command, { stdio: 'inherit' }); + } catch { + failed.push(command); + } } - const subprocesses = [ - execaCommand(`oxfmt --check${threadsArg}`, { stdio: 'inherit' }), - execaCommand(`oxlint --type-aware${threadsArg}`, { stdio: 'inherit' }), - execaCommand(`eslint . --cache`, { stdio: 'inherit' }), - execaCommand(`stylelint "**/*.{vue,css,less,scss}" --cache`, { - stdio: 'inherit', - }), - ]; + + if (failed.length > 0) { + throw new Error( + `Lint failed:\n${failed.map((command) => ` - ${command}`).join('\n')}`, + ); + } +} + +/** + * 并行执行所有命令:同时启动全部进程。 + * 任一进程失败时,强制结束其余仍在运行的进程,避免产生遗漏进程。 + */ +async function runParallel(commands: string[]) { + const subprocesses = commands.map((command) => + execaCommand(command, { stdio: 'inherit' }), + ); try { await Promise.all(subprocesses); @@ -64,6 +81,46 @@ async function runLint({ format, threads }: LintCommandOptions) { } } +async function runLint({ format, threads }: LintCommandOptions) { + // process.env.FORCE_COLOR = '3'; + const cpuCores = availableParallelism(); + + // CPU 核心数充足且可用内存充足时,默认线程数提升到 4,否则维持 2; + // 用户通过 --threads 显式指定时优先使用其值。 + const defaultThreads = + cpuCores > CPU_CORE_THRESHOLD && freemem() > FREE_MEMORY_THRESHOLD ? 4 : 2; + const threadsArg = ` --threads=${threads || defaultThreads}`; + + if (format) { + await execaCommand(`stylelint "**/*.{vue,css,less,scss}" --cache --fix`, { + stdio: 'inherit', + }); + await execaCommand(`oxfmt${threadsArg}`, { + stdio: 'inherit', + }); + await execaCommand(`oxlint --fix --type-aware${threadsArg}`, { + stdio: 'inherit', + }); + await execaCommand(`eslint . --cache --fix`, { + stdio: 'inherit', + }); + return; + } + + const commands = [ + `oxfmt --check${threadsArg}`, + `oxlint --type-aware${threadsArg}`, + `eslint . --cache`, + `stylelint "**/*.{vue,css,less,scss}" --cache`, + ]; + + // 低配机器(CPU 核心数较少)串行执行,避免多进程并发导致瞬时占用飙升; + // 高配机器并行执行以缩短整体耗时。 + await (cpuCores <= CPU_CORE_THRESHOLD + ? runSerial(commands) + : runParallel(commands)); +} + function defineLintCommand(cac: CAC) { cac .command('lint')