Skip to main content
Bun 可以将整个前端打包成一个 单个 .html 文件,无需任何外部依赖。JavaScript、TypeScript、JSX、CSS、图片、字体、视频、WASM —— 所有内容均内联到一个文件中。
terminal
bun build --compile --target=browser ./index.html --outdir=dist
输出是一个完全自包含的 HTML 文档。没有相对路径。没有外部文件。无需服务器。只有一个 .html 文件,可以在任何浏览器中打开。

一个文件,随处上传,立即可用

输出是一个单独的 .html 文件,你可以放到任何地方:
  • 上传到 S3 或任何静态文件托管 —— 无需维护目录结构,只需一个文件
  • 从桌面双击打开 —— 直接在浏览器中打开,支持离线,无需本地服务器
  • 嵌入你的 WebView 中 —— 无需处理相对文件
  • 插入 <iframe> —— 用单文件 URL 在其他页面嵌入交互内容
  • 从任何位置提供服务 —— 任何 HTTP 服务器、CDN 或文件共享,文件一份,零配置
无需安装任何东西,不用部署 node_modules,不用管理构建产物,也无需考虑相对路径。整个应用 —— 框架代码、样式表、图片等等 —— 都在这唯一的文件中。

真正的单文件

通常,发布网页意味着管理一个资产文件夹 —— HTML、JavaScript 包、CSS 文件、图片。只移动 HTML 文件,没了其他内容就会坏掉。浏览器以前尝试解决这个问题:Safari 的 .webarchive.mhtml 旨在将页面保存为单文件,但实际上它们会解包成电脑上的松散文件夹 —— 违背了初衷。 独立 HTML 不同。输出是一个普通的 .html 文件。不是归档文件,也不是文件夹。一个文件,内装所有内容。每张图片、每个字体、每行 CSS 和 JavaScript 都通过标准的 <style> 标签、<script> 标签和 data: URI 直接嵌入 HTML。任何浏览器都能打开。任何服务器都能托管。任何文件托管都能存储。 这使得发布网页就像发布 PDF 一样方便 —— 单个文件,你可以随意移动、复制、上传或分享,无需担心路径断裂或资产丢失。

快速开始

<!doctype html>
<html>
  <head>
    <link rel="stylesheet" href="./styles.css" />
  </head>
  <body>
    <div id="root"></div>
    <script src="./app.tsx"></script>
  </body>
</html>
terminal
bun build --compile --target=browser ./index.html --outdir=dist
打开 dist/index.html —— React 应用无需服务器即可运行。

所有内容均内联

Bun 会内联你 HTML 中找到的所有本地资源。如果是相对路径,则嵌入到输出文件中。这不仅限于图片和样式表 —— 适用于任何文件类型。

什么内容会被内联

你的源码输出内容
<script src="./app.tsx"><script type="module">...打包后代码...</script>
<link rel="stylesheet" href="./styles.css"><style>...打包后 CSS...</style>
<img src="./logo.png"><img src="data:image/png;base64,...">
<img src="./icon.svg"><img src="data:image/svg+xml;base64,...">
<video src="./demo.mp4"><video src="data:video/mp4;base64,...">
<audio src="./click.wav"><audio src="data:audio/wav;base64,...">
<source src="./clip.webm"><source src="data:video/webm;base64,...">
<video poster="./thumb.jpg"><video poster="data:image/jpeg;base64,...">
<link rel="icon" href="./favicon.ico"><link rel="icon" href="data:image/x-icon;base64,...">
<link rel="manifest" href="./app.webmanifest"><link rel="manifest" href="data:application/manifest+json;base64,...">
CSS 中的 url("./bg.png")CSS 中的 url(data:image/png;base64,...)
CSS 中的 @import "./reset.css"合并到 <style> 标签中
CSS 中的 url("./font.woff2")CSS 中的 url(data:font/woff2;base64,...)
JS 中的 import "./styles.css"合并到 <style> 标签中
图片、字体、WASM 二进制、视频、音频文件、SVG —— 任何相对路径引用的文件都会被 base64 编码为 data: URI,直接嵌入 HTML。MIME 类型自动根据文件扩展名检测。 外部 URL(如 CDN 链接或绝对链接)保持不变,不做内联。

与 React 一起使用

React 应用开箱即用。Bun 会自动处理 JSX 转译和 npm 包解析。
terminal
bun install react react-dom
<!doctype html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>My App</title>
    <link rel="stylesheet" href="./styles.css" />
  </head>
  <body>
    <div id="root"></div>
    <script src="./app.tsx"></script>
  </body>
</html>
terminal
bun build --compile --target=browser ./index.html --outdir=dist
React、你的组件和你的 CSS 都打包进了 dist/index.html。上传这唯一文件到任何地方即可运行。

与 Tailwind CSS 一起使用

安装插件并在 HTML 或 CSS 中引用 Tailwind:
terminal
bun install --dev bun-plugin-tailwind
<!doctype html>
<html>
  <head>
    <link rel="stylesheet" href="tailwindcss" />
  </head>
  <body class="bg-gray-100 flex items-center justify-center min-h-screen">
    <div id="root"></div>
    <script src="./app.tsx"></script>
  </body>
</html>
使用 JavaScript API 通过插件构建:
https://mintcdn.com/ikxin/42j8wRmGt8kDDLLK/icons/typescript.svg?fit=max&auto=format&n=42j8wRmGt8kDDLLK&q=85&s=a2a397cd68603d207db5c5b5d620260abuild.ts
await Bun.build({
  entrypoints: ["./index.html"],
  compile: true,
  target: "browser",
  outdir: "./dist",
  plugins: [require("bun-plugin-tailwind")],
});
terminal
bun run build.ts
生成的 Tailwind CSS 会直接以内联 <style> 标签形式注入 HTML 文件。

工作原理

当你传入 --compile --target=browser 且入口是 HTML 文件时,Bun 会:
  1. 解析 HTML,发现所有 <script><link><img><video><audio><source> 及其他资源引用
  2. 将所有 JavaScript/TypeScript/JSX 打包为单个模块
  3. 将所有 CSS(包括 @import 链和 JS 中导入的 CSS)打包成一个样式表
  4. 将所有相对资源引用转换为 base64 的 data: URI
  5. 将打包后的 JS 以内联 <script type="module"> 形式放在 </body>
  6. 将打包后的 CSS 以内联 <style> 形式放在 <head>
  7. 输出一个无任何外部依赖的单个 .html 文件

压缩

添加 --minify 来压缩 JavaScript 和 CSS:
terminal
bun build --compile --target=browser --minify ./index.html --outdir=dist
或通过 API:
https://mintcdn.com/ikxin/42j8wRmGt8kDDLLK/icons/typescript.svg?fit=max&auto=format&n=42j8wRmGt8kDDLLK&q=85&s=a2a397cd68603d207db5c5b5d620260abuild.ts
await Bun.build({
  entrypoints: ["./index.html"],
  compile: true,
  target: "browser",
  outdir: "./dist",
  minify: true,
});

JavaScript API

你可以使用 Bun.build() 以编程方式生成独立 HTML:
https://mintcdn.com/ikxin/42j8wRmGt8kDDLLK/icons/typescript.svg?fit=max&auto=format&n=42j8wRmGt8kDDLLK&q=85&s=a2a397cd68603d207db5c5b5d620260abuild.ts
const result = await Bun.build({
  entrypoints: ["./index.html"],
  compile: true,
  target: "browser",
  outdir: "./dist", // 可选,省略则作为 BuildArtifact 输出
  minify: true,
});

if (!result.success) {
  console.error("构建失败:");
  for (const log of result.logs) {
    console.error(log);
  }
} else {
  console.log("构建成功:", result.outputs[0].path);
}
若省略 outdir,输出可作为 BuildArtifactresult.outputs 获取:
https://mintcdn.com/ikxin/42j8wRmGt8kDDLLK/icons/typescript.svg?fit=max&auto=format&n=42j8wRmGt8kDDLLK&q=85&s=a2a397cd68603d207db5c5b5d620260a
const result = await Bun.build({
  entrypoints: ["./index.html"],
  compile: true,
  target: "browser",
});

const html = await result.outputs[0].text();
await Bun.write("output.html", html);

多个 HTML 文件

你可以传入多个 HTML 文件作为入口,分别生成独立 HTML 文件:
terminal
bun build --compile --target=browser ./index.html ./about.html --outdir=dist

环境变量

--env 将环境变量内联到打包的 JavaScript 中:
terminal
API_URL=https://api.example.com bun build --compile --target=browser --env=inline ./index.html --outdir=dist
JavaScript 中对 process.env.API_URL 的引用会在构建时被替换为对应的字面量值。

限制

  • 不支持代码拆分 —— --splitting 不能与 --compile --target=browser 一起使用
  • 大文件资产 由于 base64 编码,体积会变大(比原二进制大33%)
  • 外部 URL(CDN 链接、绝对 URL)保持不变,只有相对路径资源会被内联