chore(lint): lint per package to avoid the typescript-eslint project-service ceiling - #3317
Open
kriskowal wants to merge 1 commit into
Open
chore(lint): lint per package to avoid the typescript-eslint project-service ceiling#3317kriskowal wants to merge 1 commit into
kriskowal wants to merge 1 commit into
Conversation
🦋 Changeset detectedLatest commit: a0dee9b The changes in this PR will be included in the next version bump. This PR includes changesets to release 0 packagesWhen changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
…ript-eslint project-service ceiling `yarn lint:eslint` no longer runs a single `eslint .` over the whole repo. A single run builds one typescript-eslint project service that must hold every package's TypeScript program at once; past a scale this monorepo crosses on large PRs, that service drops its alphabetically-last packages (`packages/where`, `packages/zip`), reporting every file as "none of those TSConfigs include this file" even though each package lints clean on its own. `yarn lint:eslint` now delegates to `scripts/eslint-repo.mjs`, which lints packages in bounded buckets (`ESLINT_BUCKET_SIZE`, default 10) in a fresh child process each, plus one batch for the repository-root files. Each project service then holds only a bucket's worth of programs, far under the whole-repo count that dropped its tail, while a handful of processes amortize ESLint startup. Coverage and rules are unchanged; only the grouping into processes differs. Ferried from endojs/endo-but-for-bots#594.
kriskowal
force-pushed
the
chore/lint-eslint-per-package-batches
branch
from
July 2, 2026 15:08
6268f88 to
a0dee9b
Compare
68 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
On large PRs, the root
yarn lint:eslint(eslint .) fails with parsing errors on the alphabetically-last packagespackages/where/**andpackages/zip/**:Each package's
tsconfig.jsonplainlyincludes those files (where/ziplint clean when linted on their own), and the base branch lints green, so this is not a config-glob gap or a per-PR code defect. It is a typescript-eslint project-service scaling ceiling: a singleeslint .builds one project service that must hold every package's TypeScript program at once, and past a size this monorepo crosses on large PRs the service drops its tail. Two independent large PRs hit the identicalwhere/ziptail-drop with entirely different diffs and neither touches those packages, i.e. size-driven, not diff-driven.Fix
yarn lint:eslintnow delegates toscripts/eslint-repo.mjs, which lintspackages/*in bounded buckets ofESLINT_BUCKET_SIZEpackages per process (default 10) plus one batch per top-level non-package directory. Each bucket's project service holds only a handful of package programs, far under the whole-repo count that dropped its tail, so the ceiling can never be reached regardless of repository size, while a handful of processes (rather than one per package) amortize ESLint startup. Each bucket is a fresheslintchild process, which the isolation depends on: typescript-eslint's TypeScript program cache is module-global, so linting the buckets in one process would re-accumulate every package's program and re-cross the ceiling.Coverage matches
eslint .: the union of the buckets' directory arguments is exactlypackages/*plus every top-level non-package directory, the same pathseslint .walks. Extra args are forwarded, soscripts/eslint-repo.mjs --fixfixes the whole repo.ESLINT_BUCKET_SIZE(default 10) tunes packages-per-process.Verification
Ran
node scripts/eslint-repo.mjson this branch (against current master): completes green, 0 errors (only the pre-existingcompartment-mapper/src/types/policy-schema.tsjsdoc/check-tag-nameswarning), coveringpackages/*includingwhere/zip.