Bun 是用 Zig 语言写的 JavaScript 运行时,目标是替代 Node.js。但它不仅仅是运行时——内置了打包器、转译器、包管理器和测试运行器。一个工具搞定所有事情。
Bun 的速度确实惊人。官方宣称比 Node.js 快 4 倍,比 Deno 快 2 倍。安装依赖比 npm 快 25 倍。这些数字虽然有营销成分,但实际体验确实很快。
安装#
# macOS / Linuxcurl -fsSL https://bun.sh/install | bash
# Windows (PowerShell)powershell -c "irm bun.sh/install.ps1 | iex"
# 或者用 npmnpm install -g bun
# 验证安装bun --version作为运行时#
运行 JavaScript/TypeScript#
Bun 原生支持 TypeScript 和 JSX,不需要任何配置:
# 直接运行 TypeScriptbun run index.ts
# 运行 JSXbun run app.tsx兼容 Node.js#
Bun 兼容大部分 Node.js API:
// 这些都能正常工作import { readFile } from 'fs/promises'import path from 'path'import http from 'http'
const content = await readFile('./package.json', 'utf8')console.log(content)Bun 特有 API#
Bun 提供了一些更简洁的 API:
// 文件操作const file = Bun.file('./data.json')const content = await file.text()const json = await file.json()
// 写入文件await Bun.write('./output.txt', 'Hello Bun!')
// HTTP 服务器(比 Node.js 简洁得多)Bun.serve({ port: 3000, fetch(request) { return new Response('Hello World!') },})内置打包器#
Bun 自带打包功能,速度极快。
基本使用#
# 打包入口文件bun build ./src/index.ts --outdir ./dist
# 指定目标环境bun build ./src/index.ts --outdir ./dist --target browser
# 生成 sourcemapbun build ./src/index.ts --outdir ./dist --sourcemap
# 压缩输出bun build ./src/index.ts --outdir ./dist --minifyJavaScript API#
const result = await Bun.build({ entrypoints: ['./src/index.tsx'], outdir: './dist', target: 'browser', minify: true, sourcemap: 'external', splitting: true, format: 'esm',})
if (!result.success) { console.error('构建失败:') for (const log of result.logs) { console.error(log) }} else { console.log('构建成功!') for (const output of result.outputs) { console.log(output.path) }}配置选项#
await Bun.build({ // 入口文件 entrypoints: ['./src/index.ts', './src/worker.ts'],
// 输出目录 outdir: './dist',
// 输出格式:esm | cjs | iife format: 'esm',
// 目标环境:browser | bun | node target: 'browser',
// 代码分割 splitting: true,
// 压缩选项 minify: { whitespace: true, identifiers: true, syntax: true, },
// Sourcemap:none | inline | external | linked sourcemap: 'external',
// 命名规则 naming: { entry: '[name].[hash].js', chunk: '[name]-[hash].js', asset: '[name]-[hash].[ext]', },
// 外部依赖(不打包) external: ['react', 'react-dom'],
// 定义全局常量 define: { 'process.env.NODE_ENV': JSON.stringify('production'), },
// 加载器配置 loader: { '.png': 'file', '.svg': 'text', '.json': 'json', },
// 路径别名 alias: { '@': './src', '@components': './src/components', },})加载器类型#
| Loader | 说明 |
|---|---|
| js | JavaScript |
| jsx | JSX |
| ts | TypeScript |
| tsx | TypeScript + JSX |
| json | JSON 文件 |
| toml | TOML 文件 |
| text | 作为字符串导入 |
| file | 复制文件,返回 URL |
| css | CSS 文件 |
| napi | Node.js 原生插件 |
包管理器#
Bun 自带包管理器,比 npm/yarn/pnpm 快很多。
基本命令#
# 安装依赖bun install
# 添加依赖bun add react react-dom
# 添加开发依赖bun add -d typescript @types/react
# 移除依赖bun remove lodash
# 更新依赖bun update
# 查看过期依赖bun outdated配置 bunfig.toml#
[install]# 安装时是否运行 postinstall 脚本auto = "install"
# 缓存目录cache = "~/.bun/install/cache"
# 是否使用锁文件frozen-lockfile = false
# registryregistry = "https://registry.npmmirror.com"
[install.scopes]# 指定 scope 的 registry"@myorg" = { token = "$NPM_TOKEN", url = "https://npm.myorg.com" }工作空间(Monorepo)#
{ "name": "my-monorepo", "workspaces": ["packages/*"]}# 在特定包中运行命令bun run --filter @myorg/app dev
# 安装所有工作空间的依赖bun installReact 项目实战#
项目结构#
my-react-app/├── src/│ ├── index.tsx│ ├── App.tsx│ └── components/├── public/│ └── index.html├── build.ts├── dev.ts├── package.json└── tsconfig.jsonpackage.json#
{ "name": "my-react-app", "scripts": { "dev": "bun run dev.ts", "build": "bun run build.ts", "preview": "bun run --bun preview.ts" }, "dependencies": { "react": "^18.2.0", "react-dom": "^18.2.0" }, "devDependencies": { "@types/react": "^18.2.0", "@types/react-dom": "^18.2.0", "typescript": "^5.0.0" }}构建脚本#
const result = await Bun.build({ entrypoints: ['./src/index.tsx'], outdir: './dist', target: 'browser', minify: true, sourcemap: 'external', splitting: true, define: { 'process.env.NODE_ENV': JSON.stringify('production'), },})
if (!result.success) { console.error('Build failed') process.exit(1)}
// 复制 HTMLconst html = await Bun.file('./public/index.html').text()const outputHtml = html.replace( '</head>', `<script type="module" src="./index.js"></script></head>`)await Bun.write('./dist/index.html', outputHtml)
console.log('Build completed!')开发服务器#
import { watch } from 'fs'
const PORT = 3000
// 简单的开发服务器Bun.serve({ port: PORT, async fetch(request) { const url = new URL(request.url) let path = url.pathname
// 默认返回 index.html if (path === '/') { path = '/index.html' }
// 尝试读取文件 const file = Bun.file(`./public${path}`) if (await file.exists()) { return new Response(file) }
// 处理 TypeScript/JSX if (path.endsWith('.tsx') || path.endsWith('.ts')) { const result = await Bun.build({ entrypoints: [`./src${path}`], target: 'browser', })
if (result.success) { const output = result.outputs[0] return new Response(await output.text(), { headers: { 'Content-Type': 'application/javascript' }, }) } }
return new Response('Not Found', { status: 404 }) },})
console.log(`Dev server running at http://localhost:${PORT}`)入口文件#
import { createRoot } from 'react-dom/client'import { App } from './App'
const root = createRoot(document.getElementById('root')!)root.render(<App />)import { useState } from 'react'
export function App() { const [count, setCount] = useState(0)
return ( <div> <h1>Hello Bun + React!</h1> <button onClick={() => setCount((c) => c + 1)}>Count: {count}</button> </div> )}测试运行器#
Bun 内置测试运行器,兼容 Jest API:
import { expect, test, describe } from 'bun:test'import { add, multiply } from './math'
describe('math', () => { test('add', () => { expect(add(1, 2)).toBe(3) })
test('multiply', () => { expect(multiply(2, 3)).toBe(6) })})运行测试:
# 运行所有测试bun test
# 运行特定文件bun test math.test.ts
# 监听模式bun test --watch
# 覆盖率报告bun test --coverage与其他工具对比#
作为运行时#
| 对比项 | Bun | Node.js | Deno |
|---|---|---|---|
| 语言 | Zig | C++ | Rust |
| TypeScript | 原生支持 | 需要编译 | 原生支持 |
| 启动速度 | 极快 | 中等 | 快 |
| 兼容性 | 大部分兼容 | - | 部分兼容 |
| 包管理器 | 内置 | npm | 内置 |
| 生态成熟度 | 发展中 | 非常成熟 | 发展中 |
作为打包器#
| 对比项 | Bun | esbuild | Vite | Webpack |
|---|---|---|---|---|
| 构建速度 | 极快 | 极快 | 快 | 慢 |
| 配置复杂度 | 简单 | 简单 | 简单 | 复杂 |
| HMR | 需自己实现 | 无 | 极快 | 有 |
| 插件系统 | 有限 | 有限 | 丰富 | 最丰富 |
| 适用场景 | 简单项目 | 库、简单项目 | 现代应用 | 复杂应用 |
当前限制#
Bun 还在快速迭代,有些功能不够完善:
打包器限制#
- HMR 支持有限:需要自己实现热更新逻辑
- CSS 处理基础:不支持 CSS Modules、Sass 等预处理器
- 插件系统不完善:不像 Webpack/Vite 那样灵活
运行时限制#
- Windows 支持较新:可能有一些边界问题
- 部分 Node.js API 不兼容:一些冷门模块可能有问题
- 生态还在发展:某些包可能需要适配
适用场景#
推荐使用 Bun 的场景:
- 个人项目、小型项目
- 需要极致性能的后端服务
- TypeScript 项目(省去编译步骤)
- 脚本任务、CLI 工具
暂时不推荐的场景:
- 大型复杂的前端应用(用 Vite 更成熟)
- 需要丰富插件生态的项目
- 生产环境的企业级应用(稳定性待验证)
常见问题#
1. 某个包不兼容#
Bun 兼容大部分 npm 包,但有些依赖 Node.js 特定 API 的包可能有问题。可以:
# 强制使用 Node.js 运行node script.js
# 或者提 issue2. 构建后样式丢失#
Bun 的 CSS 处理比较基础,可能需要:
await Bun.build({ entrypoints: ['./src/index.tsx'], outdir: './dist', loader: { '.css': 'file', // CSS 作为文件复制 },})3. React DevTools 不工作#
确保开发模式正确设置:
await Bun.build({ define: { 'process.env.NODE_ENV': JSON.stringify('development'), },})4. 安装依赖报错#
尝试清除缓存:
bun pm cache rmbun install