oxlint and Vite+
Run every Interlace plugin on oxlint or Vite+ with an oxlint-plugin-* package. Same rules, same rule IDs, no ESLint install.
Why oxlint and Vite+
Vite+ bundles the Vite toolchain into one
dependency, and its linter is oxlint.
oxlint loads ESLint-style rules through jsPlugins, so a project on Vite+ can
run our rules without adding ESLint at all.
We treat oxlint as an automated peer of ESLint: the same rule tests run on both
engines, and a rule declares in meta.interop.runtimes which engines it
supports. Rules that need TypeScript type information run on ESLint only.
One implementation, the same rule IDs
Every eslint-plugin-<name> has an oxlint-plugin-<name> twin. The twin is one
line, module.exports = require('eslint-plugin-<name>/oxlint'), and it is
released at the same version. There is no second copy of any rule to drift.
The rule IDs are identical on both engines: <name>/<rule>, for example
jwt-security/no-algorithm-none. oxlint takes the prefix from the plugin's own
meta.name, which is the same object ESLint loads.
Installing an alias does not install ESLint
eslint is an optional peer of every plugin. Installing
oxlint-plugin-<name> pulls in the plugin and its runtime helpers, not ESLint.
Set it up
Every plugin page and every rule page carries the same two tabs: oxlint / Vite+
first, ESLint second. Your choice is remembered across pages. To link someone
straight to the ESLint setup, add #engine-eslint to the page URL.
{
"jsPlugins": ["oxlint-plugin-jwt-security"],
"rules": { "jwt-security/no-algorithm-none": "error" }
}import { defineConfig } from 'vite-plus';
export default defineConfig({
lint: {
jsPlugins: ['oxlint-plugin-jwt-security'],
rules: { 'jwt-security/no-algorithm-none': 'error' },
},
});Every alias package
import-next fills the gaps in oxlint's import plugin
oxlint ships a native import plugin. oxlint-plugin-import-next adds the
rules it does not have yet: resolution (no-unresolved), ordering (order),
dependency hygiene (no-extraneous-dependencies, no-unused-modules), and
architecture boundaries (no-restricted-paths, no-internal-modules), and
path cleanup (no-useless-path-segments). The rules for which oxlint ships a
native rule of the same name are listed in the next section.
The 22 rules oxlint does not ship natively, all available as import-next/<rule> through oxlint-plugin-import-next:
dynamic-import-chunknameenforce-dependency-directionenforce-import-orderenforce-team-boundariesno-barrel-importno-cross-domain-importsno-deprecatedno-extraneous-dependenciesno-full-package-importno-import-module-exportsno-internal-modulesno-legacy-importsno-relative-packagesno-restricted-pathsno-unresolvedno-unused-modulesno-useless-path-segmentsorderprefer-direct-importprefer-modern-apiprefer-tree-shakeable-importsrequire-import-approval
Covered natively by oxlint
For some of our rules, oxlint ships a native rule of the same name, mostly in
import-next (oxlint's import), react-a11y (jsx_a11y) and
react-features (react). Each name match was triaged; matches between
unrelated rules are left out.
For 120 of our rules, oxlint 1.88.0 ships a native rule of the same name (it has 871 built-in rules in all). The behaviour has not been compared rule by rule: read both rule docs before you swap one for the other.
conventions: 6 rules
conventions/consistent-existence-index-check· native:unicorn/consistent-existence-index-checkconventions/filename-case· native:unicorn/filename-caseconventions/no-console-spaces· native:unicorn/no-console-spacesconventions/no-magic-numbers· native:eslint/no-magic-numbersconventions/prefer-code-point· native:unicorn/prefer-code-pointconventions/prefer-dom-node-text-content· native:unicorn/prefer-dom-node-text-content
import-next: 34 rules
import-next/consistent-type-specifier-style· native:import/consistent-type-specifier-styleimport-next/default· native:import/defaultimport-next/export· native:import/exportimport-next/exports-last· native:import/exports-lastimport-next/extensions· native:import/extensionsimport-next/first· native:import/firstimport-next/group-exports· native:import/group-exportsimport-next/max-dependencies· native:import/max-dependenciesimport-next/named· native:import/namedimport-next/namespace· native:import/namespaceimport-next/newline-after-import· native:import/newline-after-importimport-next/no-absolute-path· native:import/no-absolute-pathimport-next/no-amd· native:import/no-amdimport-next/no-anonymous-default-export· native:import/no-anonymous-default-exportimport-next/no-barrel-file· native:oxc/no-barrel-fileimport-next/no-commonjs· native:import/no-commonjsimport-next/no-cycle· native:import/no-cycleimport-next/no-default-export· native:import/no-default-exportimport-next/no-duplicates· native:import/no-duplicatesimport-next/no-dynamic-require· native:import/no-dynamic-requireimport-next/no-empty-named-blocks· native:import/no-empty-named-blocksimport-next/no-mutable-exports· native:import/no-mutable-exportsimport-next/no-named-as-default· native:import/no-named-as-defaultimport-next/no-named-as-default-member· native:import/no-named-as-default-memberimport-next/no-named-default· native:import/no-named-defaultimport-next/no-named-export· native:import/no-named-exportimport-next/no-namespace· native:import/no-namespaceimport-next/no-nodejs-modules· native:import/no-nodejs-modulesimport-next/no-relative-parent-imports· native:import/no-relative-parent-importsimport-next/no-self-import· native:import/no-self-importimport-next/no-unassigned-import· native:import/no-unassigned-importimport-next/prefer-default-export· native:import/prefer-default-exportimport-next/prefer-node-protocol· native:unicorn/prefer-node-protocolimport-next/unambiguous· native:import/unambiguous
maintainability: 5 rules
maintainability/consistent-function-scoping· native:unicorn/consistent-function-scopingmaintainability/error-message· native:unicorn/error-messagemaintainability/no-lonely-if· native:eslint/no-lonely-ifmaintainability/no-nested-ternary· native:eslint/no-nested-ternarymaintainability/no-unreadable-iife· native:unicorn/no-unreadable-iife
modernization: 3 rules
modernization/no-instanceof-array· native:unicorn/no-instanceof-arraymodernization/prefer-at· native:unicorn/prefer-atmodernization/prefer-event-target· native:unicorn/prefer-event-target
modularity: 1 rules
modularity/no-mutable-exports· native:import/no-mutable-exports
operability: 1 rules
operability/no-process-exit· native:unicorn/no-process-exit
react-a11y: 35 rules
react-a11y/alt-text· native:jsx_a11y/alt-textreact-a11y/anchor-ambiguous-text· native:jsx_a11y/anchor-ambiguous-textreact-a11y/anchor-has-content· native:jsx_a11y/anchor-has-contentreact-a11y/anchor-is-valid· native:jsx_a11y/anchor-is-validreact-a11y/aria-activedescendant-has-tabindex· native:jsx_a11y/aria-activedescendant-has-tabindexreact-a11y/aria-props· native:jsx_a11y/aria-propsreact-a11y/aria-role· native:jsx_a11y/aria-rolereact-a11y/aria-unsupported-elements· native:jsx_a11y/aria-unsupported-elementsreact-a11y/autocomplete-valid· native:jsx_a11y/autocomplete-validreact-a11y/click-events-have-key-events· native:jsx_a11y/click-events-have-key-eventsreact-a11y/control-has-associated-label· native:jsx_a11y/control-has-associated-labelreact-a11y/heading-has-content· native:jsx_a11y/heading-has-contentreact-a11y/html-has-lang· native:jsx_a11y/html-has-langreact-a11y/iframe-has-title· native:jsx_a11y/iframe-has-titlereact-a11y/img-redundant-alt· native:jsx_a11y/img-redundant-altreact-a11y/interactive-supports-focus· native:jsx_a11y/interactive-supports-focusreact-a11y/label-has-associated-control· native:jsx_a11y/label-has-associated-controlreact-a11y/lang· native:jsx_a11y/langreact-a11y/media-has-caption· native:jsx_a11y/media-has-captionreact-a11y/mouse-events-have-key-events· native:jsx_a11y/mouse-events-have-key-eventsreact-a11y/no-access-key· native:jsx_a11y/no-access-keyreact-a11y/no-aria-hidden-on-focusable· native:jsx_a11y/no-aria-hidden-on-focusablereact-a11y/no-autofocus· native:jsx_a11y/no-autofocusreact-a11y/no-distracting-elements· native:jsx_a11y/no-distracting-elementsreact-a11y/no-interactive-element-to-noninteractive-role· native:jsx_a11y/no-interactive-element-to-noninteractive-rolereact-a11y/no-noninteractive-element-interactions· native:jsx_a11y/no-noninteractive-element-interactionsreact-a11y/no-noninteractive-element-to-interactive-role· native:jsx_a11y/no-noninteractive-element-to-interactive-rolereact-a11y/no-noninteractive-tabindex· native:jsx_a11y/no-noninteractive-tabindexreact-a11y/no-redundant-roles· native:jsx_a11y/no-redundant-rolesreact-a11y/no-static-element-interactions· native:jsx_a11y/no-static-element-interactionsreact-a11y/prefer-tag-over-role· native:jsx_a11y/prefer-tag-over-rolereact-a11y/role-has-required-aria-props· native:jsx_a11y/role-has-required-aria-propsreact-a11y/role-supports-aria-props· native:jsx_a11y/role-supports-aria-propsreact-a11y/scope· native:jsx_a11y/scopereact-a11y/tabindex-no-positive· native:jsx_a11y/tabindex-no-positive
react-features: 33 rules
react-features/checked-requires-onchange-or-readonly· native:react/checked-requires-onchange-or-readonlyreact-features/display-name· native:react/display-namereact-features/jsx-handler-names· native:react/jsx-handler-namesreact-features/jsx-key· native:react/jsx-keyreact-features/jsx-max-depth· native:react/jsx-max-depthreact-features/jsx-no-duplicate-props· native:react/jsx-no-duplicate-propsreact-features/jsx-no-literals· native:react/jsx-no-literalsreact-features/jsx-no-script-url· native:react/jsx-no-script-urlreact-features/jsx-no-target-blank· native:react/jsx-no-target-blankreact-features/no-children-prop· native:react/no-children-propreact-features/no-danger· native:react/no-dangerreact-features/no-danger-with-children· native:react/no-danger-with-childrenreact-features/no-did-mount-set-state· native:react/no-did-mount-set-statereact-features/no-did-update-set-state· native:react/no-did-update-set-statereact-features/no-direct-mutation-state· native:react/no-direct-mutation-statereact-features/no-find-dom-node· native:react/no-find-dom-nodereact-features/no-is-mounted· native:react/no-is-mountedreact-features/no-multi-comp· native:react/no-multi-compreact-features/no-namespace· native:react/no-namespacereact-features/no-object-type-as-default-prop· native:react/no-object-type-as-default-propreact-features/no-redundant-should-component-update· native:react/no-redundant-should-component-updatereact-features/no-render-return-value· native:react/no-render-return-valuereact-features/no-set-state· native:react/no-set-statereact-features/no-string-refs· native:react/no-string-refsreact-features/no-this-in-sfc· native:react/no-this-in-sfcreact-features/no-unescaped-entities· native:react/no-unescaped-entitiesreact-features/no-unknown-property· native:react/no-unknown-propertyreact-features/no-unsafe· native:react/no-unsafereact-features/prefer-es6-class· native:react/prefer-es6-classreact-features/react-in-jsx-scope· native:react/react-in-jsx-scopereact-features/require-render-return· native:react/require-render-returnreact-features/state-in-constructor· native:react/state-in-constructorreact-features/void-dom-elements-no-children· native:react/void-dom-elements-no-children
reliability: 2 rules
reliability/error-message· native:unicorn/error-messagereliability/no-await-in-loop· native:eslint/no-await-in-loop
Similar native rule, different behaviour:
browser-security/no-eval· native:eslint/no-eval. ours adds CWE-95 context and browser sinks; keep for the security mappingimport-next/no-deprecated· native:typescript/no-deprecated. native rule is type-aware and flags any deprecated API use; ours flags imports of deprecated modules/exportsnode-security/no-dynamic-require· native:import/no-dynamic-require. ours is a security rule (CWE-706 / code loading from input); native is a module-hygiene rulereact-features/no-deprecated· native:typescript/no-deprecated. ours targets deprecated React APIs; native is type-aware over any @deprecated symbol
Building secure JavaScript with Interlace? Star the repo to get new rules and CWE coverage as we ship them — or follow the AI-code-security benchmarks behind them.