Skip to content

Bun - 全栈 JavaScript 运行时与打包器

Bun 是用 Zig 语言写的 JavaScript 运行时,目标是替代 Node.js。但它不仅仅是运行时——内置了打包器、转译器、包管理器和测试运行器。一个工具搞定所有事情。

Bun 的速度确实惊人。官方宣称比 Node.js 快 4 倍,比 Deno 快 2 倍。安装依赖比 npm 快 25 倍。这些数字虽然有营销成分,但实际体验确实很快。

安装#

Terminal window
# macOS / Linux
curl -fsSL https://bun.sh/install | bash
# Windows (PowerShell)
powershell -c "irm bun.sh/install.ps1 | iex"
# 或者用 npm
npm install -g bun
# 验证安装
bun --version

作为运行时#

运行 JavaScript/TypeScript#

Bun 原生支持 TypeScript 和 JSX,不需要任何配置:

Terminal window
# 直接运行 TypeScript
bun run index.ts
# 运行 JSX
bun 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 自带打包功能,速度极快。

基本使用#

Terminal window
# 打包入口文件
bun build ./src/index.ts --outdir ./dist
# 指定目标环境
bun build ./src/index.ts --outdir ./dist --target browser
# 生成 sourcemap
bun build ./src/index.ts --outdir ./dist --sourcemap
# 压缩输出
bun build ./src/index.ts --outdir ./dist --minify

JavaScript API#

build.ts
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说明
jsJavaScript
jsxJSX
tsTypeScript
tsxTypeScript + JSX
jsonJSON 文件
tomlTOML 文件
text作为字符串导入
file复制文件,返回 URL
cssCSS 文件
napiNode.js 原生插件

包管理器#

Bun 自带包管理器,比 npm/yarn/pnpm 快很多。

基本命令#

Terminal window
# 安装依赖
bun install
# 添加依赖
bun add react react-dom
# 添加开发依赖
bun add -d typescript @types/react
# 移除依赖
bun remove lodash
# 更新依赖
bun update
# 查看过期依赖
bun outdated

配置 bunfig.toml#

bunfig.toml
[install]
# 安装时是否运行 postinstall 脚本
auto = "install"
# 缓存目录
cache = "~/.bun/install/cache"
# 是否使用锁文件
frozen-lockfile = false
# registry
registry = "https://registry.npmmirror.com"
[install.scopes]
# 指定 scope 的 registry
"@myorg" = { token = "$NPM_TOKEN", url = "https://npm.myorg.com" }

工作空间(Monorepo)#

package.json
{
"name": "my-monorepo",
"workspaces": ["packages/*"]
}
Terminal window
# 在特定包中运行命令
bun run --filter @myorg/app dev
# 安装所有工作空间的依赖
bun install

React 项目实战#

项目结构#

my-react-app/
├── src/
│ ├── index.tsx
│ ├── App.tsx
│ └── components/
├── public/
│ └── index.html
├── build.ts
├── dev.ts
├── package.json
└── tsconfig.json

package.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"
}
}

构建脚本#

build.ts
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)
}
// 复制 HTML
const 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!')

开发服务器#

dev.ts
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}`)

入口文件#

src/index.tsx
import { createRoot } from 'react-dom/client'
import { App } from './App'
const root = createRoot(document.getElementById('root')!)
root.render(<App />)
src/App.tsx
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:

math.test.ts
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)
})
})

运行测试:

Terminal window
# 运行所有测试
bun test
# 运行特定文件
bun test math.test.ts
# 监听模式
bun test --watch
# 覆盖率报告
bun test --coverage

与其他工具对比#

作为运行时#

对比项BunNode.jsDeno
语言ZigC++Rust
TypeScript原生支持需要编译原生支持
启动速度极快中等
兼容性大部分兼容-部分兼容
包管理器内置npm内置
生态成熟度发展中非常成熟发展中

作为打包器#

对比项BunesbuildViteWebpack
构建速度极快极快
配置复杂度简单简单简单复杂
HMR需自己实现极快
插件系统有限有限丰富最丰富
适用场景简单项目库、简单项目现代应用复杂应用

当前限制#

Bun 还在快速迭代,有些功能不够完善:

打包器限制#

运行时限制#

适用场景#

推荐使用 Bun 的场景:

暂时不推荐的场景:

常见问题#

1. 某个包不兼容#

Bun 兼容大部分 npm 包,但有些依赖 Node.js 特定 API 的包可能有问题。可以:

Terminal window
# 强制使用 Node.js 运行
node script.js
# 或者提 issue

2. 构建后样式丢失#

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. 安装依赖报错#

尝试清除缓存:

Terminal window
bun pm cache rm
bun install

参考资料#