chore: migrate repo runtime linting from ESLint to oxlint#6928
chore: migrate repo runtime linting from ESLint to oxlint#6928aymeric-giraudet merged 5 commits intomasterfrom
Conversation
|
This pull request is automatically built and testable in CodeSandbox. To see build info of the built libraries, click here or the icon next to each commit SHA. Latest deployment of this branch, based on commit b500d8c:
|
|
does oxlint have a similar import order feature, even if the order is slightly different? could be nice to be able to drop eslint completely |
|
@Haroenv |
Haroenv
left a comment
There was a problem hiding this comment.
🔥 this looks very good! Are there any rules other than import formatting and the ones that are converted to a custom file that aren't compatible yet?
|
On the compatibility question: aside from import ordering and the repo-specific restrictions I moved into the local plugin, the remaining intentional drops are mostly legacy or style-only rules. Concretely, that is things like |
There was a problem hiding this comment.
Pull request overview
This PR migrates the repository linting workflow from ESLint to Oxlint, introducing a shared .oxlintrc.json, custom Oxlint rules, and new scripts to run lint across the monorepo and selected file sets.
Changes:
- Replace the root
eslint-based lint scripts withscripts/lint/run-oxlint.cjsandscripts/lint/run-lint.cjs, and add Oxlint as optional dependencies. - Add a root
.oxlintrc.jsonplus package-/folder-level.oxlintrc.jsonoverrides, and introduce a custominstantsearchOxlint plugin. - Update many files to comply with the new lint rules (type-only imports,
voidon floating promises, rule-name updates in eslint-disable comments, etc.), and update Node version references.
Reviewed changes
Copilot reviewed 76 out of 78 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| yarn.lock | Locks new dependencies (notably Oxlint binaries/bindings). |
| tests/utils/matchers/vue.ts | Updates lint-disable directives for global Jest namespace augmentation. |
| tests/utils/matchers/toWarnDev.ts | Updates lint-disable directives for Jest matcher augmentation. |
| tests/utils/matchers/toMatchNormalizedInlineSnapshot.ts | Updates lint-disable directives for Jest matcher augmentation. |
| tests/e2e/playwright/fixtures.ts | Adjusts Playwright imports to use type import. |
| tests/common/.oxlintrc.json | Adds test-level Oxlint overrides for Jest helpers. |
| specs/src/layouts/WidgetLayout.astro | Reorders imports to satisfy import ordering. |
| specs/src/components/WidgetContent.astro | Reorders imports to satisfy import ordering. |
| scripts/lint/run-oxlint.cjs | Adds a CLI wrapper around Oxlint with changed/staged selection and workspace partitioning. |
| scripts/lint/run-lint.cjs | Adds a higher-level lint runner orchestrating root + selected workspaces. |
| scripts/lint/instantsearch-oxlint-plugin.mjs | Adds a custom Oxlint plugin (repo-specific rules). |
| scripts/.oxlintrc.json | Adds script-folder Oxlint overrides (CommonJS + console allowed). |
| scripts/.eslintrc.js | Removes legacy ESLint config for scripts. |
| packages/vue-instantsearch/src/tests/common-widgets.test.js | Updates eslint-disable rule name for unused vars. |
| packages/vue-instantsearch/.storybook/config.js | Reorders imports (and keeps Storybook setup intact). |
| packages/vue-instantsearch/.oxlintrc.json | Adds Vue InstantSearch package-specific Oxlint overrides. |
| packages/vue-instantsearch/.eslintrc.js | Removes legacy ESLint config for the package. |
| packages/react-instantsearch/src/widgets/Autocomplete.tsx | Expands search-parameter typing to include hitsPerPage?. |
| packages/react-instantsearch/src/ui/tests/InfiniteHits.test.tsx | Removes TypeScript non-null assertion in a querySelectorAll access. |
| packages/react-instantsearch-router-nextjs/src/index.ts | Marks router push promise as intentionally ignored (void). |
| packages/react-instantsearch-core/src/lib/dequal.ts | Updates lint-disable directives and restricted-syntax suppression for for..in. |
| packages/instantsearch.js/test/module/is-es-module.mjs | Reorders imports to satisfy lint rules. |
| packages/instantsearch.js/test/module/is-cjs-module.cjs | Reorders requires to satisfy lint rules. |
| packages/instantsearch.js/src/widgets/hits/defaultTemplates.ts | Updates lint-disable directive for type-only imports. |
| packages/instantsearch.js/src/widgets/autocomplete/autocomplete.tsx | Hardens getInputProps() spreading and simplifies event typing usage. |
| packages/instantsearch.js/src/widgets/analytics/analytics.ts | Updates restricted-syntax suppression to custom instantsearch/no-for-in. |
| packages/instantsearch.js/src/middlewares/createInsightsMiddleware.ts | Renames naming-convention disable to custom instantsearch/naming-convention. |
| packages/instantsearch.js/src/middlewares/tests/createMetadataMiddleware.ts | Removes TypeScript non-null assertions around global.navigator. |
| packages/instantsearch.js/src/middlewares/tests/createInsightsMiddleware.ts | Updates lint-disable directive for NodeJS namespace augmentation. |
| packages/instantsearch.js/src/lib/utils/logger.ts | Updates eslint-disable rule name for unused vars. |
| packages/instantsearch.js/src/lib/utils/isEqual.ts | Updates restricted-syntax suppression to custom instantsearch/no-for-of. |
| packages/instantsearch.js/src/lib/utils/checkIndexUiState.ts | Removes TypeScript non-null assertions in widget name formatting. |
| packages/instantsearch.js/src/lib/utils/tests/hydrateSearchClient-composition-test.ts | Marks returned promises as intentionally ignored (void). |
| packages/instantsearch.js/src/lib/utils/tests/debounce-test.ts | Marks returned promises as intentionally ignored (void). |
| packages/instantsearch.js/src/lib/routers/history.ts | Avoids window identifier in callback destructuring to comply with restrictions. |
| packages/instantsearch.js/src/lib/ai-lite/types.ts | Switches naming-convention disable to custom instantsearch/naming-convention. |
| packages/instantsearch.js/src/lib/tests/server.test.ts | Replaces non-null assertions with explicit runtime checks. |
| packages/instantsearch.js/src/connectors/numeric-menu/connectNumericMenu.ts | Updates restricted-syntax suppression and slightly refactors refinement lookup. |
| packages/instantsearch.js/src/connectors/infinite-hits/connectInfiniteHitsWithInsights.ts | Updates eslint-disable rule name for unused vars. |
| packages/instantsearch.js/src/connectors/hits/connectHitsWithInsights.ts | Updates eslint-disable rule name for unused vars. |
| packages/instantsearch.js/.storybook/playgrounds/movies.ts | Converts value import to type import. |
| packages/instantsearch.js/.storybook/playgrounds/default.ts | Converts value imports to type imports. |
| packages/instantsearch.js/.storybook/decorators/withLifecycle.ts | Converts value imports to type imports. |
| packages/instantsearch.js/.storybook/decorators/withHits.ts | Splits and converts certain imports to type imports. |
| packages/instantsearch-ui-components/src/types/Renderer.ts | Updates namespace lint-disable directive for JSX namespace setup. |
| packages/instantsearch-ui-components/src/components/chat/ChatMessages.tsx | Marks clipboard promise as intentionally ignored (void). |
| packages/instantsearch-ui-components/src/components/tests/TrendingItems.test.tsx | Removes TypeScript non-null assertion in a querySelectorAll access. |
| packages/instantsearch-ui-components/src/components/tests/RelatedProducts.test.tsx | Removes TypeScript non-null assertion in a querySelectorAll access. |
| packages/instantsearch-ui-components/src/components/tests/LookingSimilar.test.tsx | Removes TypeScript non-null assertion in a querySelectorAll access. |
| packages/instantsearch-ui-components/src/components/tests/Hits.test.tsx | Removes TypeScript non-null assertion in a querySelectorAll access. |
| packages/instantsearch-ui-components/src/components/tests/FrequentlyBoughtTogether.test.tsx | Removes TypeScript non-null assertion in a querySelectorAll access. |
| packages/instantsearch-ui-components/.oxlintrc.json | Adds package-specific Oxlint overrides (notably no-unused-vars tuning). |
| packages/create-instantsearch-app/.oxlintrc.json | Adds package-specific Oxlint overrides (CommonJS + console allowed). |
| packages/algoliasearch-helper/src/functions/merge.js | Updates restricted-syntax suppression to custom instantsearch/no-for-in. |
| packages/algoliasearch-helper/package.json | Switches package lint script from ESLint to Oxlint. |
| packages/algoliasearch-helper/index.d.ts | Updates lint-disable directive for type-only import rule. |
| packages/algoliasearch-helper/.oxlintrc.json | Adds helper-specific Oxlint overrides (ES5/CommonJS allowances). |
| package.json | Replaces root lint scripts, removes some ESLint deps, adds Oxlint optional dependencies. |
| examples/vue/.oxlintrc.json | Adds Vue example-specific Oxlint overrides. |
| examples/vue/.eslintrc.js | Removes legacy ESLint config for Vue examples. |
| examples/react/ssr/.oxlintrc.json | Adds SSR example-specific Oxlint overrides. |
| examples/react/ssr/.eslintrc.js | Removes legacy ESLint config for SSR example. |
| examples/react/next/package.json | Switches example lint script from ESLint to Oxlint. |
| examples/react/next/.oxlintrc.json | Adds Next example ignore patterns. |
| examples/react/next-routing/package.json | Switches example lint script from ESLint to Oxlint. |
| examples/react/next-routing/.oxlintrc.json | Adds Next example ignore patterns. |
| examples/react/next-app-router/package.json | Switches example lint script from ESLint to Oxlint. |
| examples/react/next-app-router/.oxlintrc.json | Adds Next example ignore patterns. |
| examples/js/query-suggestions/package.json | Switches example lint script from ESLint to Oxlint. |
| examples/js/getting-started/package.json | Switches example lint script from ESLint to Oxlint. |
| examples/.oxlintrc.json | Adds shared example-level Oxlint config + ignore patterns. |
| examples/.eslintrc.js | Removes legacy ESLint config for examples. |
| CONTRIBUTING.md | Updates contributor docs to describe the new lint workflow and commands. |
| .oxlintrc.json | Adds the root Oxlint configuration (rules, plugins, overrides, custom plugin). |
| .nvmrc | Updates Node version (20.10.0 → 20.19.0). |
| .eslintrc.js | Removes legacy root ESLint config. |
| .eslintignore | Updates ignore list (and preserves legacy ESLint ignores for reference/migration). |
| .circleci/config.yml | Updates CI Node image version (20.10.0 → 20.19.0). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
|
|
||
| const result = spawnSync(oxlintBin, commandArgs, { | ||
| cwd, | ||
| stdio: 'inherit', | ||
| }); | ||
|
|
||
| return result.status || 0; | ||
| } |
Summary
This migrates the repo runtime lint flow from ESLint to Oxlint.
The new setup keeps high-signal parity with our existing lint behavior, preserves our repo-specific restrictions through a local Oxlint plugin, and adds faster partial lint workflows for local development.
What changed
.oxlintrc.jsonconfigs for the repo and relevant nested workspacesyarn lintyarn lint:ox <paths...>yarn lint:changedyarn lint:stagedyarn lint:bench.eslintrc.jsfilesNotes
oxfmteslintandeslint-plugin-importremain installed only because Oxlint still uses the JS-plugin fallback forimport/orderoxlintandoxlint-tsgolintare optional dependencies so environments that do not run lint do not fail on the Node engine requirement20.19.0in local/CI tooling, while CodeSandbox keeps the valid major selector20Validation
Validated locally on March 16, 2026 with:
yarn build:ciyarn lintyarn type-checkCircleCI uses the same relevant gates, so this is aligned with CI behavior.
Benchmark
Recorded ESLint baseline from March 16, 2026:
yarn lint:110.85sOxlint results from
yarn lint:bench:9.19s9.03s8.94sThat is a
91.7%improvement over the recorded ESLint baseline.Additional partial-run timings:
yarn lint:changed: mean0.05son the current branch stateyarn lint:ox packages/instantsearch.js: mean1.74s