Skip to content

Switch to TypeScript 7 (tsgo) and replace ESLint with oxlint - #6354

Draft
mstange wants to merge 1 commit into
firefox-devtools:mainfrom
mstange:push-yrnpkqqwltur
Draft

mstange wants to merge 1 commit into
firefox-devtools:mainfrom
mstange:push-yrnpkqqwltur

Conversation

@mstange

@mstange mstange commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

Main | Deploy preview

TypeScript 7 has a faster compiler but eslint isn't compatible with it. But we can switch to oxlint instead; oxlint has many of the lints we use built-in, and for the rest (testing-library, jest-dom) it has a jsPlugin adapter.

Timings on my machine, from a cold cache:

    yarn ts        4.83s -> 1.04s
    yarn lint-js  11.00s -> 1.93s
    yarn lint     14.03s -> 2.98s

Two notes:

  • react/no-did-mount-set-state and react/no-did-update-set-state were already dead. eslint-plugin-react turns them into no-ops for any React >= 16.3, and this project declares 18.0. They stay off.
  • ESLint's no-return-await is deprecated and has no oxlint equivalent. typescript/return-await replaces it in error-handling-correctness-only mode, which reports only where adding or removing await changes which errors a try/catch sees. That is a narrower rule, and it is what found the bug fixed in Add missing await when calling Chrome importer #6346.

The eslint-disable comments for rules loaded through jsPlugins are renamed to the oxlint names.

jsPlugins is documented as alpha and not covered by semver, so an oxlint upgrade may require revisiting this file.

TypeScript 7 is the native Go port of the compiler. It ships only the
`tsc` binary: the JavaScript compiler API is gone until 7.1, and
typescript-eslint refuses to load against it. That makes the two halves
of this change a single step rather than two.

Timings on this machine, from a cold cache:

    yarn ts        4.83s -> 1.04s
    yarn lint-js  11.00s -> 1.93s
    yarn lint     14.03s -> 2.98s

Only oxlint runs. `.oxlintrc.json` is derived from the effective
configuration of the eslint.config.mjs it replaces, so the enforced rule
set is the same one ESLint applied. Where oxlint has no native rule, the
original ESLint plugin is loaded in-process through `jsPlugins`, which is
still a single pass over the tree with a single config file:

    eslint-plugin-testing-library     20 rules
    eslint-plugin-jest-dom            11 rules
    eslint-plugin-react                7 rules, aliased to `react-js` so
                                       it sits beside oxlint's native
                                       `react` plugin
    eslint-plugin-jest-formatting      padding-around-describe-blocks

`eslint` comes back as a devDependency because those plugins import it —
eslint-plugin-react reads its package.json for a version check, and
eslint-plugin-testing-library pulls it in via @typescript-eslint/utils.
Nothing invokes the ESLint CLI and there is no ESLint config.

Two rules are deliberately not restored, because TypeScript already
reports what they caught: @babel/no-invalid-this as TS2683 under `strict`,
and import/no-unresolved as TS2307.

Checked by running both linters over a corpus of 57 single-defect files,
one per rule. Every rule ESLint caught is still caught, and oxlint
reports no false positives.

Two behavioural notes:

  - react/no-did-mount-set-state and react/no-did-update-set-state were
    already dead. eslint-plugin-react turns them into no-ops for any
    React >= 16.3, and this project declares 18.0. They stay off.
  - ESLint's no-return-await is deprecated and has no oxlint equivalent.
    typescript/return-await replaces it in
    `error-handling-correctness-only` mode, which reports only where
    adding or removing `await` changes which errors a try/catch sees.
    That is a narrower rule, and it is what found the bug fixed two
    commits earlier.

The eslint-disable comments for rules loaded through jsPlugins are
renamed to the names oxlint reports them by.

jsPlugins is documented as alpha and not covered by semver, so an oxlint
upgrade may require revisiting this file. If it ever breaks, dropping the
jsPlugins block and the rules it provides leaves a working native-only
configuration.
@codecov

codecov Bot commented Sep 23, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 84.11%. Comparing base (1132ef9) to head (6dffec8).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #6354   +/-   ##
=======================================
  Coverage   84.11%   84.11%           
=======================================
  Files         356      356           
  Lines       38444    38444           
  Branches    10887    10901   +14     
=======================================
  Hits        32339    32339           
  Misses       5676     5676           
  Partials      429      429           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant