Skip to content

Lint ​

vp lint lints code with Oxlint.

Overview ​

vp lint is built on Oxlint, the Oxc linter. Oxlint is designed as a fast replacement for ESLint for most frontend projects and ships with built-in support for core ESLint rules and many popular community rules.

Use vp lint to lint your project, and vp check to format, lint and type-check all at once.

Usage ​

bash
vp lint
vp lint --fix
vp lint --type-aware

Configuration ​

Put lint configuration directly in the lint block in the root vite.config.ts so all your configuration stays in one place. We do not recommend using oxlint.config.ts or .oxlintrc.json with Vite+.

vp lint finds its config from the working directory, so package directories without their own lint block use the root config. Relative file arguments retain their meaning. Use lint.overrides for file- or package-specific rules instead of adding lint blocks to package configs.

vp check uses the workspace-root lint block when it exists, including from a package directory. Package configs cannot replace those lint settings in vp check.

An explicit vp lint -c <path> or vp lint --config <path> selects another config. Otherwise, Oxlint discovers the nearest vite.config.* file with a lint block. Supported extensions are .js, .mjs, .ts, .cjs, .mts, and .cts. Nested configs do not override settings for individual files.

For the upstream rule set, options, and compatibility details, see the Oxlint docs.

vite.config.ts
ts
import { defineConfig } from 'vite-plus';

export default defineConfig({
  lint: {
    ignorePatterns: ['dist/**'],
    options: {
      typeAware: true,
      typeCheck: true,
    },
  },
});

Type-Aware Linting ​

We recommend enabling both typeAware and typeCheck in the lint block:

  • typeAware: true enables rules that require TypeScript type information
  • typeCheck: true enables full type checking during linting

This path is powered by tsgolint on top of the TypeScript 7 (aka TypeScript Go) toolchain. It gives Oxlint access to type information and allows type checking directly via vp lint and vp check.

JS Plugins ​

If you are migrating from ESLint and still depend on a few critical JavaScript-based ESLint plugins, Oxlint has JS plugin support that can help you keep those plugins running while you complete the migration.

JS Plugins also enable writing your own custom rules for Oxlint.

Writing Your Own Rules ​

Import the plugin authoring API from vite-plus/lint/plugins:

lint/my-plugin.js
js
import { definePlugin, defineRule } from 'vite-plus/lint/plugins';

const noFoo = defineRule({
  meta: { messages: { noFoo: 'Do not name things "foo".' } },
  create(context) {
    return {
      Identifier(node) {
        if (node.name === 'foo') {
          context.report({ node, messageId: 'noFoo' });
        }
      },
    };
  },
});

export default definePlugin({
  meta: { name: 'my' },
  rules: { 'no-foo': noFoo },
});

Register it under lint.jsPlugins and enable its rules:

vite.config.ts
ts
import { defineConfig } from 'vite-plus';

export default defineConfig({
  lint: {
    jsPlugins: ['./lint/my-plugin.js'],
    rules: {
      'my/no-foo': 'error',
    },
  },
});

For rule tests, RuleTester is available from vite-plus/lint/plugins-dev.

Both entrypoints re-export the copy that ships with Vite+. The API therefore always matches the bundled Oxlint.

Use them instead of adding @oxlint/plugins or oxlint as a direct dependency. A separately pinned copy can drift from the linter that loads your plugin. It also does not resolve from a plugin file under pnpm's strict layout, unless every package that holds a plugin declares it.

vp migrate rewrites existing oxlint and @oxlint/plugins imports for you. See Oxlint JS Plugin Imports. The vite-plus/prefer-vite-plus-imports rule reports any that come back.