使用 biome 替换 eslint 和 prettier

1,084 阅读3分钟

0. 🐌 迁移背景

eslint / format 太慢,每次 commit 都要等较长时间。Rust 凭借其性能优势大火,能否将其融入我们的开发过程,提升前端的开发“幸福感”?答案是肯定的。

biome vs oxlint

本文使用 biome v1.9.4,如果你的项目是 utils 即没有样式且仅需要 lint 强烈推荐 oxc,否则 biome,当然最推荐的是二者结合

  • biome 同时支持 lint 和 format,其目标是JS 系列(即 [m|c][t]js[x])和 css less,不支持 scss,故可替换 eslint/stylelint/prettier(biome 最大的卖点是 format,采用 CST 故即使语法错误也能 format 并且添加必要元素比如括号成正确格式,其次 96%+ 契合 prettier 毕竟赢得过 prettier 的大奖)。
  • oxc 极致性能 🚀:但仅支持 lint JS 系列、vue 和 astro svelte script 部分,不支持样式。format 支持中
  • 二者都不支持 eslint 或 stylelint 插件,如果你要检测 js 或 css 的兼容性仍然需要 eslint 和 stylelint。最新消息 2025-6-13 oxlint v1 Roadmap 列出会支持eslint 插件和自定义 lint 规则。
  • Rules 对比:biome 200 条,而 oxlint 支持超过 500 条规则,数量和性能目前无人能比,包括所有 ESLint 规则、TypeScript 规则(不包括类型检查),以及 unicorn、jsdoc、react、react-hooks、jest、import 等插件。此外,Oxlint 还提供了一些独特的规则!

更多区别:Comparison with OXC github.com/biomejs/bio…

术语解释
  • lint:检测错误
  • format:将一行代码格式化成符合规则样式,比如增加空格以及拆分成多行。

  • CST:Concrete Syntax Tree - 保留全部语法细节(括号、分号、注释),错误恢复能力强(可继续解析畸形代码),典型代表 Biome、Prettier、Tree-sitter
  • AST:Abstract Syntax Tree - 仅语义关键内容(逻辑结构),错误恢复能力 弱(遇到错误可能终止解析),典型代表 OXC、Babel、TypeScript。
特性ASTCST
保留的细节仅语义关键内容(逻辑结构)全部语法细节(括号、分号、注释)
错误恢复能力弱(遇到错误可能终止解析)强(可继续解析畸形代码)
适用场景编译器、类型检查格式化、Lint 工具
性能更高(结构更简单)稍低(存储更多信息)
工具示例OXC、Babel、TypeScriptBiome、Prettier、Tree-sitter

关于 CST 和 AST 的区别以及为何 biome 和 OXC 选择不一见 CST vs AST 以及 biome 和 Oxc 各自的选择理由

1. 📦 安装

pnpm add -D @biomejs/biome

2. ✈️ 迁移 eslint 和 prettier

如果你是新项目直接 pnpx biome init --jsonc。如果需要迁移则

biome migrate eslint --write
biome migrate prettier --write

迁移之前需要执行 init 确保 biome.json[c] 存在。

如果需要迁移从 eslint 启发而来的规则可以加 --include-inspired

pnpx biome init

pnpx biome init

// biome.json
{
  "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
  "vcs": {
    "enabled": false,
    "clientKind": "git",
    "useIgnoreFile": false
  },
  "files": {
    "ignoreUnknown": false,
    "ignore": []
  },
  "formatter": {
    "enabled": true,
    "indentStyle": "tab"
  },
  "organizeImports": {
    "enabled": true
  },
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true
    }
  },
  "javascript": {
    "formatter": {
      "quoteStyle": "double"
    }
  }
}

我的项目虽然已经有了 eslint 但是个人觉得 biome 默认规则已经足够优秀,故仅选择迁移 prettier。

已有 .prettierignore:

coverage
public
dist
pnpm-lock.yaml

和 .prettierrc.cjs:

/** @format */

/** @type {import("prettier").Config} */
module.exports = {
  semi: false,
  tabWidth: 2,
  jsxSingleQuote: true,
  bracketSpacing: true,
  singleQuote: true,
  trailingComma: 'all',
  printWidth: 100,
  proseWrap: 'never',
  endOfLine: 'lf',
  singleAttributePerLine: true,
}

biome migrate prettier --write 迁移后 biome.json 修改如下(linter 对应 eslint、formatter 对应 prettier):

// biome.json
{
  "formatter": {
    "enabled": true,
-    "indentStyle": "tab"
+    "useEditorconfig": true,
+    "formatWithErrors": false,
+    "indentStyle": "space",
+    "indentWidth": 2,
+    "lineEnding": "lf",
+    "lineWidth": 100,
+    "attributePosition": "auto",
+    "bracketSpacing": true,
+    "ignore": ["**/coverage", "**/public", "**/dist", "**/pnpm-lock.yaml"]
  },
  "organizeImports": {
    "enabled": true
  },
  "javascript": {
    "formatter": {
-      "quoteStyle": "double"
+      "jsxQuoteStyle": "single",
+      "quoteProperties": "asNeeded",
+      "trailingCommas": "all",
+      "semicolons": "asNeeded",
+      "arrowParentheses": "always",
+      "bracketSameLine": false,
+      "quoteStyle": "single",
+      "attributePosition": "auto",
+      "bracketSpacing": true
    }
  }
}

修改 lint 和 lint:fix

package.json

   "lint": "biome lint && tsc --noEmit",
   "lint:fix": "biome lint --write --unsafe",
   "format": "biome format --write --unsafe",

或者使用 lint 和 format 二合一 check:

   "lint": "biome lint && tsc --noEmit",
   "lint:fix": "biome check --write --unsafe",

--fix--write 的 alias

    "\n========== Linting ==========": "",
-   "lint": "eslint src && tsc --noEmit",
-   "lint:fix": "eslint . --fix",
+   "lint": "biome lint && tsc --noEmit",
+   "lint:fix": "biome check --write --unsafe",

3. ✈️ 迁移 lint-staged

biome 1.7 支持 check staged,无需安装 lint-staged。

删除:

"lint-staged": {
    "**/*.{js,ts}": [
      "eslint --fix"
    ],
    "**/*": "prettier --write --ignore-unknown"
  }

新增

scripts: {
  "lint-staged": "biome check --staged --fix"
}

确保 ./.husky/pre-commit 有:

pnpm lint-staged # 或 npm run lint-staged。

4. 🧩 VSCode 插件

设置 formatOnSave settings.json

  "editor.codeActionsOnSave": {
+   "source.fixAll.biome": "explicit",
+   "source.organizeImports.biome": "explicit",
    "source.removeUnused": "explicit",
    "source.fixAll.eslint": "explicit"
  },
    
  "[jsonc]": {
    "editor.formatOnSave": true,
+   "editor.defaultFormatter": "biomejs.biome"
  },
  • explicit 是指必须按 ctr + s 主动保存才会执行 fix
  • 如果发现加了之后一些不支持 import type 老的 ts 项目也会增加 type 导致编译失败。则需要删除 source.fixAll.biome

biomejs.dev/reference/v…

5. 🚀 性能对比

实际项目

package.json 新增1个字段、新增一个 biome.json 文件 ⏳ 7s → 4s

npm run lint Before ⏳ ~6s → <2s(基本上是 tsc 的时间):

❯ npm run lint    

> @neural/utils@1.1.0 lint
> eslint src && tsc --noEmit

\
 ts-library-v2 on 🌱 main [⇡] is 📦 v1.1.0 via Node.js v22.7.0 took 6s

After <2s:

time lint
$ biome lint && tsc --noEmit
Checked 19 files in 12ms. No fixes applied.
bun run lint  0.04s user 0.20s system 13% cpu 1.827 total

去除 tsc 纯粹比较

🆚 eslint vs oxlint vs biome lint

业界

Tool1,000 JS FilesMemory UsageInstallation Size
ESLint + Prettier45.2 seconds1.2 GB120 MB
Biome.js8.7 seconds280 MB35 MB

实际项目

image.png

总时间:2.7s / 667ms(8ms) / 609ms(5ms)

oxlint 和 biome 速度差不多,但是 oxlint 更胜一筹 🏆。下一篇将尝试将 lint 部分迁移到 oxlint。

实验数据:

time bunx eslint src
bun x eslint src  0.01s user 0.20s system 7% cpu 2.700 total
time bunx biome lint src
Checked 16 files in 8ms. No fixes applied.
bun x biome lint src  0.00s user 0.21s system 32% cpu 0.667 total
time bunx oxlint src        
Found 0 warnings and 0 errors.
Finished in 5ms on 16 files with 101 rules using 12 threads.
bun x oxlint src  0.03s user 0.23s system 42% cpu 0.609 total

FAQ

  • 如何忽略某行代码不让 biome format:// biome-ignore format: old code formatted by prettier

📚 参考