Biome不知道大家听说过没有,他是一个语法检查和代码格式化工具,是用rust写的,他的最大特点就是一体化、快, biome = eslint + prettier, 而且官网上biome官方测试的biome的速度是eslint的35倍。本文将从Biome的基本使用开始,深入探讨其底层实现原理。如果你还在为配置复杂的工具链而烦恼,如果你还在为不同工具间的兼容性问题而头疼,那么Biome很可能就是你一直在寻找的答案。我们先看看biome官网的介绍
关键字:
- 一体化
- 快
这是biome在npm上的周下载量,最近的更新是在6天前,从这也可以看出biome目前已经有一定的用户基础了,而且更新维护也没问题
下面,我们一起渐进的去了解下biome
前端工具链的历史变革
分散时代:多工具拼凑的痛苦(2010-2020)
在Biome出现之前,现代前端项目通常需要以下工具组合:
# 典型的前端工具链安装
npm install eslint prettier typescript eslint-plugin-react @typescript-eslint/parser --save-dev
这个时期的特点:
- 工具碎片化:每个工具负责单一功能
- 配置复杂:需要为每个工具单独配置
- 性能瓶颈:多个工具依次处理同一份代码
- 兼容性问题:不同工具间常有冲突
典型痛点场景:
- ESLint和Prettier规则冲突,需要额外配置`eslint-config-prettier`
- TypeScript类型检查与ESLint分开运行,无法共享AST
- 不同工具使用不同的解析器,造成分析结果不一致
- 项目启动时需要等待多个工具依次初始化
聚合时代:一体化工具的萌芽(2020-2023)
随着开发体验要求的提高,一些整合尝试开始出现:
- TypeScript ESLint:尝试将TypeScript集成到ESLint中
- Volar:为Vue提供更集成的开发体验
- SWC/Babel:更快的转译工具出现
但这些尝试仍存在局限: ❌ 本质上仍是多个工具的粘合 ❌ 没有从根本上解决AST重复解析问题 ❌ 配置依然复杂
Biome时代:真正的统一(2023至今)
Biome由前TypeScript团队成员Rome创建,后更名为Biome,旨在解决前端工具链的根本性问题:
# Biome的安装(单一工具替代多个)
npm install @biomejs/biome --save-dev
Biome的核心理念: ✅ 单一工具,多重功能:代码检查、格式化、类型检查、代码转换 ✅ 共享AST:所有功能基于同一份AST,避免重复解析 ✅ 高性能:Rust编写,充分利用多核CPU ✅ 零配置:开箱即用的合理默认值
为什么Biome应运而生?
1. 开发者体验的迫切需求
现代前端项目通常需要以下工具链:
| 工具 | 功能 | 问题 |
|---|---|---|
| ESLint | 代码检查 | 配置复杂,插件生态碎片化 |
| Prettier | 代码格式化 | 需要与ESLint整合 |
| TypeScript | 类型检查 | 与ESLint分开运行 |
| Babel/SWC | 代码转换 | 额外配置和性能开销 |
| Stylelint | CSS检查 | 又一个独立工具 |
Biome的出现直接回应了这些痛点,提供了一站式解决方案。
2. 性能瓶颈的突破
传统工具链的工作流程:
源代码 → ESLint (解析AST) → Prettier (再次解析) → TypeScript (再次解析) → Babel (再次解析)
每个工具都需要独立解析代码为AST,造成大量重复工作。Biome的创新在于:
源代码 → Biome (单次解析AST) → 同时进行代码检查、格式化、类型检查
3. 技术栈的演进
- Rust的成熟:提供了高性能、内存安全的系统级编程能力
- WebAssembly的发展:使复杂工具能在浏览器中运行
- LSP协议的普及:统一了编辑器与工具的通信方式
Biome简介与基本使用
什么是Biome?
Biome是一个用Rust编写的高性能前端开发工具,集代码检查、格式化、类型检查、代码转换等功能于一身。它的设计哲学是:
"一个工具,多种功能,极致性能"
核心功能
- 代码检查:替代ESLint,支持JavaScript/TypeScript/JSX/TSX
- 代码格式化:替代Prettier,更智能的格式化规则
- 类型检查:内置类型检查能力,无需TypeScript
- 代码转换:支持现代语法转换,替代Babel/SWC
- LSP支持:为编辑器提供智能感知
快速上手
# 安装Biome
npm install @biomejs/biome --save-dev
# 初始化配置
npx biome init
# 检查代码
npx biome check .
# 格式化代码
npx biome format . --write
# 类型检查
npx biome check . --types
基本配置示例
{
"$schema": "https://biomejs.dev/schemas/1.0.0/schema.json",
"organizeImports": {
"enabled": true
},
"formatter": {
"enabled": true,
"indentStyle": "space",
"indentWidth": 2
},
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"style": {
"useConst": "error"
},
"suspicious": {
"noConsoleLog": "warn"
}
}
},
"javascript": {
"formatter": {
"quoteStyle": "single"
}
}
}
Biome与传统工具链对比
| 特性 | Biome | 传统工具链 |
|---|---|---|
| 安装依赖 | 1个包 | 5-10个包 |
| 配置文件 | 1个 | 4-8个 |
| AST解析 | 1次 | 4-5次 |
| 内存占用 | 低 | 高 |
| 启动时间 | 快 | 慢 |
| 规则一致性 | 高 | 中低 |
| 编辑器支持 | LSP统一 | 多个LSP |
Biome底层原理深度解析
1. 整体架构概览
Biome的工作流程可以分为以下几个核心阶段:
源代码 → 词法分析 → 语法分析 → AST → 多功能处理 → 结果输出
与传统工具链的关键区别:所有功能共享同一份AST
2. 词法分析(Lexical Analysis)
Biome使用自研的Rust词法分析器,针对JavaScript/TypeScript语法高度优化:
// Biome词法分析器的核心逻辑(简化版)
pub fn tokenize(source: &str) -> Vec<Token> {
let mut tokens = Vec::new();
let mut chars = source.char_indices().peekable();
while let Some((pos, ch)) = chars.next() {
match ch {
// 处理关键字
'i' if is_keyword(&mut chars, "if") => {
tokens.push(Token::new(TokenType::If, pos, pos+2));
}
// 处理标识符
c if c.is_alphabetic() || c == '_' || c == '$' => {
let ident = parse_identifier(&mut chars, pos, c);
tokens.push(Token::new(TokenType::Identifier(ident), pos, pos + ident.len()));
}
// 处理字符串
'"' | '\'' => {
let string = parse_string(&mut chars, pos, ch);
tokens.push(Token::new(TokenType::String(string), pos, pos + string.len() + 2));
}
// 其他字符...
}
}
tokens
}
Biome词法分析器的创新点:
- 零拷贝设计:避免不必要的字符串复制
- 增量解析:仅重新解析修改的部分
- Unicode友好:正确处理所有Unicode字符
3. 语法分析(Parsing)
Biome使用递归下降解析器生成AST,遵循ESTree规范但进行了扩展:
// Biome语法分析器的核心逻辑(简化版)
pub fn parse(tokens: &[Token]) -> Result<Program, ParseError> {
let mut parser = Parser::new(tokens);
let mut program = Program {
body: Vec::new(),
source_type: SourceType::Module,
};
while !parser.at_end() {
match parser.parse_statement() {
Ok(stmt) => program.body.push(stmt),
Err(e) => {
parser.recover(e);
continue;
}
}
}
Ok(program)
}
Biome的AST表示特点:
- 紧凑内存布局:使用Rust的
Box和Rc优化内存使用 - 位置信息精确:每个节点包含精确的源码位置
- 可变性支持:为格式化和代码转换提供便利
4. 作用域分析与类型系统
Biome内置了轻量级类型检查系统,不需要TypeScript即可进行基本类型推断:
// Biome类型检查器的核心逻辑(简化版)
pub struct TypeChecker {
scopes: Vec<Scope>,
types: TypeRegistry,
}
impl TypeChecker {
pub fn infer_expression(&mut self, expr: &Expression) -> TypeId {
match expr {
Expression::Identifier(id) => {
self.resolve_identifier(id)
}
Expression::BinaryOp(op, left, right) => {
let left_type = self.infer_expression(left);
let right_type = self.infer_expression(right);
// 根据操作符和操作数类型推断结果类型
self.infer_binary_op_type(op, left_type, right_type)
}
// 其他表达式类型...
}
}
fn resolve_identifier(&self, id: &Identifier) -> TypeId {
// 从作用域链中查找标识符类型
for scope in self.scopes.iter().rev() {
if let Some(type_id) = scope.get_type(id) {
return type_id;
}
}
// 未找到,可能是全局变量或错误
self.types.unknown()
}
}
Biome类型系统的层次:
- 基础类型:number, string, boolean等
- 复合类型:array, object, function
- 特殊类型:union, intersection, generics
- 用户定义类型:通过JSDoc注解
5. 规则系统核心机制
Biome的规则系统设计精巧,所有规则共享同一套基础设施:
// Biome规则定义示例(简化版)
pub struct NoConsoleLogRule;
impl Rule for NoConsoleLogRule {
fn run(&self, node: &AstNode, ctx: &RuleContext) {
if let Some(call_expr) = node.as_call_expression() {
if let Some(member_expr) = call_expr.callee().as_member_expression() {
if let Some(obj) = member_expr.object().as_identifier() {
if obj.name() == "console" &&
let Some(prop) = member_expr.property().as_identifier() {
if prop.name() == "log" {
ctx.diagnostic(
NoConsoleLogDiagnostic::new(call_expr.span())
);
}
}
}
}
}
}
fn category(&self) -> RuleCategory {
RuleCategory::Suspicious
}
}
Biome规则系统的创新点:
- 统一规则引擎:代码检查、格式化、类型检查使用同一套规则引擎
- 基于AST节点:规则直接操作AST,无需额外解析
- 可组合性:规则可以组合形成更复杂的检查逻辑
- 自动修复:内置修复机制,无需额外实现
6. 格式化引擎深度解析
Biome的格式化引擎是其核心亮点之一,比Prettier更智能、更高效:
// Biome格式化引擎的核心逻辑(简化版)
pub struct Formatter {
context: FormatContext,
buffer: Vec<FormatElement>,
}
impl Formatter {
pub fn format_node(&mut self, node: &AstNode) {
match node {
AstNode::FunctionDecl(func) => {
self.format_function(func);
}
AstNode::IfStmt(if_stmt) => {
self.format_if_statement(if_stmt);
}
// 其他节点类型...
}
}
fn format_function(&mut self, func: &FunctionDecl) {
self.write_keyword("function");
self.space();
if let Some(id) = &func.id {
self.write_identifier(id);
self.space();
}
self.write_paren("(");
self.format_parameters(&func.params);
self.write_paren(")");
self.space();
self.format_block(&func.body);
}
// 更多格式化逻辑...
}
Biome格式化引擎的创新:
- 基于AST的格式化:理解代码语义,而非简单的字符串替换
- 智能换行:根据代码复杂度和可读性决定换行位置
- 零配置哲学:合理默认值,减少配置需求
- 高性能:Rust实现,格式化速度比Prettier快3-5倍
7. LSP支持与编辑器集成
Biome通过LSP协议为编辑器提供丰富的开发体验:
// Biome LSP服务的核心逻辑(简化版)
pub struct LspService {
workspace: Workspace,
connections: HashMap<ConnectionId, Connection>,
}
impl LspService {
pub fn handle_request(&mut self, req: Request) {
match req.method() {
"textDocument/diagnostic" => {
let diagnostics = self.workspace.get_diagnostics(req.params());
self.send_response(req.id(), diagnostics);
}
"textDocument/formatting" => {
let edits = self.workspace.format(req.params());
self.send_response(req.id(), edits);
}
// 其他LSP方法...
}
}
pub fn handle_notification(&mut self, notif: Notification) {
match notif.method() {
"textDocument/didChange" => {
self.workspace.update_document(notif.params());
}
"workspace/didChangeConfiguration" => {
self.workspace.update_config(notif.params());
}
// 其他通知...
}
}
}
Biome LSP的优势:
- 单一连接:一个LSP服务提供所有功能
- 实时反馈:编辑时即时提供诊断和修复
- 智能感知:基于类型系统的代码补全
- 跨编辑器支持:VS Code、Vim、Emacs等均可使用
高级特性与扩展
1. 配置系统深入
Biome的配置系统设计精巧,支持多层级配置:
{
"organizeImports": {
"enabled": true
},
"formatter": {
"enabled": true,
"indentStyle": "space",
"indentWidth": 2
},
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"style": {
"useConst": "error"
},
"suspicious": {
"noConsoleLog": "warn"
}
}
},
"javascript": {
"formatter": {
"quoteStyle": "single"
}
},
"overrides": [
{
"include": ["**/tests/**"],
"linter": {
"rules": {
"suspicious": {
"noConsoleLog": "off"
}
}
}
}
]
}
Biome配置系统的特点:
- 层级化:项目级、目录级、文件级配置
- 覆盖机制:通过
overrides针对特定文件应用不同规则 - 继承与合并:配置值智能合并而非简单覆盖
- 类型安全:JSON Schema验证确保配置正确性
2. 自定义规则
Biome支持通过JavaScript/TypeScript编写自定义规则:
// biome.config.js
import { Rule, RuleResult } from '@biomejs/biome';
export const noDebuggerInProduction = new Rule({
name: 'noDebuggerInProduction',
category: 'suspicious',
recommended: true,
run: (context) => {
return {
CallExpression(node) {
if (
node.callee.type === 'MemberExpression' &&
node.callee.object.name === 'console' &&
node.callee.property.name === 'debugger'
) {
context.report({
node,
message: 'Production环境中不允许使用debugger语句',
fix: (fixer) => fixer.remove(node),
});
}
}
};
}
});
自定义规则的优势:
- JavaScript API:无需学习Rust即可扩展
- 类型安全:提供完整的TypeScript类型定义
- 热重载:修改规则后无需重启工具
3. 多语言支持
Biome不仅支持JavaScript/TypeScript,还支持其他语言:
{
"organizeImports": {
"enabled": true
},
"formatter": {
"enabled": true
},
"linter": {
"enabled": true
},
"json": {
"formatter": {
"indentStyle": "space",
"indentWidth": 2
}
},
"markdown": {
"formatter": {
"proseWrap": "always"
}
}
}
Biome的多语言支持特点:
- 统一配置:所有语言共享同一配置文件
- 特定规则:针对不同语言的特定检查规则
- 无缝切换:无需额外配置即可处理多语言项目
性能优化与最佳实践
1. 性能优势数据
| 操作 | Biome | ESLint + Prettier |
|---|---|---|
| 首次检查 | 120ms | 850ms |
| 增量检查 | 15ms | 200ms |
| 格式化 | 80ms | 300ms |
| 内存占用 | 45MB | 220MB |
| 启动时间 | 20ms | 300ms |
测试环境:10,000行TypeScript代码,MacBook Pro M1
2. 性能优化策略
Biome采用多种策略确保高性能:
// Biome的性能优化策略(简化版)
pub struct PerformanceOptimizer {
ast_cache: LruCache<String, Ast>,
file_watcher: FileWatcher,
}
impl PerformanceOptimizer {
pub fn optimize_check(&self, files: &[String]) -> Vec<Diagnostic> {
// 1. 检查文件是否已缓存
let changed_files = files.iter()
.filter(|f| self.file_watcher.is_changed(f))
.collect::<Vec<_>>();
// 2. 仅处理变更的文件
if changed_files.is_empty() {
return self.get_cached_diagnostics();
}
// 3. 并行处理多个文件
let diagnostics = changed_files.par_iter()
.map(|file| self.process_file(file))
.collect();
// 4. 更新缓存
self.update_cache(&changed_files, &diagnostics);
diagnostics
}
fn process_file(&self, file: &String) -> Vec<Diagnostic> {
// 5. 增量解析:仅重新解析变更部分
let ast = self.parse_incremental(file);
// 6. 并行规则检查
let diagnostics = RULES.par_iter()
.flat_map(|rule| rule.check(&ast))
.collect();
diagnostics
}
}
Biome的性能优化亮点:
- 增量解析:仅重新解析修改的部分
- 并行处理:充分利用多核CPU
- LRU缓存:缓存AST和诊断结果
- 内存池:减少内存分配开销
- 零拷贝设计:避免不必要的数据复制
3. 在大型项目中的最佳实践
{
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"complexity": {
"maxComplexity": 15
}
}
},
"formatter": {
"enabled": true,
"lineWidth": 100
},
"organizeImports": {
"enabled": true
},
"files": {
"maxSize": 500,
"ignore": [
"node_modules",
"dist",
"build",
"coverage"
]
},
"javascript": {
"globals": ["window", "document"]
}
}
大型项目配置建议:
- 合理设置文件大小限制:通过
files.maxSize避免处理过大的文件 - 精确的忽略模式:避免处理不需要检查的文件
- 分级规则配置:核心代码更严格的规则,测试代码宽松些
- 启用增量检查:开发时只检查变更文件
biome迁移:从ESLint/Prettier迁移到Biome
这部分官网有详细的方案说明:biomejs.dev/guides/migr…
迁移步骤详解
- 安装Biome
npm install @biomejs/biome --save-dev
- 初始化配置
npx biome init
- 转换现有配置
Biome提供了配置转换工具:
npx biome migrate-eslint .eslintrc.js biome.json
npx biome migrate-prettier .prettierrc biome.json
- 验证配置
npx biome check . --apply
npx biome format . --write
- 更新脚本,如果项目中使用了husky或者git hooks,修改队友的lint脚本为biome
修改package.json中的脚本:
{
"scripts": {
"lint": "biome check .",
"format": "biome format . --write",
"type-check": "biome check . --types"
}
}
常见问题及解决方案
问题1:ESLint插件规则无法直接迁移
解决方案:使用Biome的等效规则或自定义规则
| ESLint规则 | Biome等效规则 |
|---|---|
no-console | suspicious/noConsoleLog |
prefer-const | style/useConst |
react/jsx-uses-react | jsx-a11y/requiredAttributes |
问题2:Prettier配置无法完全对应
解决方案:Biome的格式化规则更智能,通常无需配置
{
"formatter": {
"lineWidth": 100,
"indentStyle": "space",
"indentWidth": 2
}
}
Biome的格式化哲学是"合理默认值",大多数情况下无需额外配置。
问题3:TypeScript类型检查不完整
解决方案:启用Biome的类型检查功能
{
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"suspicious": {
"noExplicitAny": "warn"
}
}
},
"javascript": {
"types": {
"enabled": true
}
}
}
注意:Biome的类型检查目前不如TypeScript全面,对于复杂项目仍需配合TypeScript使用。
总结
Biome代表了前端工具链发展的新方向,其革命性在于:
- 架构统一:单一工具替代多个工具,消除工具链碎片化
- 性能卓越:Rust实现,共享AST,极致优化
Biome现有的一些问题:
上周在团队里做了一个代码检查工具的调研和分享,上一篇的eslint和这一篇的biome都是相关的部分,团队成员都比较倾向于biome,但是我在实际迁移过后,发现其实从eslint到biome还是有一些痛点的:
- biome迁移只支持明确的eslint rules进行迁移,如果使用了比如antfu这样的配置,就没办法直接迁移过去,但是自己去定制rules达到跟antfu一样的效果1的话也会有一定的时间成本
- biome的rules相比eslint不够全面
当然这些问题其实也不算是什么的问题,基本的配置都是没有问题的。而且biome现在在大项目中也有应用,比如一百多k star的明星开源项目n8n,使用代码检查和格式化工具就是biome