skip to content

In create-vue 3.24, what does selecting ESLint generate, why is Oxlint always added with it, and how does the Prettier choice fit in?

level: middleimportance: should knowfreq 20%

answer

  1. a flat config file
  2. two linters, one lint script
  3. rules turned off twice
  4. formatting kept out of linting
  5. a deprecated flag says why

basics

~20 s

ESLint adds a flat eslint.config with the Vue and TypeScript presets, plus Oxlint with an .oxlintrc.json; the lint script runs both. Oxlint is always included and eslint-plugin-oxlint turns off ESLint rules it covers. Prettier adds its own config and a format script.

solid answer

~30 s

Choosing ESLint writes a flat `eslint.config` (`.ts` in TypeScript projects) built with `defineConfigWithVueTs` from `@vue/eslint-config-typescript`, the Vue plugin and, with Vitest, `@vitest/eslint-plugin` for test files. Since 3.24 Oxlint is **always** added with ESLint (the old `--oxlint` flag is deprecated): an `.oxlintrc.json` with the correctness category as errors, `lint:oxlint` and `lint:eslint` scripts, and `lint` running both through `run-s`. `eslint-plugin-oxlint`'s `buildFromOxlintConfigFile` goes last and disables ESLint rules Oxlint already checks, so each rule runs once. Prettier adds `.prettierrc.json` and a `format` script; with ESLint it also adds `eslint-config-prettier`'s `skipFormatting`. The experimental Oxfmt choice replaces Prettier.

code

json · 6 lines
json
{
  "lint:oxlint": "oxlint . --fix",
  "lint:eslint": "eslint . --fix --cache",
  "lint": "run-s \"lint:*\"",
  "format": "prettier --write --experimental-cli src/"
}

go deeper

for a junior

Recall that ESLint brings a lint script and Prettier brings a format script, and that Oxlint comes along with ESLint.

for a middle

Explain the flat config, the Oxlint layer that disables duplicate rules, and how skipFormatting separates linting from formatting.

for a senior

Show you would keep the Oxlint layer last, run lint without --fix in CI, and drop deprecated flags from scaffold scripts.

for a principal

Decide how much of the generated lint stack becomes a shared config package across Vue repositories, and who owns its upgrades.

## What the ESLint choice writes Selecting ESLint (or `--eslint`) renders several layers: - **`eslint.config`**, a flat config. In a TypeScript project it becomes `eslint.config.ts` (loaded through `jiti`) and uses `defineConfigWithVueTs` with `vueTsConfigs` from `@vue/eslint-config-typescript`; in a JavaScript project it uses the JavaScript core preset. - **Global ignores** for `dist`, `dist-ssr` and `coverage`. - **Tool-specific blocks**: `@vitest/eslint-plugin`'s recommended rules for `src/**/__tests__/*` when Vitest is chosen, and matching blocks for Playwright or Cypress. - **Editor files**: `.editorconfig`, `.gitattributes` and VS Code extension recommendations. - **Oxlint**, always, as described below. ## Why Oxlint comes with it **Oxlint** is a fast linter that implements many common rules natively. create-vue pairs it with ESLint rather than replacing ESLint: the Vue and TypeScript presets it configures are ESLint configs, and Oxlint takes over the rules it can run faster. In 3.24 the `--oxlint` flag is deprecated with the message that Oxlint is now always included when ESLint is selected. The pairing is wired so each rule runs in one tool: 1. `.oxlintrc.json` enables Oxlint's plugins (`eslint`, `typescript` with TS, `unicorn`, `oxc`, `vue`, and `vitest` with Vitest) and sets the `correctness` category to `error`. 2. `eslint-plugin-oxlint`'s `buildFromOxlintConfigFile('.oxlintrc.json')` is appended **last** to the ESLint config; it only disables ESLint rules that Oxlint already covers. 3. The scripts are `lint:oxlint` (`oxlint . --fix`), `lint:eslint` (`eslint . --fix --cache`) and `lint`, which is `run-s "lint:*"`. ## Where Prettier fits | Choice | Files | Scripts | ESLint interaction | |---|---|---|---| | Prettier | `.prettierrc.json` (`semi: false`, `singleQuote: true`, `printWidth: 100`) | `format` | with ESLint, `skipFormatting` from `eslint-config-prettier` | | Oxfmt (experimental) | `.oxfmtrc.json` | `format` | same `skipFormatting` layer | | neither | none | none | none | Prettier does not require ESLint: the formatting layer renders on its own. When both are chosen, `skipFormatting` turns off ESLint's stylistic rules so the linter and the formatter never fight over the same whitespace. `--eslint-with-prettier` is deprecated in favour of `--eslint --prettier`. ## The generated config, top to bottom In a TypeScript project with Vitest, ESLint and Prettier, `eslint.config.ts` is assembled in this order: 1. a block naming the files to lint: `**/*.{vue,ts,mts,tsx}`; 2. `globalIgnores` for build and coverage output; 3. the Vue and TypeScript presets; 4. the Vitest block, scoped to `src/**/__tests__/*`; 5. the Oxlint layer, which only disables rules; 6. `skipFormatting`, which only disables stylistic rules. The two disabling layers sit at the end on purpose: the scaffolder's own comment says these configs only disable rules, so they must be applied last. A commented-out `configureVueProject` call near the top shows how to allow other script languages, such as TSX, in `.vue` files. ## Using it in an internal tool - Run `npm run format` once after install, as the scaffolder's closing message suggests when a formatter was chosen. - In CI, run `npm run lint` without the fix flags if you want a check rather than a rewrite; the generated scripts pass `--fix` because they target local use. - Keep the Oxlint layer last in `eslint.config` when adding your own blocks, or ESLint may re-enable rules Oxlint already checks. - Edit `.oxlintrc.json` rather than `eslint.config` when you want to change a rule Oxlint owns; the ESLint side follows automatically, because the disabling layer is built from that same file. - Install the recommended editor extensions the scaffold lists in `.vscode/extensions.json`, so fixes on save match what the scripts do. - The ESLint script caches results with `--cache`; clear the cache file if a config change seems to have no effect. ## Mistakes worth catching - Passing `--oxlint` in new scripts: deprecated and unnecessary. - Removing `eslint-plugin-oxlint` but keeping Oxlint: every overlapping rule then runs twice. - Adding stylistic ESLint rules alongside Prettier: `skipFormatting` exists to keep formatting out of linting.

  • Why is the Oxlint config applied last in eslint.config?
    `buildFromOxlintConfigFile` only turns rules off. Applied last, it overrides any earlier preset that enabled a rule Oxlint already checks, so the rule runs once, in the faster tool. Blocks you add after it can re-enable duplicates.
  • What changes if you pick Oxfmt instead of Prettier?
    Oxfmt is an experimental choice that replaces Prettier: the project gets `.oxfmtrc.json` and a `format` script for Oxfmt, and no Prettier config. With ESLint, the same `skipFormatting` layer keeps stylistic rules out of the linter.

saying these in an interview costs you the question

  • You must pass --oxlint to get Oxlint with ESLint.
  • Oxlint replaces ESLint entirely in create-vue projects.
  • Choosing Prettier requires choosing ESLint too.
  • Every overlapping rule runs in both Oxlint and ESLint.
  • The generated config file is a legacy .eslintrc.