Skip to content

Commit c5dc6d2

Browse files
committed
Migrate from ESLint to Oxlint
Reduces the number of dependencies for JavaScript linting from 5 to 1 with drop-in compatibility. Includes an ADR with further context.
1 parent 9ad20a5 commit c5dc6d2

13 files changed

Lines changed: 626 additions & 1339 deletions

File tree

.oxlintrc.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"$schema": "./node_modules/oxlint/configuration_schema.json",
3+
"plugins": ["unicorn", "oxc", "vitest"],
4+
"categories": {
5+
"correctness": "error"
6+
},
7+
"rules": {},
8+
"env": {
9+
"builtin": true
10+
},
11+
"ignorePatterns": ["docs/", "vendor/", "demo/", "website/"]
12+
}

contributing/03-testing.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,18 +32,18 @@ just format
3232

3333
You can check the formatting without making changes with `just format-check`
3434

35-
### Prettier, Stylelint, ESLint, and Jest
35+
### Prettier, Stylelint, Oxlint, and Jest
3636

37-
The repository is centred around a node module which is managed by the `package.json` at the top-level of the repository. This provides commands for running prettier against the project as well as linting (eslint) and unit tests (jest) for client-side code.
37+
The repository is centred around a node module which is managed by the `package.json` at the top-level of the repository. This provides commands for running prettier against the project as well as linting (oxlint) and unit tests (jest) for client-side code.
3838

3939
All top-level package commands can be run using `npm run`:
4040

4141
| Command | Description |
4242
| ------------- | ----------------------------------------------------- |
4343
| `test` | Runs all jest tests |
44-
| `lint` | Runs all linting checks (prettier, eslint, stylelint) |
44+
| `lint` | Runs all linting checks (prettier, oxlint, stylelint) |
4545
| `lint:css` | Runs only `stylelint` on the project code |
46-
| `lint:js` | Runs only `eslint` on the project code |
46+
| `lint:js` | Runs only `oxlint` on the project code |
4747
| `lint:format` | Run `prettier --check` on the project code |
4848
| `format` | Auto-format all eligible code with prettier |
4949

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Migrate from ESLint to Oxlint
2+
3+
Date: 2026-08-03
4+
5+
## Status
6+
7+
Accepted
8+
9+
## Context
10+
11+
In a previous ADR we made the decision to [move from jest to vitest](./2025-06-17-migrate-to-vitest-for-unit-tests.md). There is a similar replacement for eslint in the wider vite-ecosystem in [Oxlint](https://oxc.rs/docs/guide/usage/linter).
12+
13+
Oxlint by comparison is a single binary with a number of common eslint rules implemented as core plugins.
14+
15+
## Decision
16+
17+
Migrate to Oxlint for JavaScript linting. This is largely a drop-in replacement.
18+
19+
## Consequences
20+
21+
Reduces the number of dependencies for JavaScript linting from 5 to 1. For larger projects the performance benefits would also be significant, here they are marginal (although still significantly faster in relative terms), so the primary reason here is reducing the number of dependencies.
22+
23+
Due to the small number of files being checked in this project it's possible to quickly swap out linting tools so we can easily reverse this migration if we choose to.
24+
25+
There is also a companion `oxfmt` tool which is a drop-in replacement for `prettier`, however it is still in alpha and doesn't fundamentally change the number of dependencies.

demo/package-lock.json

Lines changed: 1 addition & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

demo/visual-regression/engine_scripts/onReady.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
/* eslint-disable no-await-in-loop */
2-
/* eslint-disable no-restricted-syntax */
1+
/* oxlint-disable no-await-in-loop, no-restricted-syntax */
32
module.exports = async (page, scenario) => {
43
// Enable prefers-reduced-motion to disable animations
54
await page.emulateMediaFeatures([

eslint.config.mjs

Lines changed: 0 additions & 34 deletions
This file was deleted.

lib/targeted-content/__snapshots__/targeted-content.test.js.snap

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
22

3-
exports[`allow toggling targeted content 1`] = `
3+
exports[`allow toggling targeted content > closed 1`] = `
44
"<button type="button" class="cads-targeted-content__button" aria-expanded="false" aria-controls="targeted-content-123-content" aria-label="show this section">
55
66
<div class="cads-targeted-content__title-text">Targeted content title</div>
@@ -11,7 +11,7 @@ exports[`allow toggling targeted content 1`] = `
1111
</button>"
1212
`;
1313

14-
exports[`allow toggling targeted content 2`] = `
14+
exports[`allow toggling targeted content > open 1`] = `
1515
"<button type="button" class="cads-targeted-content__button" aria-expanded="true" aria-controls="targeted-content-123-content" aria-label="close this section">
1616
1717
<div class="cads-targeted-content__title-text">Targeted content title</div>

lib/targeted-content/targeted-content.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ function openByHash(hash) {
5757
setState(matchEl, "open");
5858
}
5959
}
60-
} catch (e) {} // eslint-disable-line no-empty
60+
} catch (e) {} // oxlint-disable-line no-unused-vars
6161
}
6262

6363
function initTargetedContentFor(el) {

lib/targeted-content/targeted-content.test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,11 @@ test("allow toggling targeted content", () => {
4242
expect(buttonEl).toHaveAttribute("aria-expanded", "false");
4343
}
4444

45-
expect(headingEl.innerHTML).toMatchSnapshot();
45+
expect(headingEl.innerHTML).toMatchSnapshot("closed");
4646
expectClosed();
4747

4848
buttonEl.click();
49-
expect(headingEl.innerHTML).toMatchSnapshot();
49+
expect(headingEl.innerHTML).toMatchSnapshot("open");
5050
expectOpen();
5151

5252
buttonEl.click();

0 commit comments

Comments
 (0)