Skip to content

chore: migrate lint and format from ESLint+Prettier to oxlint+oxfmt - #96

Closed
martyy-code wants to merge 1 commit into
stagingfrom
chore/migrate-to-oxlint-oxfmt
Closed

martyy-code wants to merge 1 commit into
stagingfrom
chore/migrate-to-oxlint-oxfmt

Conversation

@martyy-code

Copy link
Copy Markdown
Contributor

Mirrors the migration landed in deessejs/fp PR #444. Replaces the ESLint flat configs in packages/errors and apps/web and the root .prettierrc with a single oxlint + oxfmt setup.

What

  • Add oxlint@^1.87 and oxfmt@^0.72 as root dev dependencies.
  • Remove eslint, @eslint/js, typescript-eslint, and eslint-config-next.
  • New root configs: .oxlintrc.json and .oxfmtrc.json (the latter migrated from .prettierrc).
  • Per-workspace configs at packages/errors/.oxlintrc.json and apps/web/.oxlintrc.json. A local override at apps/web/tests/seo/fixtures/.oxlintrc.json disables eslint/no-await-in-loop for that test fixture (the sequential awaits are intentional).
  • Scripts: root format and format:check now use oxfmt; per-workspace lint and lint:fix use oxlint. lint-staged invokes oxfmt and oxlint --fix.
  • Husky pre-commit now runs pnpm exec lint-staged && pnpm format:check && pnpm turbo type-check so format drift is caught on commit, not in CI.

Why

oxlint is a Rust-based linter that is materially faster than ESLint (single-digit seconds across the full workspace). oxfmt is its companion formatter. Together they replace the ESLint + Prettier pair with a single toolchain, drop the typescript-eslint plugin, and remove the legacy eslint-config-next that the web app was depending on without its own lint script. The migration also surfaces a class of issues that the prior ESLint config did not flag (e.g. consistent-type-imports, no-await-in-loop).

Source fixes driven by the migration

Four files were touched to satisfy rules that did not exist in the prior ESLint config:

  • packages/errors/tests/edge-cases.test.ts: inline import('@standard-schema/spec').StandardSchemaV1 annotation replaced with a proper type import.
  • apps/web/src/app/sitemap.ts: two duplicate imports from @/lib/source merged.
  • apps/web/proxy.ts: NextRequest (type) split from NextResponse (value) to mark the type-only import.
  • apps/web/tests/seo/fixtures/stubs/fumadocs.ts: left as-is; the await in loop is intentional and the rule is disabled in the local override.

Validation

  • pnpm lint — 0 errors, 4 warnings (non-blocking; the same warning classes that deessejs/fp landed with)
  • pnpm format:check — clean
  • pnpm type-check — clean, both packages
  • pnpm test — all tests pass
  • pnpm build — clean, both packages

Notes

  • This is a developer-tooling change only. The published @deessejs/errors artifact, the public API, and the runtime behavior are unchanged.
  • oxfmt reformatted the existing source files to match its style. The diff is large (~190 files) but mechanical: line endings and trailing commas are the main visible changes. A separate formatting-only commit is not produced; the reformat is folded into the migration commit so the working tree ends in a clean state.
  • The pre-commit hook now runs three commands sequentially (lint-staged, format:check, type-check). On a clean working tree the total pre-commit time is ~5s.

Replaces the ESLint flat configs in packages/errors and apps/web and
the root .prettierrc with a single oxlint + oxfmt setup.

- Add oxlint@^1.87 and oxfmt@^0.72 as root dev dependencies.
- Remove eslint, @eslint/js, typescript-eslint, eslint-config-next.
- New root configs: .oxlintrc.json and .oxfmtrc.json (migrated from
  .prettierrc).
- Per-workspace configs at packages/errors/.oxlintrc.json and
  apps/web/.oxlintrc.json. A local override at
  apps/web/tests/seo/fixtures/.oxlintrc.json disables
  eslint/no-await-in-loop for the test fixture.
- Scripts: root format and format:check now use oxfmt; per-workspace
  lint and lint:fix use oxlint. lint-staged invokes oxfmt and
  oxlint --fix.
- Husky pre-commit now runs pnpm exec lint-staged && pnpm format:check
  && pnpm turbo type-check.

Developer-tooling change only. The published artifact, the public
API, and the runtime behavior are unchanged. Oxfmt reformatted
existing source files to match its style. Four source fixes were
required, all driven by rules that did not exist in the prior
ESLint config:

- packages/errors/tests/edge-cases.test.ts: inline import() type
  annotation replaced with a proper type import.
- apps/web/src/app/sitemap.ts: merged two duplicate imports.
- apps/web/proxy.ts: split NextRequest (type) from NextResponse
  (value) to mark the type-only import.
- apps/web/tests/seo/fixtures/stubs/fumadocs.ts: left as-is; the
  await-in-loop is intentional and the rule is disabled in the
  local override.

Validated:
- pnpm lint         0 errors, 4 warnings (non-blocking)
- pnpm format:check clean
- pnpm type-check   clean, both packages
- pnpm test         all tests pass
- pnpm build        clean, both packages
@codewizdave
codewizdave force-pushed the chore/migrate-to-oxlint-oxfmt branch from e57c0bd to b1ece37 Compare October 7, 2026 15:06
@martyy-code

Copy link
Copy Markdown
Contributor Author

Superseded by #97 (the original branch was hitting Internal Server Error on multiple push attempts, so a fresh branch was created with the same content). The remaining CI gap on this PR is the same as on #97: staging does not yet have the unified ci.yml from PR #92 (which is only on main). Until the consolidated ci.yml lands on staging, only the changeset-check job is visible — the full 8-job matrix (Build, Lint, Tests × 3, Type Check × 3) won't run.

@martyy-code martyy-code closed this Oct 7, 2026
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.

2 participants