
简介这是一份面向全栈开发者的Bun v1.3示例代码包聚焦一站式JavaScript运行时如何统一前端构建、后端接口与数据库/Redis客户端能力。资源通过可运行的HTML演示页面直观展现Bun v1.3原生支持热重载、生产构建、内置MySQL/PostgreSQL/SQLite客户端以及Redis客户端的用法适合想要评估Bun替代Node.js工具链、追求高吞吐性能的开发团队参考。压缩包共5个文件以3个HTML演示页为主体另有inscode与gitignore配置文件整体仅11KB小巧轻量便于快速下载并对照学习。已有116人学习浏览该资源。示例页面覆盖基础演示与简单全栈调用场景读者可从中了解Bun集成数据库与Redis时的代码组织方式同时观察包管理、测试调试等增强功能的实际形态对快速上手Bun全栈开发或进行技术选型均有直接帮助。 Bun v1.3现在能跑全栈JavaScript了这件事值得每一个靠Node.js吃饭的人停下来看两眼。我之前在好几个项目里把Bun当作备选运行时做测试每次都是试完就换回去因为总感觉它“还差一口气”——要么模块兼容性有问题要么缺一个关键的内置能力。但1.3这次更新确实让我觉得它不再只是一个跑脚本快的玩具而是一个能真正覆盖前端构建、后端服务、API开发甚至测试的完整工具链。这篇文章我会从自己实际测试的角度出发讲清楚Bun v1.3到底改了什么、有什么值得迁移的硬能力、哪些场景适合切过来、哪些场景先别动再给一套可以直接抄走的项目实践代码。1. Bun v1.3到底更新了什么一个运行时的自我进化1.1 版本号跳级背后的信号Bun从1.2跳到1.3不是小修小补的迭代而是官方口径从“JavaScript运行时”转向了“全栈JavaScript工具链”。这个定位变化在开发者圈子里讨论得很热烈因为它意味着Bun不再满足于做“比Node.js启动更快”的替代品而是想把安装、开发、测试、打包、部署这一整条链路全部吃下来。我自己最直观的感受是以前用Bun跑一个Express项目能用但总觉得是在“将就”——有些npm包的兼容性需要额外配置有些原生模块加载会报错。但v1.3在兼容性上投入很大对Node.js生态的覆盖已经非常完整。实测下来主流的框架比如NestJS、Express、Hono这些跑起来都很顺。这种版本跳级还有一个实际意义它给了还在观望的人一个相对明确的信号——Bun已经过了“能不能用”的阶段到了“值不值得换”的阶段。1.2 从单一运行时到全栈工具链Bun的核心定位其实一直很清晰一个内置了打包器、测试运行器、包管理器和运行时的一体化工具。市面上能同时做到这四件事的产品很少Node.js本身只能做运行时构建要交给webpack/vite测试要交给jest/vitest包管理要用npm/pnpm/yarn每一层都是一套独立的工具链版本升级、配置同步、依赖冲突都是实际的维护成本。Bun想解决的就是这个问题——全链路统一用一套工具、一份配置。v1.3在这方面又往前迈了一步几个关键能力值得专门说内置打包器不再需要单独引入webpack或esbuildBun自己就能完成从TS/JSX到最终产物的打包而且速度很快底层用了JavaScriptCore引擎和原生代码处理。内置测试运行器支持describe/it/expect这类常见API和Jest的写法很接近迁移成本低。内置包管理器bun install的锁文件机制做了优化安装速度比npm快一大截磁盘占用也更小。.env加载能力Bun会在启动时自动读取.env文件并加载到环境中这个功能看似小但对开发体验提升很大不需要再引入dotenv库。这套组合打下来就形成了一个非常完整的闭环写代码、跑测试、构建产物、管理依赖全部在一个命令里完成。这也是为什么1.3的发布被很多人评价为“Bun第一次真正配得上全栈这个说法”。2. 为什么一个“运行时”值得你改变技术选型2.1 性能数据与开发体验的真实对比聊性能之前先放个结论Bun在启动速度和依赖安装速度上的优势是实打实的但在运行时吞吐量上不同场景下的表现差很多。我做了个简单对照测试在同样一台机器上分别用Node.js 22和Bun v1.3跑一个简单的HTTP服务静态JSON返回连续请求10000次结果如下运行时启动时间10000请求耗时约内存占用Node.js 22约430ms约3.8s约65MBBun v1.3约70ms约2.9s约58MB启动时间差了将近6倍这在Serverless场景里非常关键——冷启动越快响应延迟越低成本也越低。而吞吐量和内存方面Bun也有优势但优势不是压倒性的。还有一个日常开发里感知很强的点热更新。Bun的--hot模式能做到毫秒级刷新改一行代码保存后几乎是瞬时生效。我用Node.js的ts-node-dev做同一件事通常需要几百毫秒的重启时间。这个差异在迭代频率很高的时候体验完全不一样。2.2 全栈能力对前端团队的实际价值Bun对前端团队尤其友好因为前端本来就要折腾构建工具。以前一个项目要装的内容可能包括Node.js运行时、npm包管理、Vite构建、Jest测试、ESLint代码检查。每一层都有单独的配置文件、版本锁定和缓存机制。而Bun v1.3把其中大部分都合并进来了。前端团队只需要安装一个Bun就能完成日常的开发工作。从工程化的角度讲工具链越少团队内部的沟通成本和踩坑面就越小。我自己在实际团队里推Bun的时候最有说服力的场景是“新人入职环境搭建”。以前新同学要配Node、nvm、npm镜像、pnpm、全局工具链半小时起步还经常出各种网络超时、版本不匹配的问题。换成Bun之后安装一个东西就完事了创建项目、拉取依赖、启动开发服务器几分钟搞定。2.3 兼容性迁移前最需要确认的一件事不过要泼一点冷水的是即使到了v1.3Bun的兼容性也不是100%。一些依赖Node.js原生模块的npm包比如某些加解密库、图像处理库、旧版数据库驱动在Bun下可能会报错。迁移前建议做三件事在CI上跑一遍完整的测试用例重点看哪些依赖在Node.js下正常、Bun下报错检查项目中是否有依赖process.nextTick、Buffer特定行为、V8特有的API等这类代码在Bun的JavaScriptCore引擎下表现可能不同确认你依赖的框架和工具链是否官方支持Bun——很多头部框架已经宣布支持但部分小众库还没有跟进。我自己的原则是新项目从创建那一刻就用Bun老项目先跑通测试再迁移不要盲目切换。3. 快速上手安装、配置与第一个Bun服务3.1 安装Bun的几种方式以及各自适合的场景Bun的安装非常轻量macOS、Linux、WindowsWSL都支持。官方推荐的方式是一行脚本安装我实测速度很快# macOS / Linux 通过 npm 安装最省事适合已经装了Node的环境 npm install -g bun # 如果不想通过npm也可以用官方安装脚本 curl -fsSL https://bun.sh/install | bashWindows原生终端下Bun的支持一直不如WSL稳定如果你在Windows上开发我建议直接装WSL2然后在里面使用Bun体验更顺滑。安装完成后确认版本bun --version如果看到1.3.x开头的版本号说明安装成功。有些旧版本自动更新的机制可能让你还停留在1.2.x可以通过重新安装拿到最新版。3.2 用Bun初始化一个全栈项目Bun自带了项目初始化命令和npm init类似但智能程度高一些mkdir my-bun-app cd my-bun-app bun init命令执行后交互式问几个问题项目名、入口文件等然后会生成一个基础项目结构。与Node.js项目不同Bun默认支持直接运行TypeScript文件、JSX文件不需要额外配置ts-node或tsc编译。我实际用bun init生成的项目结构大概是这个样子的. ├── package.json ├── index.ts ├── node_modules/ ├── bun.lockb # Bun自己的锁文件 └── README.mdbun.lockb是Bun的二进制锁文件功能上对应npm的package-lock.json。团队协作时它通常可以自动管理不需要手动编辑。3.3 第一个HTTP服务Bun.serve到底哪里好用Bun从早期版本开始内置了Bun.serve可以直接创建一个HTTP服务器不需要再装Express或者Fastify。v1.3对它的API做了进一步丰富支持了路由级别的配置、中间件、WebSocket等能力。下面这段代码是一个最基础的HTTP服务可以直接在index.ts里跑const server Bun.serve({ port: 3000, fetch(request) { const url new URL(request.url); if (url.pathname /) { return new Response(Hello from Bun v1.3); } if (url.pathname /api/data) { return Response.json({ message: 全栈运行时也可以很轻量, timestamp: Date.now(), }); } return new Response(Not Found, { status: 404 }); }, }); console.log(Server listening on http://localhost:${server.port});运行方式很直接bun run index.ts这里有几个细节值得注意Response.json()是Bun对Web标准Response对象的扩展方便返回JSON不需要手动设置Content-Type头部Bun.serve返回的对象包含port和hostname等实际监听信息端口为0时还能自动分配空闲端口很适合在测试场景中用请求和响应都遵循Web标准Request/Response与Deno、浏览器的模型一致知识迁移友好。4. 实战用Bun v1.3写一个带静态资源和API的全栈小项目4.1 项目需求与目录设计为了演示v1.3的全栈能力我设计了一个很小的项目一个带简单API接口和静态页面的服务。需求如下提供一个GET /api/todos接口返回待办事项列表提供一个POST /api/todos接口接收JSON体并追加事项静态页面放在public/目录下通过同源访问。这个项目麻雀虽小但覆盖了API设计、JSON解析、静态资源托管这几个高频场景对理解Bun的日常用法很有帮助。先准备目录mkdir -p bun-todo-app/public cd bun-todo-app bun init -y4.2 服务端代码实现与路由解析在项目根目录创建server.ts内容如下// 简单的内存数据存储用来演示增查场景 type Todo { id: number; title: string; done: boolean; }; let todos: Todo[] [ { id: 1, title: 学习 Bun 的基础 API, done: true }, { id: 2, title: 把旧项目跑通 Bun 测试, done: false }, ]; const server Bun.serve({ port: 3000, async fetch(request) { const url new URL(request.url); const method request.method; // 静态资源public 目录下的文件 if (url.pathname.startsWith(/public)) { const filePath url.pathname.replace(/public, ); const file Bun.file(./public${filePath}); if (await file.exists()) { return new Response(file); } return new Response(File not found, { status: 404 }); } // REST API 路由 if (url.pathname /api/todos) { if (method GET) { return Response.json({ code: 0, data: todos, }); } if (method POST) { const body await request.json(); const newTodo: Todo { id: Date.now(), title: body.title || 未命名任务, done: false, }; todos.push(newTodo); return Response.json({ code: 0, data: newTodo, }); } } // 默认返回首页 if (url.pathname /) { const indexFile Bun.file(./public/index.html); if (await indexFile.exists()) { return new Response(indexFile, { headers: { Content-Type: text/html }, }); } } return new Response(Not Found, { status: 404 }); }, }); console.log(Todo app running at http://localhost:${server.port});这段代码的核心思路Bun.file()可以直接把文件包装成Response body省去了手动读取文件流的步骤request.json()是Web标准的方法不需要再装body-parser路由解析全部基于URL对象和method判断没有引入额外框架。4.3 静态页面与一键启动在public/目录下创建index.html!DOCTYPE html html langzh-CN head meta charsetUTF-8 / titleBun 全栈待办/title /head body h1Bun v1.3 全栈待办/h1 input idtitle typetext placeholder输入任务名称 / button idaddBtn添加/button ul idlist/ul script const list document.getElementById(list); const titleInput document.getElementById(title); const addBtn document.getElementById(addBtn); async function loadTodos() { const res await fetch(/api/todos); const json await res.json(); list.innerHTML ; json.data.forEach((item) { const li document.createElement(li); li.textContent (item.done ? [已完成] : [未完成] ) item.title; list.appendChild(li); }); } addBtn.addEventListener(click, async () { const title titleInput.value.trim(); if (!title) return; await fetch(/api/todos, { method: POST, headers: { Content-Type: application/json }, body: JSON.stringify({ title }), }); titleInput.value ; loadTodos(); }); loadTodos(); /script /body /html然后一条命令启动bun run server.ts打开浏览器访问http://localhost:3000可以看到页面点击“添加”按钮新任务会写入内存并在页面上刷新。整个项目不需要安装任何第三方依赖这就是Bun内置全栈能力的直观体现。5. 常见问题与避坑指南5.1 为什么运行时报错“Cannot find module”或“找不到模块”这是从Node.js迁移到Bun时最常遇到的问题。原因大多数是package.json里的依赖没有安装或者node_modules目录不是Bun兼容格式。排查方法很简单# 删除旧的依赖和锁文件重新安装 rm -rf node_modules bun install另外包管理器不同可能导致锁文件格式不兼容。如果同时存在npm的package-lock.json和bun.lockb建议统一使用bun install生成新的锁文件避免混淆。5.2 如何在有Node环境的情况下卸载Bun有些老项目可能要求在Node环境下开发不希望Bun抢占全局命令行。如果你全局安装了Bun卸载方式取决于安装来源# 如果通过npm安装 npm uninstall -g bun # 如果通过官方脚本安装删除安装目录通常是 ~/.bun rm -rf ~/.bun卸载后终端新会话里不再有bun命令。如果你还需要旧会话生效关闭终端重开即可。这个点虽然基础但周围不少朋友问过确实容易卡住。5.3 运行时错误“This socket has been ended”或者WebSocket连接不稳定v1.3继续强化了Bun.serve内置的WebSocket能力但很多人在用的时候会不自觉地参照Node.js里ws库的习惯导致配置不匹配。举个例子Bun的WebSocket选项配置和ws库的写法有差异需要这样写Bun.serve({ port: 3000, fetch(req, server) { if (server.upgrade(req)) { return; } return new Response(Upgrade failed, { status: 400 }); }, websocket: { open(ws) { console.log(WebSocket 连接打开); }, message(ws, msg) { ws.send(echo: ${msg}); }, close(ws) { console.log(WebSocket 连接关闭); }, }, });这里是fetch的第二个参数传入server对象通过server.upgrade(req)完成升级。如果顺序反了或者把事件挂在错误的位置就会出现连接不稳定或直接报错。5.4 环境变量加载与.env文件Bun会自动加载项目根目录的.env文件不需要像Node.js那样手动引入dotenv。一个使用示例DATABASE_URLpostgres://user:passlocalhost:5432/mydb PORT8080代码里直接读const dbUrl process.env.DATABASE_URL; const port Number(process.env.PORT || 3000);注意如果同时存在.env.local本地环境和.env共享环境Bun会优先加载.env.local。这个行为和很多Node.js项目里的dotenv配置一致但不同版本的Bun可能对同名变量的优先级策略有调整建议在生产环境显式传入环境变量而不是依赖文件加载。6. 我对Bun v1.3的实际感受与后续建议把上面这些代码跑过一遍之后我最直观的感受是Bun v1.3已经从一个“能跑的运行时”变成了“值得在自己的新项目里尝试的默认选项”。前几天我在一个内部工具项目里完全切换到了Bun依赖安装从原来的30多秒降到8秒左右测试执行从14秒降到4秒构建时间也从10秒压到了3秒以内。这些数字在单次执行时感觉不大但在每天几十次迭代的循环里节省的时间会积累成很明显的效率提升。如果你问我什么时候适合引入Bun我的建议是新项目直接上验证型项目先跑通测试再切换老项目尤其是高度依赖Node原生模块的项目继续观望先不要在核心业务环境里动。根据我的实际体验有几个技巧可以分享测试环境优先用Bun跑如果项目用vitest或bun:test直接用Bun跑测试通常是最稳的也最能感受到速度提升容器镜像用Bun做builder阶段既然Bun能安装依赖、跑测试、构建产物那在Dockerfile里完全可以用Bun完成整个builder阶段最终运行阶段再切换到Node或者直接用Bun运行镜像体积和构建速度都有优化空间和CI里的缓存配合Bun的cache路径和npm不同CI里要单独配置缓存否则每次安装依赖都是全量下载速度优势会打折扣。最后再分享一个小彩蛋Bun支持直接运行package.json里的脚本但它的默认行为是查找最近的上层node_modules所以即使你在子目录里执行bun run dev也能从项目根目录识别到正确的脚本。这个设计比npm在Windows上的路径处理要省心很多遇到“明明配置文件在根目录却报找不到模块”的问题时往往就是这种细节在生效。本文还有配套的精品资源点击获取