Skip to content

import Build from "/snippets/cli/build.mdx";

Bun 的快速原生打包器可以通過 bun build CLI 命令或 Bun.build() JavaScript API 使用。

概覽

  • JS API: await Bun.build({ entrypoints, outdir })
  • CLI: bun build <entry> --outdir ./out
  • 監聽:--watch 用於增量重建
  • 目標:--target browser|bun|node
  • 格式:--format esm|cjs|iife(cjs/iife 為實驗性)

JavaScript

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './build',
});

CLI

bash
bun build ./index.tsx --outdir ./build

它非常快。下面的數字代表了在 esbuild 的 three.js 基准測試 中的性能表現。

為什麼要打包?

打包器是 JavaScript 生態系統中的關鍵基礎設施。簡要概述為什麼打包如此重要:

  • 減少 HTTP 請求。 node_modules 中的單個包可能由數百個文件組成,大型應用程序可能有數十個這樣的依賴項。很快就會發現,通過單獨的 HTTP 請求加載這些文件中的每一個變得不可行,因此打包器用於將我們的應用程序源代碼轉換為較少數量的自包含"bundle",可以通過單個請求加載。
  • 代碼轉換。 現代應用程序通常使用 TypeScript、JSX 和 CSS 模塊等語言或工具構建,所有這些都必須在被瀏覽器使用之前轉換為純 JavaScript 和 CSS。打包器是配置這些轉換的自然場所。
  • 框架功能。 框架依賴打包器插件和代碼轉換來實現常見模式,如文件系統路由、客戶端 - 服務器代碼共存(想想 getServerSideProps 或 Remix loaders)和服務器組件。
  • 全棧應用程序。 Bun 的打包器可以在單個命令中處理服務器和客戶端代碼,實現優化的生產構建和單文件可執行文件。通過構建時 HTML 導入,您可以將整個應用程序(前端資源和後端服務器)打包到單個可部署單元中。

讓我們進入打包器 API。

NOTE

Bun 打包器不打算替代 `tsc` 進行類型檢查或生成類型聲明。

基本示例

讓我們構建第一個打包。您有以下兩個文件,它們實現了一個簡單的客戶端渲染 React 應用程序。

tsx
import * as ReactDOM from "react-dom/client";
import { Component } from "./Component";

const root = ReactDOM.createRoot(document.getElementById("root")!);
root.render(<Component message="Sup!" />);
tsx
export function Component(props: { message: string }) {
  return <h1>{props.message}</h1>;
}

這裡,index.tsx 是我們應用程序的"入口點"。通常,這將是一個執行某些副作用的腳本,比如啟動服務器或——在這種情況下——初始化 React 根。因為我們使用 TypeScript 和 JSX,所以在發送到瀏覽器之前需要打包我們的代碼。

要創建我們的打包:

ts
await Bun.build({
  entrypoints: ["./index.tsx"],
  outdir: "./out",
});
bash
bun build ./index.tsx --outdir ./out

對於 entrypoints 中指定的每個文件,Bun 將生成一個新的打包。這個打包將寫入磁盤到 ./out 目錄(從當前工作目錄解析)。運行構建後,文件系統看起來像這樣:

text
.
├── index.tsx
├── Component.tsx
└── out
    └── index.js

out/index.js 的內容看起來像這樣:

js
// out/index.js
// ...
// ~20k 行代碼
// 包括 `react-dom/client` 的內容及其所有依賴項
// 這是定義 $jsxDEV 和 $createRoot 函數的地方

// Component.tsx
function Component(props) {
  return $jsxDEV(
    "p",
    {
      children: props.message,
    },
    undefined,
    false,
    undefined,
    this,
  );
}

// index.tsx
var rootNode = document.getElementById("root");
var root = $createRoot(rootNode);
root.render(
  $jsxDEV(
    Component,
    {
      message: "Sup!",
    },
    undefined,
    false,
    undefined,
    this,
  ),
);

監聽模式

與運行時和測試運行器一樣,打包器原生支持監聽模式。

bash
bun build ./index.tsx --outdir ./out --watch

內容類型

與 Bun 運行時一樣,打包器支持一系列文件類型。下表分解了打包器的標准"加載器"集。有關完整文檔,請參閱 打包器 > 文件類型

擴展名詳情
.js .jsx .cjs .mjs .mts .cts .ts .tsx使用 Bun 的內置轉譯器解析文件並將 TypeScript/JSX 語法轉譯為純 JavaScript。打包器執行一組默認轉換,包括死代碼消除和搖樹優化。目前 Bun 不嘗試向下轉換語法;如果您使用最近的 ECMAScript 語法,這將反映在打包代碼中。
.jsonJSON 文件被解析並作為 JavaScript 對象內聯到打包中。

js<br/>import pkg from "./package.json";<br/>pkg.name; // => "my-package"<br/>
.jsonc帶注釋的 JSON。文件被解析並作為 JavaScript 對象內聯到打包中。

js<br/>import config from "./config.jsonc";<br/>config.name; // => "my-config"<br/>
.tomlTOML 文件被解析並作為 JavaScript 對象內聯到打包中。

js<br/>import config from "./bunfig.toml";<br/>config.logLevel; // => "debug"<br/>
.yaml .ymlYAML 文件被解析並作為 JavaScript 對象內聯到打包中。

js<br/>import config from "./config.yaml";<br/>config.name; // => "my-app"<br/>
.txt文本文件的內容被讀取並作為字符串內聯到打包中。

js<br/>import contents from "./file.txt";<br/>console.log(contents); // => "Hello, world!"<br/>
.htmlHTML 文件被處理,任何引用的資源(腳本、樣式表、圖像)都被打包。
.cssCSS 文件被打包在一起,輸出到輸出目錄中的單個 .css 文件中。
.node .wasm這些文件由 Bun 運行時支持,但在打包期間它們被視為資源。

資源

如果打包器遇到帶有無法識別擴展名的導入,它會將導入的文件視為外部文件。引用的文件按原樣復制到 outdir,導入解析為文件的路徑。

ts
// 打包入口點
import logo from "./logo.svg";
console.log(logo);
ts
// 打包輸出
var logo = "./logo-a7305bdef.svg";
console.log(logo);

文件加載器的確切行為也受到 namingpublicPath 的影響。

插件

此表中描述的行為可以使用插件覆蓋或擴展。有關完整文檔,請參閱 打包器 > 加載器 頁面。

API

entrypoints

應用程序入口點的路徑數組。將為每個入口點生成一個打包。

JavaScript

ts
const result = await Bun.build({
  entrypoints: ["./index.ts"]
});

CLI

bash
bun build ./index.ts

outdir

輸出文件將寫入的目錄。

JavaScript

ts
const result = await Bun.build({
  entrypoints: ['./index.ts'],
  outdir: './out'
});
// => { success: boolean, outputs: `BuildArtifact[]`, logs: `BuildMessage[]` }

CLI

bash
bun build ./index.ts --outdir ./out

如果未將 outdir 傳遞給 JavaScript API,打包的代碼將不會寫入磁盤。打包的文件在 BuildArtifact 對象數組中返回。這些對象是帶有額外屬性的 Blob;有關完整文檔,請參閱 輸出

ts
const result = await Bun.build({
  entrypoints: ["./index.ts"],
});

for (const res of result.outputs) {
  // 可以作為 blob 使用
  await res.text();

  // Bun 將設置 Content-Type 和 Etag 頭
  new Response(res);

  // 可以手動寫入,但您應該在這種情況下使用 `outdir`。
  Bun.write(path.join("out", res.path), res);
}

當設置 outdir 時,BuildArtifact 上的 path 屬性將是寫入位置的絕對路徑。

target

打包的預期執行環境。

JavaScript

ts
await Bun.build({
  entrypoints: ['./index.ts'],
  outdir: './out',
  target: 'browser', // 默認
})

CLI

bash
bun build ./index.ts --outdir ./out --target browser

根據目標,Bun 將應用不同的模塊解析規則和優化。

默認。 用於生成旨在由瀏覽器執行的打包。在解析導入時優先考慮 "browser" 導出條件。導入任何內置模塊(如 node:eventsnode:path)將有效,但調用某些函數(如 fs.readFile)將無效。

用於生成旨在由 Bun 運行時運行的打包。在許多情況下,沒有必要打包服務器端代碼;您可以直接執行源代碼而無需修改。但是,打包您的服務器代碼可以減少啟動時間並提高運行性能。這是用於構建具有構建時 HTML 導入的全棧應用程序的目標,其中服務器和客戶端代碼打包在一起。

使用 target: "bun" 生成的所有打包都標有特殊的 // @bun 指令,這表明 Bun 運行時在執行前無需重新轉譯文件。

如果任何入口點包含 Bun shebang(#!/usr/bin/env bun),打包器將默認使用 target: "bun" 而不是 "browser"

當一起使用 target: "bun"format: "cjs" 時,會添加 // @bun @bun-cjs 指令,並且 CommonJS 包裝器函數與 Node.js 不兼容。

用於生成旨在由 Node.js 運行的打包。在解析導入時優先考慮 "node" 導出條件,並輸出 .mjs。將來,這將自動填充 Bun 全局和其他內置 bun:* 模塊,盡管這尚未實現。

format

指定在生成的打包中使用的模塊格式。

Bun 默認為 "esm",並提供 "cjs""iife" 的實驗性支持。

format: "esm" - ES 模塊

這是默認格式,支持 ES 模塊語法,包括頂層 await、import.meta 等。

JavaScript

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  format: "esm",
})

CLI

bash
bun build ./index.tsx --outdir ./out --format esm

要在瀏覽器中使用 ES 模塊語法,將 format 設置為 "esm" 並確保您的 <script type="module"> 標簽設置了 type="module"

format: "cjs" - CommonJS

要構建 CommonJS 模塊,將 format 設置為 "cjs"。選擇 "cjs" 時,默認目標從 "browser" (esm) 更改為 "node" (cjs)。使用 format: "cjs"target: "node" 轉譯的 CommonJS 模塊可以在 Bun 和 Node.js 中執行(假設使用的 API 受兩者支持)。

JavaScript

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  format: "cjs",
})

CLI

bash
bun build ./index.tsx --outdir ./out --format cjs

format: "iife" - IIFE

待辦:一旦我們支持 globalNames,就記錄 IIFE。

jsx

配置 JSX 轉換行為。允許細粒度控制 JSX 的編譯方式。

經典運行時示例(使用 factoryfragment):

ts
await Bun.build({
  entrypoints: ["./app.tsx"],
  outdir: "./out",
  jsx: {
    factory: "h",
    fragment: "Fragment",
    runtime: "classic",
  },
});
bash
# JSX 配置通過 bunfig.toml 或 tsconfig.json 處理
bun build ./app.tsx --outdir ./out

自動運行時示例(使用 importSource):

ts
await Bun.build({
  entrypoints: ["./app.tsx"],
  outdir: "./out",
  jsx: {
    importSource: "preact",
    runtime: "automatic",
  },
});
bash
# JSX 配置通過 bunfig.toml 或 tsconfig.json 處理
bun build ./app.tsx --outdir ./out

splitting

是否啟用代碼分割。

JavaScript

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  splitting: false, // 默認
})

CLI

bash
bun build ./index.tsx --outdir ./out --splitting

當為 true 時,打包器將啟用代碼分割。當多個入口點都導入相同的文件、模塊或一組文件/模塊時,將共享代碼分割到單獨的打包中通常很有用。這個共享打包被稱為 chunk。考慮以下文件:

ts
import { shared } from "./shared.ts";
ts
import { shared } from "./shared.ts";
ts
export const shared = "shared";

要打包 entry-a.tsentry-b.ts 並啟用代碼分割:

JavaScript

ts
await Bun.build({
  entrypoints: ['./entry-a.ts', './entry-b.ts'],
  outdir: './out',
  splitting: true,
})

CLI

bash
bun build ./entry-a.ts ./entry-b.ts --outdir ./out --splitting

運行此構建將生成以下文件:

text
.
├── entry-a.tsx
├── entry-b.tsx
├── shared.tsx
└── out
    ├── entry-a.js
    ├── entry-b.js
    └── chunk-2fce6291bf86559d.js

生成的 chunk-2fce6291bf86559d.js 文件包含共享代碼。為避免沖突,文件名默認自動包含內容哈希。這可以使用 naming 自定義。

plugins

打包期間使用的插件列表。

ts
await Bun.build({
  entrypoints: ["./index.tsx"],
  outdir: "./out",
  plugins: [
    /* ... */
  ],
});

Bun 為 Bun 的運行時和打包器實現了通用插件系統。有關完整文檔,請參閱 插件文檔

env

控制打包期間如何處理環境變量。在內部,這使用 define 將環境變量注入到打包中,但更容易指定要注入的環境變量。

env: "inline"

通過將 process.env.FOO 引用轉換為包含實際環境變量值的字符串字面量,將環境變量注入到打包輸出中。

JavaScript

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  env: "inline",
})

CLI

bash
bun build ./index.tsx --outdir ./out --env inline

對於下面的輸入:

js
// input.js
console.log(process.env.FOO);
console.log(process.env.BAZ);

生成的打包將包含以下代碼:

js
// output.js
console.log("bar");
console.log("123");

env: "PUBLIC_*" (前綴)

內聯與給定前綴(* 字符之前的部分)匹配的環境變量,將 process.env.FOO 替換為實際環境變量值。這對於選擇性地內聯環境變量(如公共 URL 或客戶端令牌)很有用,而無需擔心將私有憑據注入輸出打包中。

JavaScript

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  
  // 內聯所有以 "ACME_PUBLIC_" 開頭的環境變量
  env: "ACME_PUBLIC_*",
})

CLI

bash
bun build ./index.tsx --outdir ./out --env ACME_PUBLIC_*

例如,給定以下環境變量:

bash
FOO=bar BAZ=123 ACME_PUBLIC_URL=https://acme.com

和源代碼:

tsx
console.log(process.env.FOO);
console.log(process.env.ACME_PUBLIC_URL);
console.log(process.env.BAZ);

生成的打包將包含以下代碼:

js
console.log(process.env.FOO);
console.log("https://acme.com");
console.log(process.env.BAZ);

env: "disable"

完全禁用環境變量注入。

sourcemap

指定要生成的 sourcemap 類型。

JavaScript

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  sourcemap: 'linked', // 默認 'none'
})

CLI

bash
bun build ./index.tsx --outdir ./out --sourcemap linked
描述
"none"默認。不生成 sourcemap。
"linked"使用 //# sourceMappingURL 注釋鏈接兩個文件,為每個 *.js 打包創建單獨的 *.js.map 文件。需要設置 --outdir。這可以使用 --public-path 自定義。

js<br/>// <此處為打包代碼><br/><br/>//# sourceMappingURL=bundle.js.map<br/>
"external"創建單獨的 *.js.map 文件,與每個 *.js 打包一起,不插入 //# sourceMappingURL 注釋。

生成的打包包含可用於將打包與其對應的 sourcemap 關聯的調試 ID。此 debugId 作為注釋添加到文件底部。

js<br/>// <生成的打包代碼><br/><br/>//# debugId=<DEBUG ID><br/>
"inline"生成 sourcemap 並作為 base64 負載附加到生成的打包末尾。

js<br/>// <此處為打包代碼><br/><br/>//# sourceMappingURL=data:application/json;base64,<encoded sourcemap here><br/>

關聯的 *.js.map sourcemap 將是包含等效 debugId 屬性的 JSON 文件。

minify

是否啟用壓縮。默認 false

NOTE

當目標為 `bun` 時,標識符將默認被壓縮。

要啟用所有壓縮選項:

JavaScript

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  minify: true, // 默認 false
})

CLI

```bash
bun build ./index.tsx --outdir ./out --minify
```

要細粒度啟用某些壓縮:

JavaScript

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  minify: {
    whitespace: true,
    identifiers: true,
    syntax: true,
  },
})

CLI

bash
bun build ./index.tsx --outdir ./out --minify-whitespace --minify-identifiers --minify-syntax

external

要視為外部的導入路徑列表。默認 []

JavaScript

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  external: ["lodash", "react"], // 默認:[]
})

CLI

bash
bun build ./index.tsx --outdir ./out --external lodash --external react

外部導入是不會包含在最終打包中的導入。相反,導入語句將保持原樣,在運行時解析。

例如,考慮以下入口點文件:

tsx
import _ from "lodash";
import { z } from "zod";

const value = z.string().parse("Hello world!");
console.log(_.upperCase(value));

通常,打包 index.tsx 將生成包含 "zod" 包完整源代碼的打包。相反,如果我們想保持導入語句原樣,我們可以將其標記為外部:

JavaScript

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  external: ['zod'],
})

CLI

bash
bun build ./index.tsx --outdir ./out --external zod

生成的打包看起來像這樣:

js
import { z } from "zod";

// ...
// "lodash" 包的內容
// 包括 `_.upperCase` 函數

var value = z.string().parse("Hello world!");
console.log(_.upperCase(value));

要將所有導入標記為外部,使用通配符 *

JavaScript

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  external: ['*'],
})

CLI

bash
bun build ./index.tsx --outdir ./out --external '*'

packages

控制是否包含包依賴項到打包中。可能的值:bundle(默認)、external。Bun 將任何不以 .../ 開頭的路徑的導入視為包。

JavaScript

ts
await Bun.build({
  entrypoints: ['./index.ts'],
  packages: 'external',
})

CLI

bash
bun build ./index.ts --packages external

naming

自定義生成的文件名。默認 ./[dir]/[name].[ext]

JavaScript

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  naming: "[dir]/[name].[ext]", // 默認
})

CLI

bash
bun build ./index.tsx --outdir ./out --entry-naming "[dir]/[name].[ext]"

默認情況下,生成的打包名稱基於相關入口點的名稱。

text
.
├── index.tsx
└── out
    └── index.js

使用多個入口點時,生成的文件層次結構將反映入口點的目錄結構。

text
.
├── index.tsx
└── nested
    └── index.tsx
└── out
    ├── index.js
    └── nested
        └── index.js

可以使用 naming 字段自定義生成文件的名稱和位置。此字段接受用於為所有對應於入口點的打包生成文件名的模板字符串,其中以下標記被替換為它們的相應值:

  • [name] - 入口點文件的名稱,不含擴展名。
  • [ext] - 生成的打包的擴展名。
  • [hash] - 打包內容的哈希。
  • [dir] - 從項目根目錄到源文件父目錄的相對路徑。

例如:

標記[name][ext][hash][dir]
./index.tsxindexjsa1b2c3d4"" (空字符串)
./nested/entry.tsentryjsc3d4e5f6"nested"

我們可以組合這些標記來創建模板字符串。例如,要在生成的打包名稱中包含哈希:

JavaScript

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  naming: 'files/[dir]/[name]-[hash].[ext]',
})

CLI

bash
bun build ./index.tsx --outdir ./out --entry-naming 'files/[dir]/[name]-[hash].[ext]'

此構建將生成以下文件結構:

text
.
├── index.tsx
└── out
    └── files
        └── index-a1b2c3d4.js

當為 naming 字段提供字符串時,它僅用於對應於入口點的打包。chunk 和復制資源的名稱不受影響。使用 JavaScript API,可以為每種類型的生成文件指定單獨的模板字符串。

JavaScript

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  naming: {
    // 默認值
    entry: '[dir]/[name].[ext]',
    chunk: '[name]-[hash].[ext]',
    asset: '[name]-[hash].[ext]',
  },
})

CLI

bash
bun build ./index.tsx --outdir ./out \
  --entry-naming '[dir]/[name].[ext]' \
  --chunk-naming '[name]-[hash].[ext]' \
  --asset-naming '[name]-[hash].[ext]'

root

項目的根目錄。

JavaScript

ts
await Bun.build({
  entrypoints: ['./pages/a.tsx', './pages/b.tsx'],
  outdir: './out',
  root: '.',
})

CLI

bash
bun build ./pages/a.tsx ./pages/b.tsx --outdir ./out --root .

如果未指定,它被計算為所有入口點文件的第一個共同祖先。考慮以下文件結構:

text
.
└── pages
  └── index.tsx
  └── settings.tsx

我們可以在 pages 目錄中構建兩個入口點:

JavaScript

js
await Bun.build({
  entrypoints: ['./pages/index.tsx', './pages/settings.tsx'],
  outdir: './out',
})

CLI

bash
bun build ./pages/index.tsx ./pages/settings.tsx --outdir ./out

這將生成如下文件結構:

text
.
└── pages
  └── index.tsx
  └── settings.tsx
└── out
  └── index.js
  └── settings.js

由於 pages 目錄是入口點文件的第一個共同祖先,它被視為項目根目錄。這意味著生成的打包位於 out 目錄的頂層;沒有 out/pages 目錄。

可以通過指定 root 選項覆蓋此行為:

JavaScript

js
await Bun.build({
  entrypoints: ['./pages/index.tsx', './pages/settings.tsx'],
  outdir: './out',
  root: '.',
})

CLI

bash
bun build ./pages/index.tsx ./pages/settings.tsx --outdir ./out --root .

通過指定 . 作為 root,生成的文件結構將如下所示:

.
└── pages
  └── index.tsx
  └── settings.tsx
└── out
  └── pages
    └── index.js
    └── settings.js

publicPath

要附加到打包代碼中任何導入路徑的前綴。

在許多情況下,生成的打包將不包含導入語句。畢竟,打包的目標是將所有代碼組合到一個文件中。但是,生成的打包將包含導入語句的情況有很多。

  • 資源導入 — 導入無法識別的文件類型(如 *.svg)時,打包器會移交給文件加載器,後者將文件按原樣復制到 outdir。導入被轉換為變量
  • 外部模塊 — 文件和模塊可以標記為外部,在這種情況下它們將不包含在打包中。相反,導入語句將保留在最終打包中。
  • 代碼分割。 當啟用 splitting 時,打包器可能生成單獨的 "chunk" 文件,表示在多個入口點之間共享的代碼。

在任何這些情況下,最終打包可能包含指向其他文件的路徑。默認情況下,這些導入是相對的。這是一個簡單資源導入的示例:

ts
import logo from "./logo.svg";
console.log(logo);
ts
var logo = "./logo-a7305bdef.svg";
console.log(logo);

設置 publicPath 將使用指定值作為所有文件路徑的前綴。

JavaScript

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  publicPath: 'https://cdn.example.com/', // 默認是 undefined
})

CLI

bash
bun build ./index.tsx --outdir ./out --public-path 'https://cdn.example.com/'

輸出文件現在看起來像這樣。

js
var logo = "https://cdn.example.com/logo-a7305bdef.svg";

define

構建時要替換的全局標識符映射。此對象的鍵是標識符名稱,值是將內聯的 JSON 字符串。

JavaScript

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  define: {
    STRING: JSON.stringify("value"),
    "nested.boolean": "true",
  },
})

CLI

bash
bun build ./index.tsx --outdir ./out --define STRING='"value"' --define nested.boolean=true

loader

文件擴展名到內置加載器名稱的映射。這可用於快速自定義如何加載某些文件。

JavaScript

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  loader: {
    ".png": "dataurl",
    ".txt": "file",
  },
})

CLI

bash
bun build ./index.tsx --outdir ./out --loader .png:dataurl --loader .txt:file

要添加到最終打包的橫幅,這可以是 React 的 use client 指令或代碼的許可證注釋塊等。

JavaScript

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  banner: 'use client;'
})

CLI

bash
bun build ./index.tsx --outdir ./out --banner 'use client";'

要添加到最終打包的頁腳,這可以是許可證的注釋塊或有趣的彩蛋。

JavaScript

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  footer: '// built with love in SF'
})

CLI

bash
bun build ./index.tsx --outdir ./out --footer '// built with love in SF'

drop

從打包中移除函數調用。例如,--drop=console 將移除所有對 console.log 的調用。調用的參數也將被移除,無論這些參數是否有副作用。丟棄 debugger 將移除所有 debugger 語句。

JavaScript

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  drop: ["console", "debugger", "anyIdentifier.or.propertyAccess"],
})

CLI

bash
bun build ./index.tsx --outdir ./out --drop console --drop debugger

輸出

Bun.build 函數返回 Promise<BuildOutput>,定義為:

ts
interface BuildOutput {
  outputs: BuildArtifact[];
  success: boolean;
  logs: Array<object>; // 詳見文檔
}

interface BuildArtifact extends Blob {
  kind: "entry-point" | "chunk" | "asset" | "sourcemap";
  path: string;
  loader: Loader;
  hash: string | null;
  sourcemap: BuildArtifact | null;
}

outputs 數組包含構建生成的所有文件。每個工件都實現了 Blob 接口。

ts
const build = await Bun.build({
  /* */
});

for (const output of build.outputs) {
  await output.arrayBuffer(); // => ArrayBuffer
  await output.bytes(); // => Uint8Array
  await output.text(); // string
}

每個工件還包含以下屬性:

屬性描述
kind此文件是什麼類型的構建輸出。構建生成打包的入口點、代碼分割 "chunks"、sourcemap、字節碼和復制的資源(如圖像)。
path磁盤上文件的絕對路徑
loader用於解釋文件的加載器。請參閱 打包器 > 加載器 了解 Bun 如何將文件擴展名映射到適當的內置加載器。
hash文件內容的哈希。始終為資源定義。
sourcemap與此文件對應的 sourcemap 文件(如果生成)。僅為入口點和 chunk 定義。

BunFile 類似,BuildArtifact 對象可以直接傳遞到 new Response() 中。

ts
const build = await Bun.build({
  /* */
});

const artifact = build.outputs[0];

// Content-Type 頭自動設置
return new Response(artifact);

Bun 運行時實現了 BuildArtifact 對象的特殊漂亮打印,以便更容易調試。

ts
// build.ts
const build = await Bun.build({
  /* */
});

const artifact = build.outputs[0];
console.log(artifact);
bash
bun run build.ts

BuildArtifact (entry-point) {
  path: "./index.js",
  loader: "tsx",
  kind: "entry-point",
  hash: "824a039620219640",
  Blob (74756 bytes) {
    type: "text/javascript;charset=utf-8"
  },
  sourcemap: BuildArtifact (sourcemap) {
    path: "./index.js.map",
    loader: "file",
    kind: "sourcemap",
    hash: "e7178cda3e72e301",
    Blob (24765 bytes) {
      type: "application/json;charset=utf-8"
    },
    sourcemap: null
  }
}

字節碼

bytecode: boolean 選項可用於為任何 JavaScript/TypeScript 入口點生成字節碼。這可以大大提高大型應用程序的啟動時間。僅支持 "cjs" 格式,僅支持 "target": "bun" 並依賴於匹配的 Bun 版本。這為每個入口點添加相應的 .jsc 文件。

JavaScript

ts
await Bun.build({
  entrypoints: ["./index.tsx"],
  outdir: "./out",
  bytecode: true,
})

CLI

bash
bun build ./index.tsx --outdir ./out --bytecode

可執行文件

Bun 支持將 JavaScript/TypeScript 入口點"編譯"為獨立的可執行文件。此可執行文件包含 Bun 二進制文件的副本。

bash
bun build ./cli.tsx --outfile mycli --compile
./mycli

有關完整文檔,請參閱 打包器 > 可執行文件

日志和錯誤

失敗時,Bun.build 返回帶有 AggregateError 的拒絕 Promise。這可以記錄到控制台以漂亮打印錯誤列表,或使用 try/catch 塊以編程方式讀取。

ts
try {
  const result = await Bun.build({
    entrypoints: ["./index.tsx"],
    outdir: "./out",
  });
} catch (e) {
  // TypeScript 不允許在 catch 子句上標注
  const error = e as AggregateError;
  console.error("Build Failed");

  // 示例:使用內置格式化器
  console.error(error);

  // 示例:將失敗序列化為 JSON 字符串。
  console.error(JSON.stringify(error, null, 2));
}

大多數時候,不需要顯式的 try/catch,因為 Bun 會整潔地打印未捕獲的異常。只需在 Bun.build 調用上使用頂層 await 就足夠了。

error.errors 中的每個項目都是 BuildMessageResolveMessage 的實例(Error 的子類),包含每個錯誤的詳細信息。

ts
class BuildMessage {
  name: string;
  position?: Position;
  message: string;
  level: "error" | "warning" | "info" | "debug" | "verbose";
}

class ResolveMessage extends BuildMessage {
  code: string;
  referrer: string;
  specifier: string;
  importKind: ImportKind;
}

構建成功時,返回的對象包含 logs 屬性,其中包含打包器警告和信息消息。

ts
const result = await Bun.build({
  entrypoints: ["./index.tsx"],
  outdir: "./out",
});

if (result.logs.length > 0) {
  console.warn("Build succeeded with warnings:");
  for (const message of result.logs) {
    // Bun 將漂亮打印消息對象
    console.warn(message);
  }
}

參考

ts
interface Bun {
  build(options: BuildOptions): Promise<BuildOutput>;
}

interface BuildConfig {
  entrypoints: string[]; // 文件路徑列表
  outdir?: string; // 輸出目錄
  target?: Target; // 默認:"browser"
  /**
   * 輸出模塊格式。頂層 await 僅支持 `"esm"`。
   *
   * 可以是:
   * - `"esm"`
   * - `"cjs"`(**實驗性**)
   * - `"iife"`(**實驗性**)
   *
   * @default "esm"
   */
  format?: "esm" | "cjs" | "iife";
  /**
   * 用於控制 JSX 轉換行為的 JSX 配置對象
   */
  jsx?: {
    runtime?: "automatic" | "classic";
    importSource?: string;
    factory?: string;
    fragment?: string;
    sideEffects?: boolean;
    development?: boolean;
  };
  naming?:
    | string
    | {
        chunk?: string;
        entry?: string;
        asset?: string;
      };
  root?: string; // 項目根目錄
  splitting?: boolean; // 默認 true,啟用代碼分割
  plugins?: BunPlugin[];
  external?: string[];
  packages?: "bundle" | "external";
  publicPath?: string;
  define?: Record<string, string>;
  loader?: { [k in string]: Loader };
  sourcemap?: "none" | "linked" | "inline" | "external" | boolean; // 默認:"none", true -> "inline"
  /**
   * 解析導入時使用的 package.json `exports` 條件
   *
   * 等同於 `bun build` 或 `bun run` 中的 `--conditions`。
   *
   * https://nodejs.org/api/packages.html#exports
   */
  conditions?: Array<string> | string;

  /**
   * 控制打包期間如何處理環境變量。
   *
   * 可以是以下之一:
   * - `"inline"`:通過將 `process.env.FOO` 引用轉換為包含實際環境變量值的字符串字面量,將環境變量注入到打包輸出中
   * - `"disable"`:完全禁用環境變量注入
   * - 以 `*` 結尾的字符串:內聯與給定前綴匹配的環境變量。
   *   例如,`"MY_PUBLIC_*"` 將僅包含以 "MY_PUBLIC_" 開頭的環境變量
   */
  env?: "inline" | "disable" | `${string}*`;
  minify?:
    | boolean
    | {
        whitespace?: boolean;
        syntax?: boolean;
        identifiers?: boolean;
      };
  /**
   * 忽略死代碼消除/搖樹優化注釋,如 @__PURE__ 和 package.json
   * "sideEffects" 字段。這應僅用作庫中不正確注釋的臨時解決方案。
   */
  ignoreDCEAnnotations?: boolean;
  /**
   * 即使 minify.whitespace 為 true 也強制發出 @__PURE__ 注釋。
   */
  emitDCEAnnotations?: boolean;

  /**
   * 為輸出生成字節碼。這可以大大提高冷
   * 啟動時間,但會使最終輸出更大並略微增加
   * 內存使用。
   *
   * 字節碼目前僅支持 CommonJS(`format: "cjs"`)。
   *
   * 必須是 `target: "bun"`
   * @default false
   */
  bytecode?: boolean;
  /**
   * 向打包代碼添加橫幅,如 "use client";
   */
  banner?: string;
  /**
   * 向打包代碼添加頁腳,如注釋塊
   *
   * `// made with bun!`
   */
  footer?: string;

  /**
   * 丟棄與屬性訪問匹配的函數調用。
   */
  drop?: string[];

  /**
   * - 當設置為 `true` 時,當構建失敗時,返回的 Promise 以 AggregateError 拒絕。
   * - 當設置為 `false` 時,返回 `{success: false}` 的 {@link BuildOutput}
   *
   * @default true
   */
  throw?: boolean;

  /**
   * 用於路徑解析的自定義 tsconfig.json 文件路徑。
   * 等同於 CLI 中的 `--tsconfig-override`。
   */
  tsconfig?: string;

  outdir?: string;
}

interface BuildOutput {
  outputs: BuildArtifact[];
  success: boolean;
  logs: Array<BuildMessage | ResolveMessage>;
}

interface BuildArtifact extends Blob {
  path: string;
  loader: Loader;
  hash: string | null;
  kind: "entry-point" | "chunk" | "asset" | "sourcemap" | "bytecode";
  sourcemap: BuildArtifact | null;
}

type Loader =
  | "js"
  | "jsx"
  | "ts"
  | "tsx"
  | "css"
  | "json"
  | "jsonc"
  | "toml"
  | "yaml"
  | "text"
  | "file"
  | "napi"
  | "wasm"
  | "html";

interface BuildOutput {
  outputs: BuildArtifact[];
  success: boolean;
  logs: Array<BuildMessage | ResolveMessage>;
}

declare class ResolveMessage {
  readonly name: "ResolveMessage";
  readonly position: Position | null;
  readonly code: string;
  readonly message: string;
  readonly referrer: string;
  readonly specifier: string;
  readonly importKind:
    | "entry_point"
    | "stmt"
    | "require"
    | "import"
    | "dynamic"
    | "require_resolve"
    | "at"
    | "at_conditional"
    | "url"
    | "internal";
  readonly level: "error" | "warning" | "info" | "debug" | "verbose";

  toString(): string;
}

Bun學習網由www.bunjs.com.cn整理維護