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

# HTML

> Process HTML files with bundled assets using Bun's bundler

Bun's bundler can process HTML files as entrypoints, automatically bundling all referenced assets (scripts, stylesheets, images, etc.) and updating the HTML to reference the bundled files.

## Basic usage

Given an HTML file:

```html index.html theme={null}
<!DOCTYPE html>
<html>
  <head>
    <title>My App</title>
    <link rel="stylesheet" href="./styles.css" />
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="./app.ts"></script>
  </body>
</html>
```

Bundle it with:

```bash theme={null}
bun build ./index.html --outdir ./dist
```

The output will be:

```text theme={null}
dist/
  index.html
  app-[hash].js
  styles-[hash].css
```

And the HTML will be updated to reference the hashed files:

```html dist/index.html theme={null}
<!DOCTYPE html>
<html>
  <head>
    <title>My App</title>
    <link rel="stylesheet" href="./styles-a1b2c3.css" />
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="./app-d4e5f6.js"></script>
  </body>
</html>
```

## Supported elements

Bun's HTML processor recognizes and bundles the following elements:

### Scripts

```html theme={null}
<!-- Module scripts are bundled -->
<script type="module" src="./app.ts"></script>

<!-- Regular scripts are also bundled -->
<script src="./legacy.js"></script>

<!-- Inline scripts are preserved -->
<script>
  console.log("Hello!");
</script>
```

### Stylesheets

```html theme={null}
<!-- CSS files are bundled -->
<link rel="stylesheet" href="./styles.css" />

<!-- Multiple stylesheets are merged -->
<link rel="stylesheet" href="./reset.css" />
<link rel="stylesheet" href="./theme.css" />
```

### Images

```html theme={null}
<!-- Images are hashed and copied -->
<img src="./logo.png" alt="Logo" />

<!-- srcset is also processed -->
<img
  src="./hero.jpg"
  alt="Hero"
/>
```

### Other assets

```html theme={null}
<!-- Favicons -->
<link rel="icon" href="./favicon.ico" />
<link rel="apple-touch-icon" href="./apple-touch-icon.png" />

<!-- Fonts -->
<link
  rel="preload"
  href="./font.woff2"
  as="font"
  type="font/woff2"
  crossorigin
/>

<!-- Manifests -->
<link rel="manifest" href="./manifest.json" />

<!-- Video and audio -->
<video src="./video.mp4" />
<audio src="./audio.mp3" />
```

## External URLs

External URLs (those starting with `http://`, `https://`, or `//`) are preserved as-is:

```html theme={null}
<!-- These are NOT bundled -->
<script src="https://cdn.example.com/library.js"></script>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter" />
<img src="https://example.com/remote-image.jpg" />
```

## Public path

Use `--public-path` to prefix all asset URLs:

```bash theme={null}
bun build ./index.html --outdir ./dist --public-path /assets/
```

```html Output theme={null}
<script type="module" src="/assets/app-d4e5f6.js"></script>
<link rel="stylesheet" href="/assets/styles-a1b2c3.css" />
```

This is useful for CDN deployments:

```bash theme={null}
bun build ./index.html --outdir ./dist --public-path https://cdn.example.com/
```

## Minification

HTML is minified when `--minify` is enabled:

```bash theme={null}
bun build ./index.html --outdir ./dist --minify
```

This removes:

* Whitespace between elements
* HTML comments (except conditional comments)
* Unnecessary quotes around attribute values
* Optional closing tags

## Multiple HTML files

You can bundle multiple HTML files:

```bash theme={null}
bun build ./index.html ./about.html ./contact.html --outdir ./dist
```

Each HTML file becomes an independent entrypoint with its own set of bundled assets.

## Code splitting

When multiple HTML files share JavaScript or CSS, those assets can be code-split:

```bash theme={null}
bun build ./index.html ./about.html --outdir ./dist --splitting
```

Shared code is extracted into separate chunk files, and each HTML file references the appropriate chunks.

## JavaScript API

```ts theme={null}
await Bun.build({
  entrypoints: ["./index.html"],
  outdir: "./dist",
  minify: true,
  publicPath: "/assets/",
});
```

## Dynamic HTML generation

For server-side rendering or dynamic HTML generation, import HTML files in your JavaScript:

```ts server.ts theme={null}
import html from "./index.html";

const server = Bun.serve({
  port: 3000,
  fetch(req) {
    return new Response(html, {
      headers: { "Content-Type": "text/html" },
    });
  },
});
```

When bundled with `--target=bun`, the HTML import resolves to a manifest object for serving pre-bundled assets efficiently.

## Full-stack applications

Combine HTML processing with server-side code:

```ts server.ts theme={null}
import html from "./index.html";

const server = Bun.serve({
  port: 3000,
  fetch(req) {
    const url = new URL(req.url);
    
    // Serve the HTML for the root path
    if (url.pathname === "/") {
      return new Response(html, {
        headers: { "Content-Type": "text/html" },
      });
    }
    
    // API routes
    if (url.pathname === "/api/data") {
      return Response.json({ message: "Hello!" });
    }
    
    return new Response("Not found", { status: 404 });
  },
});

console.log(`Server running at http://localhost:${server.port}`);
```

Build for production:

```bash theme={null}
bun build ./server.ts --outdir ./dist --target=bun --compile
```

This creates a standalone executable with all assets embedded.

## Templates and components

For more complex HTML generation, use template literals or JSX:

```tsx server.tsx theme={null}
function Layout({ children }: { children: any }) {
  return (
    <html>
      <head>
        <title>My App</title>
        <link rel="stylesheet" href="./styles.css" />
      </head>
      <body>
        <div id="root">{children}</div>
        <script type="module" src="./app.ts" />
      </body>
    </html>
  );
}

const server = Bun.serve({
  port: 3000,
  fetch(req) {
    const html = (
      <Layout>
        <h1>Welcome!</h1>
      </Layout>
    );
    
    return new Response(html, {
      headers: { "Content-Type": "text/html" },
    });
  },
});
```

## Asset hashing

All bundled assets are content-hashed by default:

```
app-a1b2c3d4.js
styles-e5f6g7h8.css
logo-i9j0k1l2.png
```

This enables:

* Long-term caching (files can be cached forever)
* Cache invalidation (changing content changes the hash)
* Parallel loading (no version conflicts)

## Source maps

Generate source maps for JavaScript bundles:

```bash theme={null}
bun build ./index.html --outdir ./dist --sourcemap=external
```

Source map files are placed alongside their corresponding bundles:

```
dist/
  index.html
  app-a1b2c3.js
  app-a1b2c3.js.map
```

## Examples

### Static site

```html index.html theme={null}
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Static Site</title>
    <link rel="stylesheet" href="./styles.css" />
  </head>
  <body>
    <header>
      <img src="./logo.svg" alt="Logo" />
      <nav>
        <a href="/">Home</a>
        <a href="/about">About</a>
      </nav>
    </header>
    <main id="content"></main>
    <script type="module" src="./app.ts"></script>
  </body>
</html>
```

```bash theme={null}
bun build ./index.html --outdir ./dist --minify
```

### Single-page application

```html index.html theme={null}
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>SPA</title>
    <link rel="stylesheet" href="./src/styles/main.css" />
  </head>
  <body>
    <div id="app"></div>
    <script type="module" src="./src/main.tsx"></script>
  </body>
</html>
```

```tsx src/main.tsx theme={null}
import { render } from "react-dom";
import { App } from "./App";

render(<App />, document.getElementById("app"));
```

```bash theme={null}
bun build ./index.html --outdir ./dist --minify --splitting
```

### Progressive Web App

```html index.html theme={null}
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>PWA</title>
    <link rel="manifest" href="./manifest.json" />
    <link rel="icon" href="./favicon.ico" />
    <link rel="apple-touch-icon" href="./icon-192.png" />
    <meta name="theme-color" content="#000000" />
    <link rel="stylesheet" href="./styles.css" />
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="./app.ts"></script>
    <script>
      if ('serviceWorker' in navigator) {
        navigator.serviceWorker.register('./sw.js');
      }
    </script>
  </body>
</html>
```

```bash theme={null}
bun build ./index.html --outdir ./dist --minify --public-path /
```

## Troubleshooting

### Paths not resolving

Make sure all asset paths are relative to the HTML file:

```html theme={null}
<!-- Good -->
<script src="./app.ts"></script>
<img src="./images/logo.png" />

<!-- Bad -->
<script src="app.ts"></script>
<img src="images/logo.png" />
```

### Assets not found

Check that the referenced files exist relative to the HTML file:

```text theme={null}
project/
  index.html
  app.ts
  images/
    logo.png
```

### External URLs bundled

Ensure external URLs start with `http://`, `https://`, or `//`:

```html theme={null}
<!-- These are external -->
<script src="https://cdn.example.com/lib.js"></script>
<script src="//cdn.example.com/lib.js"></script>

<!-- This will be bundled -->
<script src="cdn.example.com/lib.js"></script>
```

### Inline scripts interfering

Inline scripts run immediately and might interfere with bundled modules. Use `type="module"` for modern code:

```html theme={null}
<!-- Modern approach -->
<script type="module" src="./app.ts"></script>

<!-- Inline module -->
<script type="module">
  import { init } from "./app.ts";
  init();
</script>
```
