> ## Documentation Index
> Fetch the complete documentation index at: https://bun.zhcndoc.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 独立 HTML

> 将单页应用打包成一个无外部依赖的自包含 `.html` 文件

Bun 可以将整个前端打包成一个 **单个 `.html` 文件**，无需任何外部依赖。JavaScript、TypeScript、JSX、CSS、图片、字体、视频、WASM —— 所有内容均内联到一个文件中。

```bash terminal icon="terminal" theme={"theme":{"light":"github-light","dark":"dracula"}}
bun build --compile --target=browser ./index.html --outdir=dist
```

输出是一个完全自包含的 HTML 文档。没有相对路径。没有外部文件。无需服务器。只有一个 `.html` 文件，可以在任何浏览器中打开。

## 单文件。随处上传。

输出是一个单独的 `.html` 文件，你可以放到任何地方：

* **上传到 S3** 或任何静态文件托管服务 — 无需维护目录结构，只有一个文件
* **从桌面双击打开** — 在浏览器中打开并且可离线工作，不需要 localhost 服务器
* **嵌入到你的 webview 中** — 不用处理相对文件
* **插入到 `<iframe>` 中** — 使用单个文件 URL 在另一个页面中嵌入交互内容
* **从任何地方提供服务** — 任何 HTTP 服务器、CDN 或文件共享。一个文件，零配置。

无需安装任何东西，不用部署 `node_modules`，不用管理构建产物，也无需考虑相对路径。整个应用 —— 框架代码、样式表、图片等等 —— 都在这唯一的文件中。

## 真正的单文件

通常，发布网页意味着管理一个资产文件夹 —— HTML、JavaScript 包、CSS 文件、图片。只移动 HTML 文件，没了其他内容就会坏掉。浏览器以前试图解决这个问题：Safari 的 `.webarchive` 和 `.mhtml` 旨在将页面保存为单文件，但实际上它们会在电脑上解包成一堆松散文件 —— 违背了初衷。

独立 HTML 不同。输出是一个普通的 `.html` 文件。不是归档文件，也不是文件夹。一个文件，内装所有内容。每张图片、每个字体、每行 CSS 和 JavaScript 都通过标准的 `<style>` 标签、`<script>` 标签和 `data:` URI 直接嵌入 HTML。任何浏览器都能打开。任何服务器都能托管。任何文件托管都能存储。

这使得发布网页就像发布 PDF 一样方便 —— 单个文件，你可以随意移动、复制、上传或分享，无需担心路径断裂或资产丢失。

## 快速开始

<CodeGroup>
  ```html index.html icon="file-code" theme={"theme":{"light":"github-light","dark":"dracula"}}
  <!doctype html>
  <html>
    <head>
      <link rel="stylesheet" href="./styles.css" />
    </head>
    <body>
      <div id="root"></div>
      <script src="./app.tsx"></script>
    </body>
  </html>
  ```

  ```tsx app.tsx icon="https://mintcdn.com/bun-zhcndoc/cnUTwgMuf4cCrwC-/icons/typescript.svg?fit=max&auto=format&n=cnUTwgMuf4cCrwC-&q=85&s=e7767043c9e885c34f2d6c8fe2a95217" theme={"theme":{"light":"github-light","dark":"dracula"}}
  import React from "react";
  import { createRoot } from "react-dom/client";

  function App() {
    return <h1>来自单个 HTML 文件的问候！</h1>;
  }

  createRoot(document.getElementById("root")!).render(<App />);
  ```

  ```css styles.css icon="file-code" theme={"theme":{"light":"github-light","dark":"dracula"}}
  body {
    margin: 0;
    font-family: system-ui, sans-serif;
    background: #f5f5f5;
  }
  ```
</CodeGroup>

```bash terminal icon="terminal" theme={"theme":{"light":"github-light","dark":"dracula"}}
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 包解析。

```bash terminal icon="terminal" theme={"theme":{"light":"github-light","dark":"dracula"}}
bun install react react-dom
```

<CodeGroup>
  ```html index.html icon="file-code" theme={"theme":{"light":"github-light","dark":"dracula"}}
  <!doctype html>
  <html>
    <head>
      <meta charset="utf-8" />
      <meta name="viewport" content="width=device-width, initial-scale=1" />
      <title>我的应用</title>
      <link rel="stylesheet" href="./styles.css" />
    </head>
    <body>
      <div id="root"></div>
      <script src="./app.tsx"></script>
    </body>
  </html>
  ```

  ```tsx app.tsx icon="https://mintcdn.com/bun-zhcndoc/cnUTwgMuf4cCrwC-/icons/typescript.svg?fit=max&auto=format&n=cnUTwgMuf4cCrwC-&q=85&s=e7767043c9e885c34f2d6c8fe2a95217" theme={"theme":{"light":"github-light","dark":"dracula"}}
  import React, { useState } from "react";
  import { createRoot } from "react-dom/client";
  import { Counter } from "./components/Counter.tsx";

  function App() {
    return (
      <main>
        <h1>单文件 React 应用</h1>
        <Counter />
      </main>
    );
  }

  createRoot(document.getElementById("root")!).render(<App />);
  ```

  ```tsx components/Counter.tsx icon="https://mintcdn.com/bun-zhcndoc/cnUTwgMuf4cCrwC-/icons/typescript.svg?fit=max&auto=format&n=cnUTwgMuf4cCrwC-&q=85&s=e7767043c9e885c34f2d6c8fe2a95217" theme={"theme":{"light":"github-light","dark":"dracula"}}
  import React, { useState } from "react";

  export function Counter() {
    const [count, setCount] = useState(0);
    return <button onClick={() => setCount(count + 1)}>计数：{count}</button>;
  }
  ```
</CodeGroup>

```bash terminal icon="terminal" theme={"theme":{"light":"github-light","dark":"dracula"}}
bun build --compile --target=browser ./index.html --outdir=dist
```

React、你的组件和你的 CSS 都打包进了 `dist/index.html`。把这唯一文件上传到任何地方即可运行。

## 与 Tailwind CSS 一起使用

安装插件并在 HTML 或 CSS 中引用 Tailwind：

```bash terminal icon="terminal" theme={"theme":{"light":"github-light","dark":"dracula"}}
bun install --dev bun-plugin-tailwind
```

<CodeGroup>
  ```html index.html icon="file-code" theme={"theme":{"light":"github-light","dark":"dracula"}}
  <!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>
  ```

  ```tsx app.tsx icon="https://mintcdn.com/bun-zhcndoc/cnUTwgMuf4cCrwC-/icons/typescript.svg?fit=max&auto=format&n=cnUTwgMuf4cCrwC-&q=85&s=e7767043c9e885c34f2d6c8fe2a95217" theme={"theme":{"light":"github-light","dark":"dracula"}}
  import React from "react";
  import { createRoot } from "react-dom/client";

  function App() {
    return (
      <div className="bg-white rounded-lg shadow-lg p-8 max-w-md">
        <h1 className="text-2xl font-bold text-gray-800">你好 Tailwind</h1>
        <p className="text-gray-600 mt-2">这是一个单文件 HTML。</p>
      </div>
    );
  }

  createRoot(document.getElementById("root")!).render(<App />);
  ```
</CodeGroup>

使用 JavaScript API 通过插件构建：

```ts build.ts icon="https://mintcdn.com/bun-zhcndoc/cnUTwgMuf4cCrwC-/icons/typescript.svg?fit=max&auto=format&n=cnUTwgMuf4cCrwC-&q=85&s=e7767043c9e885c34f2d6c8fe2a95217" theme={"theme":{"light":"github-light","dark":"dracula"}}
await Bun.build({
  entrypoints: ["./index.html"],
  compile: true,
  target: "browser",
  outdir: "./dist",
  plugins: [require("bun-plugin-tailwind")],
});
```

```bash terminal icon="terminal" theme={"theme":{"light":"github-light","dark":"dracula"}}
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：

```bash terminal icon="terminal" theme={"theme":{"light":"github-light","dark":"dracula"}}
bun build --compile --target=browser --minify ./index.html --outdir=dist
```

或通过 API：

```ts build.ts icon="https://mintcdn.com/bun-zhcndoc/cnUTwgMuf4cCrwC-/icons/typescript.svg?fit=max&auto=format&n=cnUTwgMuf4cCrwC-&q=85&s=e7767043c9e885c34f2d6c8fe2a95217" theme={"theme":{"light":"github-light","dark":"dracula"}}
await Bun.build({
  entrypoints: ["./index.html"],
  compile: true,
  target: "browser",
  outdir: "./dist",
  minify: true,
});
```

## JavaScript API

你可以使用 `Bun.build()` 以编程方式生成独立 HTML：

```ts build.ts icon="https://mintcdn.com/bun-zhcndoc/cnUTwgMuf4cCrwC-/icons/typescript.svg?fit=max&auto=format&n=cnUTwgMuf4cCrwC-&q=85&s=e7767043c9e885c34f2d6c8fe2a95217" theme={"theme":{"light":"github-light","dark":"dracula"}}
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`，输出可以作为 `BuildArtifact` 从 `result.outputs` 获取：

```ts icon="https://mintcdn.com/bun-zhcndoc/cnUTwgMuf4cCrwC-/icons/typescript.svg?fit=max&auto=format&n=cnUTwgMuf4cCrwC-&q=85&s=e7767043c9e885c34f2d6c8fe2a95217" theme={"theme":{"light":"github-light","dark":"dracula"}}
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 文件：

```bash terminal icon="terminal" theme={"theme":{"light":"github-light","dark":"dracula"}}
bun build --compile --target=browser ./index.html ./about.html --outdir=dist
```

## 环境变量

使用 `--env` 将环境变量内联到打包的 JavaScript 中：

```bash terminal icon="terminal" theme={"theme":{"light":"github-light","dark":"dracula"}}
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）保持不变，只有相对路径资源会被内联
