名称: bun 描述: 使用Bun JavaScript运行时构建快速应用程序。适用于创建Bun项目、使用Bun API、捆绑、测试或优化Node.js替代方案。触发词:Bun, Bun runtime, bun.sh, bunx, Bun serve, Bun test, JavaScript runtime。
Bun - 快速的JavaScript运行时
使用Bun的一体化工具包构建和运行JavaScript/TypeScript应用程序。
快速开始
# 安装Bun(macOS、Linux、WSL)
curl -fsSL https://bun.sh/install | bash
# Windows
powershell -c "irm bun.sh/install.ps1 | iex"
# 创建新项目
bun init
# 直接运行TypeScript(无需构建步骤!)
bun run index.ts
# 安装包(比npm更快)
bun install
# 运行脚本
bun run dev
包管理
# 安装依赖
bun install # 从package.json安装所有
bun add express # 添加依赖
bun add -d typescript # 添加开发依赖
bun add -g serve # 添加全局包
# 移除包
bun remove express
# 更新包
bun update
# 运行包二进制文件
bunx prisma generate # 类似npx但更快
bunx create-next-app
# 锁文件
bun install --frozen-lockfile # CI模式
bun.lockb vs package-lock.json
# Bun使用二进制锁文件(bun.lockb)- 更快
# 为兼容性生成yarn.lock:
bun install --yarn
# 从其他锁文件导入
bun install # 自动检测package-lock.json、yarn.lock
Bun运行时
运行文件
# 运行任何文件
bun run index.ts # TypeScript
bun run index.js # JavaScript
bun run index.jsx # JSX
# 监视模式
bun --watch run index.ts
# 热重载
bun --hot run server.ts
内置API
// 文件I/O(超快)
const file = Bun.file('data.json');
const content = await file.text();
const json = await file.json();
const bytes = await file.arrayBuffer();
// 写入文件
await Bun.write('output.txt', 'Hello, Bun!');
await Bun.write('data.json', JSON.stringify({ key: 'value' }));
await Bun.write('image.png', await fetch('https://example.com/img.png'));
// 文件元数据
const file = Bun.file('data.json');
console.log(file.size); // 字节
console.log(file.type); // MIME类型
console.log(file.lastModified);
// 全局文件
const glob = new Bun.Glob('**/*.ts');
for await (const file of glob.scan('.')) {
console.log(file);
}
HTTP服务器
// 简单服务器
const server = Bun.serve({
port: 3000,
fetch(req) {
const url = new URL(req.url);
if (url.pathname === '/') {
return new Response('Hello, Bun!');
}
if (url.pathname === '/json') {
return Response.json({ message: 'Hello!' });
}
return new Response('Not Found', { status: 404 });
},
});
console.log(`服务器运行在 http://localhost:${server.port}`);
高级服务器
Bun.serve({
port: 3000,
// 主请求处理程序
async fetch(req, server) {
const url = new URL(req.url);
// WebSocket升级
if (url.pathname === '/ws') {
const upgraded = server.upgrade(req, {
data: { userId: '123' }, // 附加数据到socket
});
if (upgraded) return undefined;
}
// 静态文件
if (url.pathname.startsWith('/static/')) {
const filePath = `./public${url.pathname}`;
const file = Bun.file(filePath);
if (await file.exists()) {
return new Response(file);
}
}
// JSON API
if (url.pathname === '/api/data' && req.method === 'POST') {
const body = await req.json();
return Response.json({ received: body });
}
return new Response('Not Found', { status: 404 });
},
// WebSocket处理程序
websocket: {
open(ws) {
console.log('客户端连接:', ws.data.userId);
ws.subscribe('chat'); // 发布/订阅
},
message(ws, message) {
// 广播给所有订阅者
ws.publish('chat', message);
},
close(ws) {
console.log('客户端断开连接');
},
},
// 错误处理
error(error) {
return new Response(`错误:${error.message}`, { status: 500 });
},
});
WebSocket客户端
const ws = new WebSocket('ws://localhost:3000/ws');
ws.onopen = () => {
ws.send('Hello, server!');
};
ws.onmessage = (event) => {
console.log('收到:', event.data);
};
Bun API
SQLite(内置)
import { Database } from 'bun:sqlite';
const db = new Database('mydb.sqlite');
// 创建表
db.run(`
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT UNIQUE
)
`);
// 插入
const insert = db.prepare('INSERT INTO users (name, email) VALUES (?, ?)');
insert.run('Alice', 'alice@example.com');
// 查询
const query = db.prepare('SELECT * FROM users WHERE id = ?');
const user = query.get(1);
// 所有结果
const allUsers = db.prepare('SELECT * FROM users').all();
// 事务
const insertMany = db.transaction((users) => {
for (const user of users) {
insert.run(user.name, user.email);
}
});
insertMany([
{ name: 'Bob', email: 'bob@example.com' },
{ name: 'Charlie', email: 'charlie@example.com' },
]);
密码哈希(内置)
// 哈希密码
const hash = await Bun.password.hash('mypassword', {
algorithm: 'argon2id', // 或 'bcrypt'
memoryCost: 65536, // 64 MB
timeCost: 2,
});
// 验证密码
const isValid = await Bun.password.verify('mypassword', hash);
生成进程
// 生成进程
const proc = Bun.spawn(['ls', '-la'], {
cwd: '/home/user',
env: { ...process.env, MY_VAR: 'value' },
stdout: 'pipe',
});
const output = await new Response(proc.stdout).text();
console.log(output);
// 同步生成
const result = Bun.spawnSync(['echo', 'hello']);
console.log(result.stdout.toString());
// Shell命令
const { stdout } = Bun.spawn({
cmd: ['sh', '-c', 'echo $HOME'],
stdout: 'pipe',
});
哈希与加密
// 哈希字符串
const hash = Bun.hash('hello world'); // Wyhash(快速)
// 加密哈希
const sha256 = new Bun.CryptoHasher('sha256');
sha256.update('data');
const digest = sha256.digest('hex');
// 一行代码
const md5 = Bun.CryptoHasher.hash('md5', 'data', 'hex');
// HMAC
const hmac = Bun.CryptoHasher.hmac('sha256', 'secret-key', 'data', 'hex');
捆绑器
# 为浏览器打包
bun build ./src/index.ts --outdir ./dist
# 打包选项
bun build ./src/index.ts \
--outdir ./dist \
--minify \
--sourcemap \
--target browser \
--splitting \
--entry-naming '[dir]/[name]-[hash].[ext]'
构建API
const result = await Bun.build({
entrypoints: ['./src/index.ts'],
outdir: './dist',
minify: true,
sourcemap: 'external',
target: 'browser', // 'bun' | 'node' | 'browser'
splitting: true,
naming: {
entry: '[dir]/[name]-[hash].[ext]',
chunk: '[name]-[hash].[ext]',
asset: '[name]-[hash].[ext]',
},
external: ['react', 'react-dom'],
define: {
'process.env.NODE_ENV': JSON.stringify('production'),
},
loader: {
'.png': 'file',
'.svg': 'text',
},
});
if (!result.success) {
console.error('构建失败:', result.logs);
}
测试
// test.ts
import { describe, test, expect, beforeAll, afterAll, mock } from 'bun:test';
describe('数学操作', () => {
test('加法', () => {
expect(1 + 1).toBe(2);
});
test('数组包含', () => {
expect([1, 2, 3]).toContain(2);
});
test('对象匹配', () => {
expect({ name: 'Alice', age: 30 }).toMatchObject({ name: 'Alice' });
});
test('异步测试', async () => {
const result = await Promise.resolve(42);
expect(result).toBe(42);
});
test('抛出错误', () => {
expect(() => {
throw new Error('fail');
}).toThrow('fail');
});
});
// 模拟
const mockFn = mock(() => '模拟');
mockFn();
expect(mockFn).toHaveBeenCalled();
// 模拟模块
mock.module('./database', () => ({
query: mock(() => [{ id: 1 }]),
}));
# 运行测试
bun test
# 监视模式
bun test --watch
# 特定文件
bun test user.test.ts
# 覆盖率
bun test --coverage
Node.js兼容性
// 大多数Node.js API开箱即用
import fs from 'fs';
import path from 'path';
import { createServer } from 'http';
import express from 'express';
// Bun实现Node.js API
const data = fs.readFileSync('file.txt', 'utf-8');
const fullPath = path.join(__dirname, 'file.txt');
// Express有效!
const app = express();
app.get('/', (req, res) => res.send('Hello!'));
app.listen(3000);
Node.js vs Bun API
// Node.js方式
import { readFile } from 'fs/promises';
const content = await readFile('file.txt', 'utf-8');
// Bun方式(更快)
const content = await Bun.file('file.txt').text();
// Node.js加密
import crypto from 'crypto';
const hash = crypto.createHash('sha256').update('data').digest('hex');
// Bun方式(更快)
const hash = Bun.CryptoHasher.hash('sha256', 'data', 'hex');
环境变量
// .env文件支持(内置,无需dotenv!)
// .env
// DATABASE_URL=postgres://localhost/db
// API_KEY=secret
// 访问环境变量
const dbUrl = Bun.env.DATABASE_URL;
const apiKey = process.env.API_KEY; // 同样有效
// bunfig.toml用于Bun配置
// [run]
// preload = ["./setup.ts"]
HTTP客户端
// Fetch(在Bun中优化)
const response = await fetch('https://api.example.com/data', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer token',
},
body: JSON.stringify({ key: 'value' }),
});
const data = await response.json();
// 流式响应
const response = await fetch('https://api.example.com/stream');
const reader = response.body?.getReader();
while (true) {
const { done, value } = await reader!.read();
if (done) break;
console.log(new TextDecoder().decode(value));
}
项目结构
my-bun-project/
├── src/
│ ├── index.ts # 入口点
│ ├── routes/
│ │ └── api.ts
│ └── lib/
│ └── database.ts
├── tests/
│ └── index.test.ts
├── public/
│ └── 静态文件
├── package.json
├── bunfig.toml # Bun配置(可选)
├── tsconfig.json
└── .env
bunfig.toml
[install]
# 默认使用精确版本
exact = true
# 注册表
registry = "https://registry.npmjs.org"
[run]
# 在`bun run`之前运行的脚本
preload = ["./instrumentation.ts"]
[test]
# 测试配置
coverage = true
coverageDir = "coverage"
[bundle]
# 默认打包配置
minify = true
sourcemap = "external"
性能比较
| 操作 | Node.js | Bun | 速度提升 |
|---|---|---|---|
| 启动时间 | ~40ms | ~7ms | 5.7倍 |
| 包安装 | ~10s | ~1s | 10倍 |
| 文件读取 | 基准 | 更快 | 10倍 |
| HTTP服务器 | 基准 | 更快 | 4倍 |
| SQLite | 外部 | 内置 | 3倍 |
| TypeScript | 需要编译 | 原生 | ∞ |
资源
- Bun文档: https://bun.sh/docs
- Bun API参考: https://bun.sh/docs/api
- Bun Discord: https://bun.sh/discord
- GitHub: https://github.com/oven-sh/bun