Bun 是一个集 JavaScript 运行时、包管理器、打包器与测试 Runner 于一体的全功能 JavaScript 工具链,使用 Zig 编写、底层基于 JavaScriptCore。相比传统的 Node.js + npm 组合,Bun 在安装依赖、启动服务和运行 TypeScript 上都有数量级的提速,正在成为前端与服务端开发的新选择。
一、为什么需要 Bun:Node.js 的痛点
Node.js 生态成熟,但日常开发里总有些慢得让人抓狂的环节:npm install 动辄几十秒甚至数分钟、冷启动要等 V8 预热、跑 TypeScript 还得先 tsc 或 ts-node 编译一遍。Bun 把这些分散的工具收敛成一个二进制,从根上缩短了「改一行代码到看到结果」的反馈链路。它与我们之前聊过的 Deno 实战 思路相似,但 Bun 更强调「无缝兼容 Node 生态」而非另起炉灶。
| 能力 | Node.js + npm | Deno | Bun |
|---|---|---|---|
| 运行时内核 | V8 | V8 | JavaScriptCore |
| 包管理器 | npm / pnpm | 内置(URL import) | 内置 bun install |
| TS 原生支持 | 需编译 | 原生 | 原生(转译) |
| 打包器 | 需 esbuild/webpack | 实验性 | 内置 bun build |
| 测试 Runner | 需 jest/vitest | 内置 | 内置 bun test |
| npm 兼容 | 原生 | 部分 | 高度兼容 |
二、安装与版本管理
官方推荐用一条命令安装,也可以全局用 npm 安装,或用 mise 之类版本管理器固定团队版本,避免本地与 CI 不一致。
# 官方一键安装(macOS / Linux)
curl -fsSL https://bun.sh/install | bash
# 或者全局安装
npm install -g bun
# 验证
bun --version
bun --help
建议使用版本管理器锁定版本,CI 里显式写死 bun-version,这样构建可复现,也方便回滚。
三、包管理:bun install 的极速体验
Bun 自带包管理器,命令与 npm 几乎一致,但安装速度通常快 5–10 倍,因为它用全局缓存 + 并行解析,并直接写二进制锁文件 bun.lockb。
# 初始化并安装依赖
bun init
bun add react react-dom
bun add -d typescript @types/react
# 删除与更新
bun remove lodash
bun update
# CI 里用 --frozen-lockfile 保证可复现
bun install --frozen-lockfile
首次安装后,Bun 会把包缓存到 ~/.bun/install/cache,后续项目复用同一份,换新项目几乎秒装。
四、原生运行 TypeScript 与 ESM
不用配置 tsconfig 的 transpile 流水线,直接 bun run 一个 .ts 文件就能跑,Bun 在加载时完成转译。它也默认拥抱 ESM,import 语法开箱即用。
// server.ts
const name: string = "Bun";
console.log(`Hello from ${name}`);
// 直接运行,无需 tsc
bun run server.ts
对于习惯了在 VS Code 里写前端的同学,这种「存盘即跑」的体验能明显缩短调试循环。
五、内置打包器 bun build
需要产出浏览器或 Node 可用的产物时,无需引入 esbuild/webpack,bun build 一条命令搞定,支持代码分割、压缩(需 esbuild 作为可选依赖)和 Target 指定。
# 打包为浏览器可用的 IIFE
bun build ./src/index.ts --outdir ./dist --target browser
# 打包为 Node 可执行格式
bun build ./cli.ts --outfile ./dist/cli --target bun
# 在代码里调用 API 做更细控制
import { build } from "bun";
await build({
entrypoints: ["./src/index.ts"],
outdir: "./dist",
minify: true,
});
六、内置测试 Runner
bun test 兼容 Jest 风格的 expect / describe / it,启动极快,适合放进提交前钩子。配合 Playwright 做端到端测试,可以覆盖从单元到界面的完整链路。
// math.test.ts
import { expect, test } from "bun:test";
test("adds numbers", () => {
expect(1 + 1).toBe(2);
});
test("async fetch", async () => {
const res = await fetch("https://example.com");
expect(res.ok).toBe(true);
});
// 运行
bun test
七、用 Bun.serve 起一个 HTTP 服务
Bun 内置了性能优秀的 HTTP 服务器,用 Bun.serve 即可起服务,吞吐接近专业框架。对于轻量 API 服务,它可以和 FastAPI 这类后端框架形成互补:前端用 Bun 一条龙,重业务逻辑交给专门服务。
Bun.serve({
port: 3000,
fetch(req) {
const url = new URL(req.url);
if (url.pathname === "/api/ping") {
return Response.json({ ok: true });
}
return new Response("Hello from Bun!");
},
});
console.log("Listening on http://localhost:3000");
八、接入 Docker 与 CI
官方提供了 oven/bun 镜像,镜像体积比 Node 官方镜像更小、启动更快。下面这份 Dockerfile 同时覆盖了依赖安装与构建,配合 Docker 编排 与 GitHub Actions 可以做到提交即构建、即出镜像。
# Dockerfile
FROM oven/bun:1 AS base
WORKDIR /app
FROM base AS deps
COPY package.json bun.lockb ./
RUN bun install --frozen-lockfile
FROM base AS build
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN bun build ./src/index.ts --outdir ./dist
FROM oven/bun:1-alpine AS run
WORKDIR /app
COPY --from=build /app/dist ./dist
EXPOSE 3000
CMD ["bun", "dist/index.js"]
九、迁移注意事项与常见坑
Bun 高度兼容 Node,但仍有边界差异,上线前建议重点验证以下几点:
- 原生 Node API:少数依赖直接使用
process.binding、特定 V8 内部行为的包可能跑不起来,优先用纯 JS 实现的库。 - 全局对象:Bun 提供了
Bun.file、Bun.write等内置 API,迁移时可以用它们替换fs样板代码,但要注意和 Node 行为的小差别。 - 环境变量:
Bun.env与process.env指向同一份,但热更新语义略有不同,留意长驻进程里的读取时机。 - 依赖锁定:CI 务必用
--frozen-lockfile,否则 Bun 可能在无锁时自动升级,导致构建漂移。
十、生产落地检查清单
| 检查项 | 建议做法 |
|---|---|
| 版本固定 | CI 与团队用版本管理器锁定 bun 版本 |
| 依赖可复现 | 提交 bun.lockb,CI 用 –frozen-lockfile |
| 镜像体积 | 采用 oven/bun:1-alpine 多阶段构建 |
| 测试前置 | 提交钩子跑 bun test,阻断坏代码 |
| 兼容性 | 上线前扫描依赖对 Node 原生 API 的依赖 |
| 可观测 | 接入日志与监控,关注启动耗时指标 |
十一、性能实测:Bun 到底快多少
根据社区基准,bun install 在冷缓存场景下通常比 npm install 快 5 倍以上,热缓存几乎瞬时;bun test 的启动开销也远低于 Jest。下面是一组仅供参考的对比,具体数值会随项目规模与机器配置浮动:
| 场景 | npm + node | Bun |
|---|---|---|
| 冷安装约 200 个依赖 | 约 30 秒 | 约 5 秒 |
| 热安装(已有缓存) | 约 3 秒 | 约 0.3 秒 |
| 运行单个测试文件 | 约 1.2 秒 | 约 0.15 秒 |
| 启动空路由 HTTP 服务 | 约 80 毫秒 | 约 15 毫秒 |
数字之外更关键的是「体感」:开发时改完代码回车即见结果,CI 里安装步骤从分钟级降到秒级,团队整体的等待成本被显著压缩。对一天要装十几次依赖的前端同学来说,这点提速累积起来非常可观。
十二、Bun 与前端框架的协同
在前端工程里,Bun 可以无缝替换 npm/pnpm 来跑 Vue3 或 Next.js RSC 项目:用 bunx 直接调用脚手架,用 bun run dev 启动开发服务器,启动与热更新都比 Node 更轻快。它还能作为 Vite 的底层 transpiler,让大型组件库的冷启动明显变快。
# 用 Bun 初始化并运行一个 Vite + Vue 项目
bunx create-vite@latest my-app --template vue-ts
cd my-app
bun install
bun run dev
# 在 vite.config.ts 里用 Bun 做依赖预编译提速
export default {
optimizeDeps: { transformer: "bun" },
};
对于已经用 Node 的老项目,不必一步到位重写,只需把本地开发命令从 npm run 换成 bun run,往往就能立刻感受到安装与启动的提速,而风险几乎为零,是成本最低的上手路径。
十三、何时该上 Bun,何时先观望
Bun 适合依赖大量 JS/TS 工具链、追求开发反馈速度的前端团队和全栈项目;对强依赖特定 Node 原生模块、或运行在极度保守生产环境的服务,建议先在 CI 与本地开发试点,跑通兼容矩阵再扩大范围。技术选型没有银弹,但把 Bun 当作「开发期加速器」几乎是稳赚不赔的第一步,既能立刻吃到效率红利,又不必承担重写生产服务的迁移风险。
总体来看,Bun 把运行时、包管理、打包、测试四个高频环节统一到一个工具里,对中小团队和前端重度项目尤其划算。它不要求你立刻重写 Node 服务,从「本地开发提速」切入,逐步把 bun install、bun test、bun build 接进流水线,就能先吃到最明显的效率红利。



