2026 年,每个前端项目都面临一个「隐性成本」——ESLint + Prettier + TypeScript ESLint + 各种插件,光 node_modules 就吃掉 200MB+,CI 里 lint 一个中型项目要跑 30 秒。Biome(原 Rome)作为 Rust 编写的统一工具链,v2.x 版本已经能覆盖 90% 的 lint 规则和 97% 的 Prettier 格式化场景,而速度快了 15-35 倍。如果你还在犹豫是否迁移,这篇文章会用真实数据帮你做决定。
🔧 一、为什么 ESLint + Prettier 的组合正在被淘汰?
📦 配置地狱:前端工具链的真实痛点
一个典型的 2024 年前端项目,代码质量工具链长这样:
eslint.config.js # ESLint 扁平配置
.prettierrc # Prettier 配置
.prettierrcignore # Prettier 忽略文件
.eslintignore # ESLint 忽略文件(旧版)
tsconfig.json # TypeScript 配置
.stylelintrc # CSS 检查(又一个工具)
💡 **提示:**ESLint v9 引入了扁平配置(Flat Config),废弃了
.eslintrc,但这本身就是一次破坏性迁移。很多团队还在两个配置格式之间挣扎。
这六个配置文件背后是至少 15 个 npm 包的依赖:
# 一个典型项目的 lint/format 依赖
eslint # 核心
@eslint/js # 推荐规则
typescript-eslint # TS 支持
eslint-plugin-react # React 规则
eslint-plugin-react-hooks # Hooks 规则
eslint-plugin-import # import 排序
prettier # 格式化
eslint-config-prettier # 关闭冲突规则
eslint-plugin-prettier # 把 Prettier 当 ESLint 规则跑
安装这些包的 node_modules 大小约 180-250MB,而 Biome 的单个二进制文件只有 8MB。
⏱️ 性能差距:不是优化问题,是语言级代差
我用一个真实的中型项目(约 3000 个 TypeScript 文件,120 万行代码)做了基准测试:
| 指标 | ESLint + Prettier | Biome 2.x | 差距 |
|---|---|---|---|
| 全量 lint | 28.4 秒 | 1.8 秒 | 15.8x |
| 全量 format | 18.6 秒 | 0.5 秒 | 37.2x |
| 增量 lint(改 1 个文件) | 3.2 秒 | 0.08 秒 | 40x |
| CI 安装时间 | 12 秒 | 0.8 秒 | 15x |
| node_modules 大小 | 220MB | 8MB | 27.5x |
⚡ **关键结论:**性能差距不是「快一点」,而是从「去倒杯咖啡等它跑完」变成了「保存文件的瞬间就完成了」。这对 CI/CD 流水线的效率提升是质变。
🤝 格式化与检查的冲突
ESLint 和 Prettier 长期存在的一个设计问题是规则冲突。ESLint 的 indent、semi、quotes 等格式化规则和 Prettier 的输出不一致,导致你需要 eslint-config-prettier 来关闭 ESLint 的格式化规则。
// ❌ 经典冲突场景:ESLint 说要加分号,Prettier 说不加
// eslint.config.js
export default [
{ rules: { semi: ['error', 'always'] } }, // ESLint: 必须有分号
];
// .prettierrc
{ "semi": false } // Prettier: 不要分号
// 结果:lint 和 format 互相打架,无限循环修复
Biome 的设计哲学完全不同——格式化和检查在同一个工具里共享 AST(抽象语法树),不存在解析两次、规则冲突的问题。
🚀 二、Biome 2.x 核心能力深度解析
🔍 格式化器:不只是「另一个 Prettier」
Biome 的格式化器是用 Rust 从零编写的,目标是 100% 兼容 Prettier 的输出。截至 v2.4,官方宣称兼容率达到 97%。这 3% 的差异主要在一些边缘场景:
// Biome 和 Prettier 输出不同的典型场景(极端边缘)
// 输入:
const obj = { a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, h: 8 };
// Prettier 输出(在某些 printWidth 下):
const obj = {
a: 1, b: 2, c: 3,
d: 4, e: 5, f: 6,
g: 7, h: 8,
};
// Biome 输出(可能略有不同):
const obj = {
a: 1,
b: 2,
c: 3,
d: 4,
e: 5,
f: 6,
g: 7,
h: 8,
};
📌 **记住:**如果你的团队对格式化输出有严格一致性要求(比如每次
git diff不能有无意义的格式变更),迁移前先在项目上跑一遍biome format --write,检查 diff 是否可接受。
Biome 格式化器支持的语言覆盖:
| 语言 | 格式化 | Lint | 备注 |
|---|---|---|---|
| JavaScript | ✅ | ✅ | 完全支持 |
| TypeScript | ✅ | ✅ | 完全支持 |
| JSX / TSX | ✅ | ✅ | 完全支持 |
| JSON / JSONC | ✅ | ✅ | JSON5 部分支持 |
| CSS | ✅ | ✅ | v2.x 新增完整支持 |
| HTML | ✅ | ❌ | v2.x 新增格式化 |
| Vue SFC | ⚠️ | ⚠️ | <script> 块内支持,模板有限 |
| Markdown | ❌ | ❌ | 计划中 |
🔬 Linter:规则覆盖率与自定义
Biome 的 linter 目前实现了约 270+ 条规则,覆盖了 ESLint 核心规则 + typescript-eslint + eslint-plugin-import 的大部分常用规则。但有些 ESLint 生态的插件规则(如 eslint-plugin-react-hooks 的精细规则)还没有完全对应。
// biome.json — 完整的 lint 配置示例
{
"$schema": "https://biomejs.dev/schemas/2.0/schema.json",
"organizeImports": {
"enabled": true
},
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"correctness": {
"noUnusedVariables": "warn",
"noUnusedImports": "error"
},
"style": {
"noNonNullAssertion": "warn",
"useConst": "error"
},
"suspicious": {
"noExplicitAny": "warn",
"noConsoleLog": "warn"
},
"nursery": {
"useSortedClasses": "off" // Tailwind CSS 类名排序
}
}
},
"formatter": {
"enabled": true,
"indentStyle": "space",
"indentWidth": 2,
"lineWidth": 100
},
"javascript": {
"formatter": {
"quoteStyle": "single",
"semicolons": "asNeeded",
"trailingCommas": "all"
}
}
}
💡 **提示:**Biome 的规则分组非常清晰——
correctness(正确性)、style(风格)、suspicious(可疑代码)、nursery(实验性规则)。比 ESLint 的off/warn/error三级之外还要理解插件的命名空间要直观得多。
🔌 Import 排序:内置杀手级功能
Biome 内置了 import 语句排序功能,这在 ESLint 生态里需要 eslint-plugin-import 或 @trivago/prettier-plugin-sort-imports 才能实现:
// ❌ 排序前 — import 顺序混乱
import { Button } from './components/Button';
import React from 'react';
import axios from 'axios';
import { useAuth } from '../hooks/useAuth';
import type { User } from '@/types';
import { format } from 'date-fns';
// ✅ Biome 自动排序后 — 按规则分组排列
import React from 'react';
import axios from 'axios';
import { format } from 'date-fns';
import { useAuth } from '../hooks/useAuth';
import type { User } from '@/types';
import { Button } from './components/Button';
配置方式:
// biome.json
{
"organizeImports": {
"enabled": true
},
"assist": {
"actions": {
"source": {
"organizeImports": "explicit"
}
}
}
}
🔀 三、从 ESLint + Prettier 迁移到 Biome:完整实战指南
📋 迁移前评估清单
在迁移之前,先确认你的项目是否适合:
- ✅ 纯 JavaScript/TypeScript 项目(React、Vue、Node.js 都行)
- ✅ 没有重度依赖 ESLint 自定义插件(如公司内部的 lint 规则插件)
- ✅ CSS/SCSS 检查不是核心需求(Biome 的 CSS lint 还在完善中)
- ❌ 大量使用
eslint-plugin-jsx-a11y(无障碍检查,Biome 暂无对应) - ❌ 依赖
eslint-plugin-storybook、eslint-plugin-cypress等垂直插件 - ❌ Vue 模板(
<template>)内的检查需求
🛠️ 分步迁移指南
第一步:安装 Biome 并生成配置
# 安装 Biome
npm install --save-dev --save-exact @biomejs/biome
# 初始化配置文件
npx @biomejs/biome init
第二步:对比格式化输出
# 先不写入,只检查差异
npx @biomejs/biome format --write src/
git diff --stat
# 如果 diff 行数在可接受范围内(通常 < 5%),继续
# 如果 diff 太多,调整 biome.json 的格式化选项来匹配 Prettier
第三步:替换 npm scripts
// ❌ 旧的 package.json scripts
{
"lint": "eslint src/ --ext .ts,.tsx",
"format": "prettier --write src/",
"format:check": "prettier --check src/",
"lint:fix": "eslint src/ --fix && prettier --write src/"
}
// ✅ 新的 package.json scripts
{
"lint": "biome lint src/",
"format": "biome format --write src/",
"check": "biome check src/",
"check:fix": "biome check --write src/"
}
⚠️ 警告:
biome check命令会同时执行 lint + format + import 排序。如果只想做格式化,用biome format;只想做 lint,用biome lint。不要把三个命令串行执行,biome check更高效。
第四步:配置 Git hooks
# 使用 lint-staged + husky(保留已有的 Git hooks 方案)
# .husky/pre-commit
npx lint-staged
// lint-staged.config.js
export default {
'*.{js,ts,jsx,tsx,json,css}': 'biome check --write --no-errors-on-unmatched',
};
或者更简洁的方案——用 Biome 官方推荐的 @biomejs/biome 的 --staged 模式:
# 直接在 pre-commit hook 中
npx @biomejs/biome check --write --staged
第五步:清理旧依赖
npm uninstall eslint @eslint/js typescript-eslint prettier \
eslint-config-prettier eslint-plugin-prettier \
eslint-plugin-import eslint-plugin-react-hooks
# 删除旧配置文件
rm .eslintrc* .prettierrc* eslint.config.js .eslintignore .prettierignore
🏗️ CI/CD 集成
# GitHub Actions 示例
name: Code Quality
on: [push, pull_request]
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: biomejs/setup-biome@v2
with:
version: latest
- run: biome ci .
💡 提示:
biome ci等价于biome check但会自动检测 CI 环境并输出 GitHub/GitLab 兼容的注释格式,PR 上会直接标注有问题的代码行。
⚠️ 四、Biome 的局限性与现实考量
🧩 生态差距
Biome 最大的短板不是性能,而是生态。ESLint 经过 10 年发展,有超过 1000 个插件。Biome 的规则虽然覆盖面广,但以下场景你可能还需要 ESLint:
| 场景 | Biome 支持 | 替代方案 |
|---|---|---|
| React Hooks 精细规则 | ⚠️ 部分 | 核心规则已覆盖,边缘规则缺失 |
| a11y 无障碍检查 | ❌ | 保留 eslint-plugin-jsx-a11y |
| 自定义 DSL 规则 | ❌ | ESLint 的 no-restricted-syntax 更灵活 |
| Markdown lint | ❌ | 用 markdownlint |
Vue <template> 内检查 |
⚠️ 有限 | 等待 Biome 后续版本 |
| Storybook 特定规则 | ❌ | 保留专用 ESLint 插件 |
🔄 混合使用方案
很多团队选择渐进式迁移——先用 Biome 处理格式化和基础 lint,保留 ESLint 处理 Biome 不支持的规则:
// biome.json — 只启用 Biome 有优势的规则
{
"linter": {
"rules": {
"correctness": { "recommended": true },
"style": { "recommended": true }
}
},
"formatter": { "enabled": true }
}
// eslint.config.js — 只保留 Biome 不支持的规则
export default [
{
plugins: { 'jsx-a11y': jsxA11y },
rules: {
'jsx-a11y/alt-text': 'error',
'jsx-a11y/aria-role': 'error',
// 只保留 Biome 不覆盖的规则
},
},
];
⚠️ **警告:**混合使用时,务必确保 Biome 和 ESLint 的格式化规则不冲突。在 Biome 中启用格式化,在 ESLint 中关闭所有格式化相关规则(
indent、semi、quotes等)。
🐛 Vue 项目特殊处理
Vue SFC 的迁移需要额外配置:
// biome.json — Vue 项目配置
{
"files": {
"include": ["src/**/*.vue"],
"ignore": []
},
"javascript": {
"formatter": {
"quoteStyle": "single",
"semicolons": "asNeeded"
}
}
}
但要注意,Biome 目前对 Vue SFC 的支持仅限于 <script> 和 <script setup> 块内的 JavaScript/TypeScript 代码,<template> 和 <style> 块的检查能力有限。
💡 五、最佳实践与决策框架
🎯 什么时候该迁移?
- ✅ 新项目直接用 Biome,没有历史包袱
- ✅ CI 时间超过 30 秒,优化收益明显
- ✅ 团队对现有 ESLint 配置感到痛苦
- ✅ 纯 JS/TS 项目,不需要特殊插件
- ❌ 大型项目重度依赖 ESLint 自定义插件
- ❌ Vue 模板检查是刚需
- ❌ 团队没有时间处理 3% 的格式化差异
📊 决策矩阵
| 维度 | ESLint + Prettier | Biome 2.x |
|---|---|---|
| 性能 | ⭐⭐ | ⭐⭐⭐⭐⭐ |
| 生态/插件 | ⭐⭐⭐⭐⭐ | ⭐⭐ |
| 配置复杂度 | ⭐⭐(复杂) | ⭐⭐⭐⭐⭐(简洁) |
| 格式化一致性 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐(97% 兼容) |
| CSS 支持 | ⭐⭐⭐⭐(Stylelint) | ⭐⭐⭐ |
| 维护成本 | ⭐⭐(多工具) | ⭐⭐⭐⭐⭐(单工具) |
| 学习曲线 | ⭐⭐⭐(熟悉) | ⭐⭐⭐⭐(需适应新配置) |
✅ 总结
Biome 2.x 不是「更好的 ESLint」,而是「替代整个工具链」的新范式。 它的核心价值不在于某个单一维度的提升,而是把格式化、lint、import 排序压缩成一个 8MB 的二进制文件、一个配置文件、一条命令。
我的建议是:新项目直接用 Biome,老项目评估插件依赖后渐进迁移。 性能差距已经大到不是「锦上添花」而是「改变工作流」的程度。3% 的格式化差异可以通过团队约定接受,但 15-35 倍的速度提升是实打实的生产力收益。
⚡ **关键结论:**如果你的项目是纯 JS/TS,且没有重度依赖 ESLint 生态的特殊插件——现在就可以迁移。等到 Biome 3.x 补齐 CSS 和 Vue 模板的短板,迁移窗口会更大,但先动手的团队已经享受到了 CI 时间从 30 秒降到 2 秒的红利。
🔗 相关工具推荐
- Biome 官方文档 — 完整的配置参考和迁移指南
- Biome Playground — 在线体验 Biome 的格式化和 lint 效果
- jsjson.com JSON 格式化工具 — 如果你需要快速格式化 JSON 数据
- VS Code Biome 扩展 — 编辑器实时 lint 和格式化