Biome — JS/TS 工具链一体化(Rust 写的 linter+formatter)
是什么
Biome 是用 Rust 重写的 JavaScript / TypeScript 工具链,把 ESLint(找代码问题)、Prettier(统一代码格式)、import sorter(整理 import 顺序)三件事塞进同一个二进制。日常类比:以前你家厨房有 4 个独立小电器(榨汁机、搅拌机、料理机、研磨杯),现在变成一台多功能料理机——少占空间、共享马达、洗一次就行。
你只要写一行:
npx @biomejs/biome check ./src一个命令同时做:扫语法错、按规则格式化、排好 import 顺序、给出诊断报告——速度比 ESLint + Prettier 跑一遍快 25-100 倍。截至 2026-05,v2.4.16,450+ 条规则,24.8k stars。
为什么重要
不理解 Biome 的设计选择,下面这些事都没法解释:
- 为什么 ESLint + Prettier 已经存在 10 年,还能被一个新工具一战打穿
- 为什么”性能优势”不是核心卖点——真正的杠杆是”共享一份 AST”
- 为什么 Biome 故意限制插件生态——这不是功能缺失,是判断
- 为什么 Vite 团队另起炉灶做 oxlint 而不是直接用 Biome——同流派的工具是怎么分流的
核心要点
Biome 的设计选择可以拆成 三条:
-
一份 AST,多个 pass 共享:源码只 parse 一次,linter / formatter / import sorter 全部读同一棵语法树。类比:开会做会议纪要,一个人记,所有人共用,而不是 4 个人各自做笔记。
-
配置统一:一个
biome.json替代.eslintrc+.prettierrc+.eslintignore+.prettierignore四件套。类比:把 4 张分散的卡塞进一张身份证。 -
故意不追求 100% 兼容:97% 兼容 Prettier 输出,450+ 条规则覆盖 ESLint 高价值部分。剩下的 3% / 自定义规则要么改写、要么放弃。类比:搬家时只带 90% 常用物品,省下的搬运成本远超那 10%。
这三条加起来叫 “整合优于单点” 的判断——是一种产品哲学,不是单纯的技术胜利。
实践案例
案例 1:5 分钟跑通
mkdir biome-demo && cd biome-demonpm init -ynpm install --save-dev --save-exact @biomejs/biomenpx @biomejs/biome init # 生成 biome.jsonecho 'const x=1;var y=2' > demo.jsnpx @biomejs/biome check --write demo.jscat demo.js# const x = 1;# const y = 2;逐部分解释:
init生成默认配置(biome.json,约 10 行)check --write一次跑完 lint + format + auto-fixvar y被自动改成const y(noVar 规则的 unsafe fix)- 整个过程没装 ESLint、没装 Prettier、没装任何 plugin
案例 2:lineWidth 改一处看字节差
biome.json 里把 "lineWidth": 80 改成 "lineWidth": 120,对同一份长对象字面量跑 format:
// lineWidth: 80(容不下 → 整个对象 break)const obj = { foo: 1, bar: 2, baz: [1, 2, 3 /* ... */], nested: { a: 1, b: 2 },};
// lineWidth: 120(同一对象塞回一行)const obj = { foo: 1, bar: 2, baz: [1, 2, 3 /* ... */], nested: { a: 1, b: 2 } };输出在两个稳定状态间切换——没有”换 3 个字段、保留 2 个不换”的中间态。这是 Wadler 1998 paper 的 group atom 性质(见 wadler-prettier)。
案例 3:CI 里替代 ESLint + Prettier
旧 CI:
- run: npx eslint . # ~8 秒- run: npx prettier --check . # ~3 秒换成:
- run: npx biome ci . # ~0.5 秒(同等规模 1000 文件 TS 项目)biome ci 是给 CI 优化的子命令——只读、不写、错误码 1 退出。整体 lint 阶段从 11 秒缩到 1 秒以内。
踩过的坑
- 97% 兼容不是 100%:那 3% 集中在 JSX、TS decorators、object literal 边界场景——下游工具如果硬吃 Prettier 输出,迁移会炸。
- 复杂 ESLint 自定义规则没等价:内部 lint 规则 / 复杂 plugin 要重写,迁移成本可能 > 性能收益。
- plugin 系统故意被限制:只支持 GritQL pattern 匹配,不支持任意 Rust plugin——这不是 bug 是判断,但被卡过的人会觉得是缺失。
- 默认配置不一定合团队:
lineWidth: 80/indentStyle: tab大概率你会想改,别以为”零配置开箱即用”等于”什么都不用动”。
适用 vs 不适用场景
适用:
- 新项目起步——30 分钟搭好、一个文件配置完
- 已有 ESLint + Prettier 项目想加速——可双跑过渡
- pre-commit hook(
lint-staged + biome check)替换原 ESLint hook - CI 里把 lint job 从 30 秒缩到 1 秒以下
不适用:
- 重度依赖 ESLint 自定义规则的大型项目——迁移成本太高
- 必须 100% Prettier 兼容(下游工具吃 Prettier 输出格式)——3% 差异可能炸
- 需要写 plugin 深度扩展核心——Biome 故意限制
- 只想要”更快的 Prettier”不要 lint——用 dprint 更纯粹
历史小故事(可跳过)
- 2017 年:前 Babel 作者发起 Rome 项目——目标是做完整 web toolchain(含 bundler)。野心过大,进展缓慢。
- 2022 年:Rome 团队组建公司,宣布用 Rust 全量重写。
- 2023 年 8 月:公司倒闭。社区 fork 出 Biome,由 maintainer 群体接管。
- 2024 年:Biome 1.0 发布——只做 lint + format + import sort,砍掉 bundler 等一半野心。
- 2026 年 5 月:v2.4.16,Vercel / Astro / Tailwind 等都在用。
→ 知道这个背景才理解:Biome 不是凭空冒出,是一群人从废墟里把可保留的部分抢救出来。砍野心是它活下来的关键。
学到什么
- 设计胜过性能:Biome 真正的杠杆不是 Rust,是”一份 AST + 一个配置”——这是产品判断,不是技术优势
- 整合优于单点最强:dprint 在 format 单点更纯粹,oxlint 在 lint 单点更快,但 Biome 把两者合一拿到了 80% 用户
- 故意限制 = 设计:不开放任意 plugin、不追求 100% 兼容——这些”限制”换来的是迭代速度和体验一致性
- 救活项目的关键是砍野心:Rome 想做完整 toolchain 死了,Biome 砍到 lint+format 活了
延伸阅读
- Biome 官方文档 —— 最新规则列表、配置参考、迁移指南
- Wadler 1998 — A Prettier Printer —— Biome formatter IR 的理论根
- Biome blog —— Rome 倒闭 → Biome 重生的项目治理演化
- oxlint 源码 —— 同代竞品(只做 lint)的设计差异
- wadler-prettier —— Wadler 论文的零基础解读
关联
- wadler-prettier —— Biome formatter IR 直接来自这篇 paper(group / soft_line_break / atom 性质)
- esbuild —— 同样用编译型语言(Go)重写 JS 工具链,思路并行
- swc —— Rust 写的 JS 编译器,和 Biome 同流派但分工不同(swc 做 transform,biome 做 lint+format)
- vite —— 现代前端构建,常和 Biome 搭配做 lint job
- turborepo —— monorepo 缓存工具,Biome 在 monorepo 场景里更省时间
- hindley-milner —— Biome 不做类型检查(交给 tsc),但类型推导是相邻领域
反向链接
- ast-grep —— ast-grep — 按语法树搜代码、改代码的命令行工具
- changesets —— changesets — 让每个 PR 自带版本号 bump 声明
- dust —— dust — du 的可视化替代,按目录大小排树状条形图
- esbuild —— esbuild — 用 Go 写的极速 JS bundler
- geany —— Geany — GTK 轻量 IDE
- gh —— gh — GitHub 官方命令行
- glab —— glab — GitLab 官方命令行
- hindley-milner —— Hindley-Milner — 编译器自己猜变量类型
- just —— just — 把 make 拆成两半,只留 ‘命令编排’ 那一半
- lighthouse —— Lighthouse — Google 出品的网页质量审计工具
- lightningcss —— lightningcss — 用 Rust 把 CSS 工具链一遍跑完的编译器
- nanostores —— nanostores — 不到 1 KB 的”框架无关”状态库
- notepad-plus-plus —— Notepad++ — Windows 国民文本编辑器
- oxc —— oxc — Rust 写一整套 JS/TS 工具链的勇气
- plug —— Plug — 把 HTTP 中间件写成『conn 进 conn 出』的纯函数
- ripgrep —— ripgrep — Rust 写的现代 grep
- rspack —— rspack — 用 Rust 重写 webpack 的内核,但留下整个 plugin 生态
- sd —— sd — 直觉语法的 sed 替代品(Rust 写的 find-and-replace)
- shadcn-ui —— shadcn/ui — 把 React 组件从 npm 包变成”源码 + CLI 协议”
- sharp —— sharp — 让 Node.js 处理图像快到不像 JS
- shfmt —— shfmt — Shell 脚本的 gofmt(用 Go 写的统一格式化器)
- stylex —— StyleX — 编译期把样式拍扁成原子 className 的 CSS-in-JS
- swc —— SWC — Rust 写的 TS/JS 编译器
- task —— Task — 用 YAML 写一份跨平台的 ‘项目命令清单’
- turborepo —— Turborepo — 让 monorepo 学会”哪些活已经干过了不要再干”
- vite —— Vite — 浏览器自己加载源码的构建工具
- volta —— Volta — cd 进项目就自动换 Node 版本的工具链管理器
- vscodium —— VSCodium — 去微软遥测的 VS Code 干净构建
- wadler-prettier —— Wadler Prettier — 函数式优雅打印器
- xh —— xh — HTTPie 的 Rust 重写版