Skip to content

build: replace ESLint and Prettier with Biome - #70

Open
AliceR wants to merge 2 commits into
chore/migrate-pnpmfrom
chore/migrate-biome
Open

AliceR wants to merge 2 commits into
chore/migrate-pnpmfrom
chore/migrate-biome

Conversation

@AliceR

@AliceR AliceR commented Oct 1, 2026

Copy link
Copy Markdown
Member

Stacked on #69 (pnpm), which is stacked on #68 (dependency updates). Merge those first.

Replaces ESLint, Prettier and 8 plugin and config packages with Biome 2.5.14. ESLint 9 is now marked deprecated on npm, and eslint-plugin-react blocks ESLint 10, so staying on ESLint wasn't a good option.

Formatting

biome.jsonc mirrors .prettierrc (single quotes, ES5 trailing commas, semicolons, 100 cols, 2 spaces). biome format produces zero changes on the existing code.

Linting

Biome's recommended preset (roughly eslint:recommended + typescript-eslint recommended), plus the previous custom rules:

ESLint Biome
no-console suspicious/noConsole
react-hooks/rules-of-hooks correctness/useHookAtTopLevel
react/self-closing-comp style/useSelfClosingElements
react/no-array-index-key suspicious/noArrayIndexKey
@typescript-eslint/no-explicit-any (warn) suspicious/noExplicitAny (warn)
no-unused-vars / _ prefix noUnusedVariables / noUnusedFunctionParameters (ignore _ by default)
@typescript-eslint/no-floating-promises, no-misused-promises nursery/noFloatingPromises, nursery/noMisusedPromises

Verified with a probe file that each of these rules fires.

Coverage differences

  • Fewer type-aware checks. Biome uses its own type inference rather than the TS compiler, so most of typescript-eslint's type-checked rules (unbound-method, restrict-template-expressions, no-base-to-string, …) have no equivalent. The promise rules are carried over, but are still in Biome's nursery group.
  • useAwaitThenable is off. It reported 30 false positives on await act(async () => {}), because Biome's inference doesn't resolve React's act overloads.
  • react/jsx-pascal-case has no Biome equivalent.
  • Stricter: Biome's preset includes useExhaustiveDependencies, which ESLint never enabled. The one existing hit (useStacSearch.ts, reset effect) is suppressed with a reason rather than changing hook behaviour in a tooling PR.
  • Example app: an override disables a11y and noShadowRestrictedNames, and allows Tailwind v3's @tailwind, so it's linted about as strictly as before; the app is due to be rebuilt.

Code changes (separate commit)

  • eslint-disable → biome-ignore comments, each with a reason. react/prop-types ones were removed.
  • handleStacResponse: let detail was implicitly any; now typed as GenericObject | string, matching ApiError.
  • Biome's safe fixes: type-only imports where values are only used as types.
  • Gotcha: Biome assumes the automatic JSX runtime by default, and its "safe" useImportType fix turned import React into import type React. That breaks tsc under our "jsx": "react". Fixed with "jsxRuntime": "reactClassic" in biome.jsonc.

Scripts and CI

  • pnpm lint → biome check . (lint + format check); new pnpm format → biome format --write .
  • CI lint job runs biome ci ., which emits GitHub annotations
  • 8 style warnings remain (useOptionalChain in tests, noNonNullAssertion, one unused test import). Warnings don't fail CI.

Note on pnpm's minimumReleaseAge

pnpm 12 rejects versions published less than 24 hours ago. When pnpm add hits this, it silently writes a minimumReleaseAgeExclude list to pnpm-workspace.yaml. Check that file before committing after adding a dependency. Biome 2.5.15 is under 24 hours old, so this PR uses 2.5.14; #68 also holds back vite and globals for the same reason.

Verification

From a clean pnpm install --frozen-lockfile: pnpm lint and biome ci . (0 errors), pnpm test (94/94), pnpm build, and tsc --noEmit all pass.

Editor

Install the Biome VS Code extension (biomejs.biome) and set it as the default formatter instead of Prettier.

🤖 Generated with Claude Code

AliceR and others added 2 commits October 1, 2026 13:02
- Convert eslint-disable comments to biome-ignore with reasons; drop the
  react/prop-types ones, which have no Biome equivalent
- Type the error detail in handleStacResponse instead of implicit any
- Use type-only imports where values are only used as types
- Mark the web-vitals import promise in the example as intentionally
  unawaited

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Biome formats identically to the previous Prettier config (no changes on
the existing code) and covers the custom ESLint rules (noConsole, hooks
at top level, self-closing elements, array index keys, explicit any).
noFloatingPromises and noMisusedPromises replace the corresponding
typescript-eslint type-checked rules.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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