Skip to content

Dev: Migrate from ESLint + Prettier to Biome #31

@evans-sam

Description

@evans-sam

Problem

The project uses two separate tools for code style:

  • ESLint (eslint, @eslint/js, typescript-eslint, eslint-plugin-compat) with flat config in eslint.config.mjs
  • Prettier (prettier) with config in .prettierrc

That's 5 devDependencies, 2 configs, and 2 CI invocations for what Biome provides in a single Rust binary with one config.

Why it matters

  • Speed: Biome is roughly 25× faster than ESLint+Prettier. Matters for pre-commit latency (Dev: Add Husky + lint-staged pre-commit hook #26) and CI feedback loops.
  • One config, one devDep: biome.json replaces eslint.config.mjs + .prettierrc; @biomejs/biome replaces five packages.
  • No tool conflicts: ESLint and Prettier occasionally disagree about the same rule; a unified tool eliminates that class of confusion.
  • Native TS: No typescript-eslint plugin layer to maintain.
  • Smaller dev surface: Fewer transitive devDeps means less for Security: Add CodeQL static analysis workflow #14 (audit-in-CI) and Dependabot to chew on.

Trade-offs to acknowledge

  • eslint-plugin-compat (browser compat warnings) has no direct Biome equivalent. Options:
    • Drop it (recommended) — the rule is currently warn, not error, and compat coverage is loose anyway. Document supported browsers in README.
    • Keep ESLint installed only for that one rule (defeats most of the migration value).
    • Replace with a standalone browserslist-driven check in CI.
  • Markdown / YAML formatting: Biome does not format .md or .yml. Either keep Prettier solely for docs, drop docs formatting, or accept manual care.
  • Lint rule coverage: Biome's rule set is narrower than ESLint's full ecosystem. The currently used @eslint/js recommended + typescript-eslint recommended sets have near-equivalent Biome coverage, but verify against the 9 existing eslint-disable comments to confirm each rule has a Biome equivalent (or that the disable is no longer needed once Biome takes over).

Proposed approach

  1. npm install --save-dev @biomejs/biome and npx @biomejs/biome init.
  2. Migrate existing config: npx @biomejs/biome migrate eslint --write then npx @biomejs/biome migrate prettier --write. Review the generated biome.json.
  3. Port project style preferences explicitly into biome.json:
    • printWidth: 240
    • singleQuote: true
    • trailingComma: 'all'
    • arrowParens: 'always'
    • bracketSameLine: false
  4. Resolve the eslint-plugin-compat decision per the trade-off above.
  5. Update the 9 existing eslint-disable comments in src/ to Biome's // biome-ignore lint/... syntax (or remove them if Biome doesn't flag the underlying issue).
  6. Replace npm scripts:
    • lintbiome lint .
    • formatbiome format --write .
    • format:checkbiome format .
    • Optional new checkbiome check . (lint + format combined)
  7. Update .github/workflows/pr.yml to call the new scripts (or just one npm run check).
  8. Verify npm run format produces a zero-diff against current source — i.e., style is preserved exactly. Tune biome.json until it is.
  9. Decide on .md / .yml formatting (keep Prettier just for docs, or drop).
  10. Remove ESLint (and possibly Prettier) from package.json, delete eslint.config.mjs (and .prettierrc if Prettier is fully gone).
  11. Update CONTRIBUTING.md to document the new tool and commands.

Coordination

Acceptance criteria

  • eslint, @eslint/js, typescript-eslint, eslint-plugin-compat removed from package.json.
  • prettier removed (or kept solely for .md/.yml, with that decision documented).
  • eslint.config.mjs deleted.
  • biome.json present and committed.
  • npm run lint, npm run format, npm run format:check all delegate to Biome.
  • npm run format produces zero diff against the existing source on first run.
  • PR workflow passes against Biome-formatted code.
  • All 9 existing eslint-disable comments migrated to Biome syntax or removed.
  • CI lint+format step duration is lower than before (Biome should be faster).

Metadata

Metadata

Assignees

No one assigned

    Labels

    oss-hygieneCommunity health, governance, contributor UXtech-debtTechnical debt / code quality

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions