vite-plugin-oxlint
Runs the Oxlint linter automatically during Vite dev and build, surfacing lint errors without leaving your workflow.
Repository Health
Technical Analysis
vite-plugin-oxlint wires the Rust-based Oxlint linter into a Vite project’s dev server and build pipeline, so lint errors and warnings show up alongside compiler output instead of requiring a separate terminal or CI step. It spawns the oxlint binary through the detected package manager (npm, pnpm, yarn, or bun), streams its output through Vite’s logger, and re-runs it on a debounce whenever files change during development.
Because it delegates all rule evaluation to Oxlint itself, the plugin’s own surface area stays small: a thin options layer for ignore patterns, allow/deny/warn overrides, output format, and whether lint failures should fail the build. It is a drop-in complement to (or replacement for) vite-plugin-eslint-style setups, giving teams that have already adopted Oxlint’s speed a way to see results without leaving vite dev.
What You Get
- Automatic Oxlint runs on
buildStartand on debounced HMR updates duringvite dev - Package-manager-aware execution (npm, pnpm, yarn, bun) via
package-manager-detector, with anpx-style fallback - Fine-grained control over rules via
allow/deny/warnarrays that override the on-disk oxlint config file - Configurable failure behavior (
failOnError,failOnWarning) to gate builds on lint results, or leave them non-blocking - Support for all native Oxlint output formats (
default,checkstyle,github,gitlab,json,junit,stylish,unix) - An
oxlintPathoverride for monorepos where the binary isn’t resolvable from the project root
Common Use Cases
- Surfacing lint errors in the Vite dev server terminal instead of needing a separate
oxlint --watchprocess - Failing CI builds on lint errors or warnings by setting
failOnError/failOnWarningin the Vite config - Migrating a project from
vite-plugin-eslintto Oxlint for faster lint feedback without changing the developer workflow - Emitting
checkstyle/junit/githubformatted lint output for CI annotation and reporting integrations
Under The Hood
Architecture - The plugin is a single Vite Plugin object (src/index.ts) built around three hooks: configResolved captures Vite’s logger instance, buildStart runs Oxlint once via runOxlintOnce, and handleHotUpdate debounces re-runs (300ms, via setTimeout) on every file change during dev. Execution itself goes through runOxlintOnce → tryRun → runChild: tryRun resolves the correct invocation command for the detected package manager via resolveCommand from package-manager-detector, first attempting a local binary execution and falling back to a general execute mode (e.g. npx) if that resolution fails; runChild wraps cross-spawn in a Promise, buffering output when using the fallback path so a failed local-binary attempt doesn’t print noise before retrying. Exit code 0 is success, code 1 is lint errors (rejected or logged depending on failOnError/failOnWarning), anything else is treated as an unexpected/fallback condition.
Tech Stack - Written in TypeScript, built with tsdown to dual CJS/ESM output plus .d.mts/.d.cts type declarations, targeting vite@>=5.0.0 and oxlint@>=0.9.0 as peer dependencies. Runtime dependencies are minimal and well-scoped: cross-spawn for cross-platform child-process spawning and package-manager-detector for identifying npm/pnpm/yarn/bun. Dev tooling uses oxlint/oxfmt for its own linting and formatting (eating its own dog food) and vitest for tests, with pnpm as the declared package manager (workspace-pinned via packageManager in package.json).
Code Quality - The codebase is small (src/index.ts, src/types.ts, one test file) and reads cleanly: buildArgs is a pure function mapping Options to CLI flags, isolated from the process-spawning logic, which makes the option-to-flag mapping easy to verify. Tests in src/__tests__/index.test.ts cover plugin shape (hook presence) and option-acceptance (empty options, all options, single vs. array ignorePattern) but do not exercise the actual runChild/spawn behavior or assert on generated CLI args, so the child-process and package-manager-fallback logic is untested. Naming and typing are consistent throughout, and there is no any usage in the reviewed source.
API Design - The public surface is a single default export, oxlintPlugin(options?), matching the standard Vite plugin factory convention — zero-config by default (oxlintPlugin() runs with sane defaults for configFile, lintOnStart, lintOnHotUpdate) with an Options interface that maps almost 1:1 onto native Oxlint CLI flags (allow/deny/warn/format/quiet/fix), so anyone familiar with the oxlint CLI can guess the plugin options without reading docs. The README documents every option in a table plus worked examples for each, keeping the barrier to first use low.