Skip to content

chore: adopt Oxlint for JS/TS semantics; keep Biome for format/non-JS (#321) - #14

Closed
thedavidweng wants to merge 3 commits into
vite-8-migration-21befrom
oxlint-biome-split-21be
Closed

chore: adopt Oxlint for JS/TS semantics; keep Biome for format/non-JS (#321)#14
thedavidweng wants to merge 3 commits into
vite-8-migration-21befrom
oxlint-biome-split-21be

Conversation

@thedavidweng

@thedavidweng thedavidweng commented Jul 16, 2026

Copy link
Copy Markdown
Owner

Issue

Closes / implements 1weiho#321 (parent roadmap 1weiho#318).

Stacked on: cursor/vite-8-migration-21be (PR for 1weiho#320). Merge after that branch.

Exact scope

  • Add Oxlint as the sole JS/TS semantic linter
  • Keep Biome as the sole formatter + CSS/JSON (non-JS) linter
  • Disable Biome JS/TS lint via override (no duplicate diagnostics)
  • Update scripts, contributor docs, and fix findings required for a green tree
  • Do not add ESLint, Prettier, Stylelint, or Oxfmt

Versions before → after

Package Before After
oxlint (none) 1.74.0
oxlint-tsgolint (none) 0.24.0
@biomejs/biome 2.4.12 2.4.12 (unchanged)

Base commit for this branch tip parent: 2331ec590346baf8306455a23a396b0bcd1ea14d (Vite 8 PR tip).

Why the old state was a problem

Biome owned JS/TS lint, formatting, and CSS/JSON together. That duplicated parser generations vs the Vite 8 / Oxc / Rolldown stack and limited type-aware / multi-file semantic checks (floating promises, import cycles).

Why these tools/versions were chosen

Breaking changes reviewed

Source changes required

  • Correctness fixes: dead || expression, useless spreads, floating promises (void), hook deps, a11y labels, unbound method on presenter channel, Vitest mock typing / conditional expect
  • Intentional suppressions only where behavior is deliberate (file drop zones; open-transition focused sync; locale-stable toast string)
  • jsx-a11y/prefer-tag-over-role left off (intentional ARIA/role patterns; Biome useSemanticElements was already selectively off for slides/landing)

Tests added or changed

  • print-ready.test.ts: typed vi.fn<() => Promise<void>>()
  • design-plugin.test.ts: replace conditional expect with toEqual
  • No silent snapshot updates

Rule mapping table

Existing Biome JS/TS rule/domain Oxlint equivalent Action Reason
linter.rules.recommended (correctness/suspicious/complexity/…) categories.correctness: error + default plugins enabled Core correctness parity
React domain / hooks (useExhaustiveDependencies) react plugin + react-hooks/exhaustive-deps enabled Stronger than prior Biome effective coverage; intentional deps documented inline
a11y recommended (noStaticElementInteractions, labels, …) jsx-a11y plugin enabled (selected) Match prior a11y intent
a11y useSemanticElements / prefer semantic tags jsx-a11y/prefer-tag-over-role disabled Prior Biome overrides already relaxed this for slides/landing; many intentional role patterns
slides/landing a11y overrides oxlint overrides for **/slides/**, apps/web/components/landing/** mirrored Preserve authoring UX exceptions
Import organization Biome assist.organizeImports retained in Biome Non-conflicting with Oxlint
CSS lint + Tailwind directives Biome CSS linter/parser retained in Biome Oxlint has no CSS scope
JSON/JSONC lint/format Biome retained in Biome Oxlint has no JSON scope
Formatting (quotes, width, semicolons) Biome formatter retained Sole formatter
(new) floating promises typescript/no-floating-promises enabled Reviewed; fire-and-forget marked with void
(new) import cycles import/no-cycle enabled Multi-file graph check
(new) Vitest plugin vitest/* correctness enabled assertFunctionNames includes helpers
Vendored shadcn UI ignore packages/core/src/app/components/ui/** ignored Same as prior Biome exclude
CLI template sources ignore packages/cli/template/** ignored Not a linted workspace package install

No previous JS/TS coverage was dropped silently; gaps above are classified.

Benchmark results

Same machine, Node 24.18.0, pnpm 11.13.1. One warm-up + 10 measured runs (median / p95). Times for wrapped pnpm/pnpm exec include package-manager startup.

Metric Current Biome-only (pre-change) Oxlint JS/TS (no type-aware) Oxlint JS/TS (type-aware) Final combined pnpm lint Change vs current
warm median elapsed 0.605 s 0.598 s 1.168 s 1.918 s combined +1.31 s (adds type-aware + CSS/JSON)
warm p95 elapsed 0.631 s 0.613 s 1.202 s 1.965 s
peak RSS (direct binary) n/a (pre) 199 MB 479 MB n/a (pnpm wrapper) type-aware costs memory
diagnostics found 1 warning (useOptionalChain) 0 0 0 (Biome non-JS: 0) prior JS warning fixed/migrated
autofix median (oxlint --fix) n/a 1.171 s clean tree; fix pass is no-op

Type-aware on vs off (Oxlint only): median 1.168 s vs 0.598 s (~2×). Decision: keep type-aware on in lint:js for floating-promise + cycle coverage; lint:js:no-type-aware available for local comparison.

Biome post-split non-JS-only median: 0.400 s (40 files).

Security audit results

pnpm audit --prod / pnpm audit still report lockfile advisories (mostly transitive / website). This PR does not claim to resolve vulnerabilities; no new advisory was introduced by adding Oxlint. Remaining advisories are tracked for 1weiho#323.

Advisory Package / path Severity Prod reachable? Before After Resolution / blocker
(unchanged set from 1weiho#320 tip) various transitive mixed mostly web/dev present present deferred to 1weiho#323 dependency upgrades

Package and bundle-size changes

  • Root adds oxlint + oxlint-tsgolint (devDependencies only)
  • No published package API change; core patch changeset for lint-driven source fixes only
  • pnpm --filter @open-slide/core pack --dry-run and CLI pack dry-run succeed

Manual validation results

corepack enable
pnpm install
pnpm format:check   # pass
pnpm lint           # pass (Node 24 and Node 22.13.0)
pnpm typecheck      # pass
pnpm test           # 306 passed
pnpm build          # pass

Known limitations

  • Combined lint is slower than Biome-only because type-aware Oxlint + Biome non-JS both run; JS semantic coverage is richer
  • jsx-a11y/prefer-tag-over-role intentionally off
  • CLI template tree ignored by Oxlint (same as not being a workspace consumer install)

Prohibited workarounds

Confirmed not used: --force, --legacy-peer-deps, dependency overrides/resolutions, patch-package, vendored forks, blanket TS/lint suppressions, prerelease packages, silent snapshot updates, unrelated features/UI churn.


Open in Devin Review

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 2 additional findings.

Open in Devin Review

@thedavidweng
thedavidweng force-pushed the vite-8-migration-21be branch from ab2a5fb to fc023fc Compare July 16, 2026 05:43
@thedavidweng
thedavidweng force-pushed the oxlint-biome-split-21be branch from 2ed9b17 to f586148 Compare July 16, 2026 05:43
@thedavidweng
thedavidweng force-pushed the vite-8-migration-21be branch from fc023fc to aa2258e Compare July 26, 2026 06:16
cursoragent and others added 3 commits July 25, 2026 23:18
Adopt Oxlint 1.74 for JS/TS/React/Vitest/import semantics with
type-aware floating-promise and import-cycle checks. Keep Biome as the
sole formatter and non-JS linter (CSS/JSON). Update scripts, docs, and
fix correctness findings surfaced by the new lint path.

Co-authored-by: Davy <thedavidweng@users.noreply.github.com>
…icker-dialog

Add oxlint-enable after the drop-zone section so jsx-a11y/no-noninteractive-element-interactions
is not silenced for the rest of each file.
@thedavidweng

Copy link
Copy Markdown
Owner Author

Superseded by upstream PR 1weiho#371 (1weiho#371). The stacked fork branch has been rebased onto current main and re-pushed to the upstream repo as an independent/stacked PR. Closing this fork PR to avoid duplicate review.

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