Repository navigation
Description
Problem
pnpm lint and pnpm check-types are slow. The src package causes most of the wait in both.
The pre-commit hook runs pnpm lint on the whole repo. The pre-push hook runs pnpm check-types.
Measurements
All runs are warm, with the turbo cache bypassed (--force). Machine: WSL2, 20 cores.
Lint
| Package | Time |
|---|---|
src |
26.1 s |
webview-ui |
6.3 s |
vscode-e2e |
3.1 s |
cli |
2.1 s |
types |
1.8 s |
| other 6 packages | 0.8 s to 1.4 s each |
pnpm lint --force (all, turbo) |
28.1 s |
Turbo runs the packages in parallel. The total is about 2 s more than src alone.
TIMING=15 on src:
| Rule | Time | Share of rule time |
|---|---|---|
@typescript-eslint/no-floating-promises |
7.2 s | 73% |
@typescript-eslint/no-unused-vars |
1.3 s | 13% |
| each other rule | 0.2 s or less | under 2% |
no-floating-promises is the only type-aware rule. It needs a TypeScript program (parserOptions.project: true in src/eslint.config.mjs).
Check types
| Package | Time |
|---|---|
src |
19.0 s |
webview-ui |
15.1 s |
cli |
5.4 s |
| other 8 packages | 0.7 s to 4.8 s each |
pnpm check-types --force (all, turbo) |
25.9 s |
tsc --noEmit --extendedDiagnostics on src:
- 3,428 files. 1.7 GB of memory.
- Check time is 16.4 s of 20.3 s total. Parse time is 1.7 s. Bind time is 0.9 s.
skipLibCheckis already on. File loading is not the cost.
Experiments
Run on src with CLI flags and a scratch cache. No repo files changed.
TypeScript incremental mode
Command: tsc --noEmit --incremental --tsBuildInfoFile <path>.
Today packages/config-typescript/base.json sets "incremental": false, and src/tsconfig.json does not extend it.
| Run | Time |
|---|---|
| Cold (no build info) | 18.9 s to 19.6 s |
| Warm, no change | 3.2 s to 3.4 s |
| Comment edit in a leaf test file | 3.3 s |
Comment edit in utils/path.ts (41 direct importers) |
19.7 s to 20.6 s |
Without the declaration option, tsc cannot tell if a change affects other files. Any edit invalidates every file that depends on the edited file.
So incremental mode helps for edits to leaf files. It does not help for edits to shared files.
tsc --noEmit --incremental --declaration exits with TS errors in src. Do not use it until we fix them.
ESLint cache
Command: eslint . --ext=ts --max-warnings=0 --cache --cache-strategy content --cache-location <path>.
| Run | Time |
|---|---|
| Cold (no cache) | 26.4 s |
| Warm, no change | 1.3 s |
| After a comment edit in one file | 1.3 s |
The edited file was outside the typed-lint globs. An edit to a file inside those globs may cost more. We did not test that.
Proposed changes
- Add
--cache --cache-strategy contentto thelintscripts insrcandwebview-ui. Put the cache undernode_modules/.cache/so git ignores it. - Add
"incremental": trueand atsBuildInfoFileundernode_modules/.cache/tosrc/tsconfig.jsonandwebview-ui/tsconfig.json. - Change the pre-commit hook to lint only staged files through
lint-staged. Keep the full lint in CI. - Check that
webview-uicheck-typesneeds to emit. Its script istscwithout--noEmit.
Not yet measured
- Cold-start time on CI or on other machines.
webview-uiwith the proposed changes.- ESLint after an edit to a file inside the typed-lint globs.
parserOptions.projectServiceagainstproject: true. The typescript-eslint performance repo reports thatprojectServiceno longer beatsproject.- A claim that
--prune-suppressionsslows ESLint. We found no evidence for it.
Sources
- typescript-eslint: Typed linting performance
- typescript-eslint/performance repo
- typescript-eslint: Typed linting
- ESLint v9 CLI reference (
--cache,--cache-strategy,--cache-location) - ESLint v9 stats docs
- OpenReplay: Slow ESLint rules (
TIMING)
🤖 Generated with Claude Code
Activity