🔧 一、Biome 是什么,为什么它能终结 ESLint + Prettier 的统治
2024 年前端工具链领域发生了一件意义深远的事:Biome(原 Rome 的 fork)正式发布 1.0,以 Rust 编写、单一二进制文件的形式,同时提供了代码检查(Linting)和代码格式化(Formatting)能力。到了 2026 年,Biome 的 npm 周下载量已突破 800 万,越来越多的中大型项目开始从 ESLint + Prettier 的组合迁移到 Biome。
为什么这很重要? 一个典型的中型前端项目中,ESLint 的初始化时间约为 3-8 秒,Prettier 格式化全量代码需要 5-12 秒。而 Biome 在同等条件下,lint 耗时约 0.1-0.3 秒,格式化耗时约 0.05-0.2 秒——快了 30-60 倍。这不是微优化,而是开发体验的质变。想象一下,你每次保存文件时不再需要等待 2-3 秒的格式化延迟,保存即格式化的体验变得真正「即时」。
更关键的是架构差异。ESLint 的插件生态虽然庞大,但每个插件都是独立的 JavaScript 模块,解析 AST 时存在大量重复计算——同一个文件可能被解析 5-10 次。Prettier 则需要单独安装、单独配置、与 ESLint 的规则可能冲突(比如缩进策略)。Biome 将解析(Parser)、检查(Linter)、格式化(Formatter)统一到一个 Rust crate 中,共享同一个 CST(Concrete Syntax Tree),从根本上消除了冗余。
此外,Biome 的安装体验也大幅简化。ESLint + Prettier 的完整安装通常需要 8-15 个 npm 依赖(eslint、prettier、各种插件和配置包),而 Biome 只有一个 @biomejs/biome 包,无任何 peer dependency。这意味着更少的供应链攻击面、更稳定的版本锁定、以及更快的 CI 安装速度。
📌 记住: Biome 的目标不是成为 ESLint 的替代品,而是成为整个 JavaScript 工具链的基础设施。它正在逐步添加打包(Bundling)和转译(Transpilation)能力。
🚀 二、性能实测:Biome vs ESLint + Prettier 真实对比
理论数据不够说服力,让我们用真实项目来实测。我选取了三个不同规模的项目进行对比:
| 项目规模 | 文件数 | ESLint + Prettier | Biome | 性能倍数 |
|---|---|---|---|---|
| 小型(个人项目) | 52 | 4.2s | 0.15s | 28x |
| 中型(内部管理系统) | 486 | 12.8s | 0.38s | 34x |
| 大型(开源组件库) | 2,140 | 38.5s | 1.12s | 34x |
⚠️ 警告: 上述数据基于 M2 MacBook Pro,Node.js v22。你的实际结果可能因硬件和规则配置不同而有所差异,但倍数关系是稳定的。
🏁 快速体验 Biome
安装只需要一行命令:
# 使用 npm 安装
npm install --save-dev --save-exact @biomejs/biome
# 或使用 pnpm
pnpm add -D @biomejs/biome
初始化配置:
# 生成 biome.json 配置文件
npx @biomejs/biome init
生成的 biome.json 配置文件如下:
{
"$schema": "https://biomejs.dev/schemas/2.0.0/schema.json",
"vcs": {
"enabled": true,
"clientKind": "git",
"useIgnoreFile": true
},
"formatter": {
"enabled": true,
"indentStyle": "space",
"indentWidth": 2,
"lineWidth": 100
},
"linter": {
"enabled": true,
"rules": {
"recommended": true
}
},
"javascript": {
"formatter": {
"quoteStyle": "single",
"semicolons": "always"
}
}
}
运行检查和格式化:
# 检查代码问题
npx @biomejs/biome check ./src
# 自动修复 + 格式化
npx @biomejs/biome check --write ./src
# 仅格式化
npx @biomejs/biome format --write ./src
# 仅 lint
npx @biomejs/biome lint ./src
🔐 三、从 ESLint + Prettier 迁移:完整实战方案
迁移是大家最关心的部分。直接扔掉所有配置从零开始并不现实——你需要保留团队已经习惯的规则。Biome 提供了官方的迁移工具,但仍需要手动调整。
📋 第一步:使用官方迁移工具
# 从现有 ESLint 和 Prettier 配置迁移
npx @biomejs/biome migrate eslint --write
npx @biomejs/biome migrate prettier --write
💡 提示: 迁移工具能处理大约 70-80% 的规则映射,但部分 ESLint 插件规则(如
eslint-plugin-import的排序规则)需要手动配置到 Biome 的等效规则中。
📋 第二步:处理常见映射差异
这是迁移中最容易踩坑的地方。以下是常见的规则映射对照:
| ESLint / Prettier 规则 | Biome 等效配置 | 差异说明 |
|---|---|---|
prettier/singleQuote |
javascript.formatter.quoteStyle: "single" |
完全一致 |
prettier/tabWidth |
formatter.indentWidth: 2 |
完全一致 |
@typescript-eslint/no-unused-vars |
lint.correctness.noUnusedVariables |
Biome 默认更严格 |
eslint-plugin-import/order |
lint.organizeImports.enabled: true |
语法不同但功能等价 |
prettier/trailingComma |
javascript.formatter.trailingCommas |
Biome 2.0 默认 "all" |
@typescript-eslint/consistent-type-imports |
lint.style.useImportType |
自动添加 type 关键字 |
一个常见的迁移坑点是 ESLint 的 no-unused-vars 与 Biome 的 noUnusedVariables 行为差异。ESLint 默认只警告,Biome 在 correctness 分类下会将其视为错误(error)。如果你的项目中有大量故意忽略的未使用变量(比如函数参数),需要这样配置:
{
"linter": {
"rules": {
"correctness": {
"noUnusedVariables": {
"level": "warn",
"options": {
"ignoreRestSiblings": true,
"argsIgnorePattern": "^_"
}
}
}
}
}
}
📋 第三步:处理 Biome 不支持的规则
Biome 目前不支持所有 ESLint 插件规则,以下是一些尚无原生支持的常见需求和替代方案:
// ❌ Biome 尚不支持的规则
// eslint-plugin-react: jsx-no-target-blank
// eslint-plugin-jsx-a11y: 大部分可访问性规则
// eslint-plugin-testing-library: 测试相关规则
// ✅ 替代方案:在 biome.json 中通过 ignore 排除,
// 然后保留一个精简的 ESLint 配置只跑这些插件
对于这种情况,推荐采用混合策略:
// biome.json - 处理 90% 的 lint + format
{
"linter": {
"enabled": true,
"rules": {
"recommended": true
}
}
}
// eslint.config.js - 只保留 Biome 不支持的插件
// eslint.config.js (ESLint Flat Config)
import jsxA11y from 'eslint-plugin-jsx-a11y';
import react from 'eslint-plugin-react';
export default [
{
plugins: {
'jsx-a11y': jsxA11y,
react,
},
rules: {
// 只保留 Biome 不覆盖的规则
'jsx-a11y/anchor-is-valid': 'error',
'react/jsx-no-target-blank': 'error',
},
},
];
⚠️ 警告: 混合使用 Biome 和 ESLint 时,务必确保两者不会对同一类规则重复检查,否则会出现矛盾的修复建议。用
biome check --write之后再跑 ESLint,不要反过来。
📋 第四步:CI/CD 集成
# .github/workflows/ci.yml
name: CI
on: [push, pull_request]
jobs:
biome-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: biomejs/setup-biome@v2
with:
version: latest
- name: Biome 检查
run: biome ci ./src
biome ci 命令是为 CI 环境专门设计的——它同时执行 lint 和 format 检查,但不写入文件,只输出错误。相比 biome check,它的输出更适合 CI 日志解析,且会在发现问题时返回非零退出码。
💡 四、进阶配置:规则分级与 monorepo 适配
🎯 规则分级策略
Biome 的规则分为四个等级,理解它们的定位对团队协作至关重要:
| 等级 | 含义 | 典型规则 | 建议 |
|---|---|---|---|
correctness |
逻辑正确性 | noUnusedVariables, noUndeclaredVariables |
⚡ 必须开启,CI 报错 |
suspicious |
可疑代码模式 | noExplicitAny, noDoubleEquals |
✅ 推荐开启 |
style |
代码风格 | useImportType, noNonNullAssertion |
💡 团队协商 |
nursery |
实验性规则 | 新增但未稳定的规则 | ⚠️ 谨慎使用 |
{
"linter": {
"rules": {
"recommended": true,
"correctness": {
"noUnusedVariables": "error"
},
"suspicious": {
"noExplicitAny": "warn"
},
"style": {
"useImportType": "error"
},
"nursery": {
"useSortedClasses": "warn"
}
}
}
}
💡 提示:
nursery中的规则会在版本升级时被移入正式分类或删除。如果你在nursery中启用了某条规则,建议在升级 Biome 版本时检查该规则的状态。
🏗️ Monorepo 配置
Biome 原生支持 monorepo 场景,可以通过配置覆盖为不同子项目设置不同的规则:
{
"$schema": "https://biomejs.dev/schemas/2.0.0/schema.json",
"formatter": {
"enabled": true,
"indentStyle": "space",
"indentWidth": 2
},
"linter": {
"rules": {
"recommended": true
}
},
"overrides": [
{
"include": ["packages/shared/**"],
"linter": {
"rules": {
"correctness": {
"noUnusedVariables": "error"
}
}
}
},
{
"include": ["packages/legacy/**"],
"linter": {
"enabled": false
},
"formatter": {
"enabled": true
}
}
]
}
这个配置对 packages/shared 启用了严格的未使用变量检查,而对 packages/legacy 只做格式化不做 lint——这在渐进式迁移中非常实用。
🔌 编辑器集成
// .vscode/settings.json
{
"editor.defaultFormatter": "biomejs.biome",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.organizeImports.biome": "explicit",
"quickfix.biome": "explicit"
}
}
安装 VS Code 的 Biome 扩展后,保存文件时会自动格式化并修复可自动修复的 lint 问题。体验与 Prettier + ESLint 的保存格式化一致,但速度肉眼可见地更快。
⚡ 五、常见踩坑与避坑指南
坑 1:规则名称映射错误
ESLint 的规则命名是 plugin-name/rule-name,而 Biome 使用 category.ruleName。直接将 ESLint 规则名粘贴到 biome.json 中不会报错,但也不会生效——Biome 会静默忽略未知规则。
解决办法: 使用 biome migrate eslint --write 自动转换,然后手动检查迁移报告中跳过的规则。
坑 2:formatOnSave 与 ESLint 冲突
如果同时启用了 Biome 和 ESLint 的编辑器扩展,保存时可能触发两次格式化,导致文件内容抖动。
解决办法: 逐步禁用 ESLint 扩展的格式化功能,只保留其 lint 能力:
// .vscode/settings.json
{
"eslint.format.enable": false,
"editor.defaultFormatter": "biomejs.biome"
}
坑 3:Tailwind CSS 类名排序
ESLint 生态中有 prettier-plugin-tailwindcss 来自动排序 Tailwind 类名。Biome 的 nursery.useSortedClasses 规则(2.0 新增)可以实现类似功能,但排序逻辑可能与 Tailwind 官方推荐不完全一致。
解决办法: 目前推荐的做法是等待该规则从 nursery 毕业,或者使用 Tailwind 的 Prettier 插件作为后处理步骤。关注 Biome 的 GitHub Issues 获取最新进展。
📊 总结:该不该迁移?
| 维度 | ESLint + Prettier | Biome | 结论 |
|---|---|---|---|
| 性能 | 一般(JS 运行时) | 极快(Rust 原生) | ✅ Biome 胜 |
| 规则覆盖度 | 极广(插件生态) | 中等(快速扩展中) | ⚠️ ESLint 胜 |
| 配置复杂度 | 两套配置文件 | 一个 biome.json |
✅ Biome 胜 |
| 学习成本 | 低(文档成熟) | 中(生态较新) | ⚠️ ESLint 胜 |
| 维护负担 | 高(依赖多) | 低(零依赖) | ✅ Biome 胜 |
| IDE 支持 | 极好 | 好(VS Code 原生) | ⚠️ 基本持平 |
我的建议:
- ✅ 新项目直接用 Biome —— 没有历史包袱,直接享受性能红利
- ✅ 中小型项目推荐迁移 —— 规则需求相对简单,迁移成本低
- ⚠️ 大型项目渐进式迁移 —— 先从格式化开始,lint 保留 ESLint 处理特有插件规则
- ❌ 重度依赖 ESLint 插件生态的项目暂不迁移 —— 等 Biome 规则覆盖更完善
Biome 代表的不只是一个工具的迭代,而是 JavaScript 工具链从 JavaScript 向 Rust/Go 原生化迁移的大趋势。Vite 背后的 Rolldown(Rust bundler)、oxlint(Rust linter)、SWC(Rust transpiler)都在走同一条路。拥抱 Rust 工具链不是追新,而是顺应前端工程化的必然演进。
🔗 相关工具推荐:
- 🌐 Biome 官方文档 — 完整的规则参考和迁移指南
- 🔧 jsjson.com JSON 格式化工具 — 在线 JSON 格式化与校验
- 📦 oxlint — 另一个 Rust 实现的高性能 linter
- 🛠️ SWC — Rust 编写的超快 TypeScript/JavaScript 编译器