HTML 与全栈开发服务器
本教程共 34 篇 · 第 20 篇 · 更新于 2026-08-06
本节目标:
- 理解 Bun 如何把 HTML 文件当作打包入口(开发服务器与生产构建)
- 掌握
bun --hot全栈开发模式与 HMR 热重载- 学会用
Bun.serve({ routes })把 HTML 导入作为路由,并处理 API 请求- 了解动态路由、独立 HTML 打包与开发/生产两种工作流
前几章我们一直在”打包出 JS/CSS 产物”的语境下讨论打包器。但真实的前端/全栈开发里,第一公民往往是 HTML:一个 index.html 引用了 CSS、JS、图片,我们希望”改一行代码、浏览器自动刷新”。Bun 把这件事做得很轻量——你几乎不需要 webpack-dev-server 那样的重型配置,直接用 bun 命令就能跑起带热重载的开发服务器,甚至能用同一个文件描述”前端页面 + 后端 API”的全栈应用。
20.1 把 HTML 当作开发入口
Bun 可以直接”运行”一个 HTML 文件,此时它会启动一个开发服务器,把该 HTML 及其引用的资源(JS、CSS、图片)按依赖图实时服务出来:
# 启动开发服务器,自动服务 index.html
bun ./index.html
执行后终端会打印一个本地地址(如 http://localhost:3000),浏览器打开即可。当你修改 index.html 引用的 TS/CSS 文件时,Bun 会重新构建相关模块。这种方式对 SPA(单页应用)、MPA(多页应用,多个 HTML 入口)都适用,多页时把多个 HTML 路径一起作为参数即可。
Note在第 17 章提到的
fileloader、CSS 导入等,在这里会自然生效:HTML 里<link>的本地 CSS、<script>引用的 TS,都会被 Bun 的依赖图纳入构建并按需服务。
20.2 生产构建 HTML
开发用 bun ./index.html 方便,但上线要用 bun build 产出静态文件:
# 把 index.html 及其资源打包到 dist
bun build ./index.html --outdir ./dist --minify
# 多页应用:传入多个 HTML 入口
bun build ./pages/home.html ./pages/about.html --outdir ./dist
生产构建会把 HTML 里引用的脚本、样式、图片全部处理:本地图片 URL 会被加上内容哈希、CSS 的 @import 会被合并、TS/JSX 会被转译。最终 ./dist 目录是一份可直接交给任意静态服务器托管的完整站点。
Tip部署前加
--minify压缩产物,并用--sourcemap=linked保留排错能力(第 19 章已讲)。HTML 入口同样可以享受这些优化。
20.3 把 HTML 应用编译成单文件可执行文件
如果你希望把整个 HTML 应用(含其 JS/CSS/图片资源)随一个文件一起分发,可以用 --compile:
# 把 HTML 应用编译成单一可执行文件,资源随二进制内嵌
bun build --compile ./index.html --outfile ./myapp
--compile 会把 HTML 引用的脚本、样式、图片等资源全部内嵌进生成的二进制文件(机制见第 19 章),拿到文件的机器无需安装 Bun 即可直接运行。这种方式适合做演示工具或离线分发的客户端。
20.4 bun --hot:全栈热重载
--hot(或 -h)模式是 Bun 开发体验的核心。它让服务器在文件变化时自动重载,且对前端做 HMR(热模块替换)——只更新变化的模块,不丢失页面状态:
# 启动带热重载的全栈开发服务器
bun --hot ./server.ts
bun --hot 会监听项目文件,当源码变更时,自动重启或热替换相关模块,浏览器侧无需手动刷新即可看到更新。这对”改后端 API 顺带改前端页面”的全栈开发尤为顺手。
Note热重载依赖
import.meta.hotAPI(详见下文 20.6)。在生产构建里,这类 HMR 代码会被 dead-code-eliminate 自动移除,不会进入产物。
20.5 用 Bun.serve 把 HTML 作为路由
Bun 的全栈模式下,你可以把”导入的 HTML”直接当成路由的返回值。Bun.serve 的 routes 选项接受一个路径到处理器(或 HTML 模块)的映射:
import homepage from "./index.html";
Bun.serve({
routes: {
"/": homepage, // 直接返回导入的 HTML
"/api/users": {
GET() {
return Response.json([{ id: 1, name: "张三" }]);
},
POST(req) {
return Response.json({ ok: true }, { status: 201 });
},
},
},
development: true, // 开启 HMR 与 console 回传
});
这里有几个要点:
"/"映射到homepage(一个被 Bun 当作 HTML 模块导入的文件),访问根路径就返回该页面;"/api/users"是一个 API 路由,按 HTTP 方法(GET/POST/PUT/DELETE)分发处理函数,返回标准Response;development: true打开开发体验:前端 HMR、以及把浏览器console回传到终端。
20.5.1 动态路由与通配
routes 支持路径参数与通配符:
Bun.serve({
routes: {
"/users/:id": (req) => {
const id = req.params.id; // 从路径取出 :id
return Response.json({ userId: id });
},
"/assets/*": staticHandler, // 通配其余静态资源
},
});
:id 这类动态段会被解析进 req.params,让你用一份处理器覆盖一类 URL;* 用于兜底匹配。
20.6 import.meta.hot:前端热更新钩子
在浏览器侧代码里,Bun 提供 import.meta.hot 让你精细控制热更新行为。常见用法:
import.meta.hot.accept():表示”本模块接受热替换”,更新后不整页刷新;import.meta.hot.accept((mod) => { ... }):拿到新模块并手动应用(例如替换组件状态);import.meta.hot.decline():声明”本模块不能被热替换,必须整页刷新”;import.meta.hot.dispose(() => { ... }):在模块被替换前做清理(如移除事件监听、关闭连接);import.meta.hot.data:在热替换的两次版本间传递状态。
// 一个可热替换的前端模块
if (import.meta.hot) {
import.meta.hot.accept((newModule) => {
// 用新模块的逻辑刷新 UI,而不丢失页面状态
render(newModule.default);
});
import.meta.hot.dispose(() => {
// 旧模块下线前,清理副作用
cleanup();
});
}
Warning
import.meta.hot必须在模块顶层直接调用,不能先赋值给某个变量再延迟调用,否则 Bun 无法在静态分析阶段正确织入 HMR 逻辑。另外,这个 API 只在开发服务器下有意义,生产构建会被自动剔除。
20.7 开发流 vs 生产流
Bun 的 HTML/全栈工作流可以很清晰地分成两段:
开发期:用 bun --hot ./server.ts(或 bun ./index.html 做纯前端),享受 HMR、动态路由、API 同进程调试。development: true 让前端错误与 console 直接回传到终端,调试体验接近主流前端框架的 dev server。
生产期:用 bun build ./index.html --outdir=dist --minify(纯前端站点),或对全栈应用做 AOT 构建(bun build --target=bun --production),把代码预打包,再以普通 Bun.serve 运行编译后的产物,降低运行时开销。
Tip轻量项目里,甚至可以跳过单独的”前端构建”步骤:开发用
--hot,上线用bun build --target=bun --production直接产出优化后的服务器代码。Bun 的”打包器 + 运行时 + 服务器”一体设计,正是为了减少这类工具链的拼接成本。
20.8 小结
本章我们把打包器接入了真实的 HTML 与全栈场景:
bun ./index.html直接启动开发服务器,HTML 是天然入口;bun build ./index.html --outdir=dist产出可托管的静态站点,bun build --compile ./index.html把应用编译成单文件可执行文件;bun --hot提供全栈热重载,浏览器侧走 HMR;Bun.serve({ routes })让”导入的 HTML”成为路由返回值,并与 API 路由(GET/POST/动态:id、通配*)共存于同一进程;development: true开启 HMR 与 console 回传;import.meta.hot提供 accept/decline/dispose/data 等精细热更新钩子,且生产构建会被自动移除。
Note全栈模式下,前端页面与后端 API 运行在同一进程、共享同一套模块图,因此你在后端
routes里改了逻辑、前端组件里改了样式,都会经由--hot被同一套热重载机制捕获,无需分别启动前端 dev server 与后端服务。这种”单进程全栈”的简洁性,正是 Bun 把运行时、打包器、服务器打包在一起的设计收益之一。
至此,Bun 打包器篇章(第 16–20 章)全部完成:从 bun build 基础、loader 与资源、插件系统、压缩与独立可执行文件,到 HTML 与全栈开发服务器,我们已经能够用一套统一的工具链,覆盖”开发 → 构建 → 分发 → 全栈”的完整链路。下一章起,我们将转入测试主题(bun test)。