Bun 快速的原生打包器可以透過 bun build CLI 命令或 Bun.build() JavaScript API 來使用。
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './build',
});
bun build ./index.tsx --outdir ./build它速度很快。下面的數字代表 esbuild 的 three.js 基準測試 上的效能。

為什麼要打包?
打包器是 JavaScript 生態系統中基礎設施的關鍵組成部分。簡而言之,打包如此重要的原因如下:
- 減少 HTTP 請求。
node_modules中的單個包可能由數百個檔案組成,而大型應用程式可能有數十個此類依賴項。使用單獨的 HTTP 請求載入每個檔案會很快變得不可行,因此打包器用於將我們的應用程式原始碼轉換為數量較少、自包含的“包”,以便一次請求載入。 - 程式碼轉換。 現代應用程式通常使用 TypeScript、JSX 和 CSS Modules 等語言或工具構建,在瀏覽器消費它們之前,所有這些都必須轉換為純 JavaScript 和 CSS。打包器是配置這些轉換的自然場所。
- 框架功能。 框架依賴於打包器外掛和程式碼轉換來實現常見模式,例如檔案系統路由、客戶端-伺服器程式碼共存(例如
getServerSideProps或 Remix loaders)以及伺服器元件。 - 全棧應用程式。 Bun 的打包器可以透過單個命令處理伺服器端和客戶端程式碼,從而實現最佳化的生產構建和單檔案可執行檔案。透過構建時 HTML 匯入,您可以將整個應用程式——前端資源和後端伺服器——打包成一個可部署單元。
讓我們開始使用打包器 API。
請注意,Bun 打包器不旨在替換 tsc 進行型別檢查或生成型別宣告。
基本示例
讓我們構建我們的第一個包。您擁有以下兩個檔案,它們實現了一個簡單的客戶端渲染的 React 應用程式。
import * as ReactDOM from 'react-dom/client';
import {Component} from "./Component"
const root = ReactDOM.createRoot(document.getElementById('root')!);
root.render(<Component message="Sup!" />)
export function Component(props: {message: string}) {
return <p>{props.message}</p>
}
在這裡,index.tsx 是我們應用程式的“入口點”。通常,這將是一個執行某些副作用的指令碼,例如啟動伺服器,或者(在這種情況下)初始化 React 根。因為我們使用的是 TypeScript 和 JSX,所以在將程式碼傳送到瀏覽器之前,我們需要對其進行打包。
建立我們的包
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
})
bun build ./index.tsx --outdir ./out對於 entrypoints 中指定的每個檔案,Bun 將生成一個新包。此包將寫入當前工作目錄解析到的 ./out 目錄的磁碟。執行構建後,檔案系統如下所示:
.
├── index.tsx
├── Component.tsx
└── out
└── index.js
out/index.js 的內容將類似如下:
// ...
// ~20k lines of code
// including the contents of `react-dom/client` and all its dependencies
// this is where the $jsxDEV and $createRoot functions are defined
// 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));
教程:在瀏覽器中執行此檔案
Watch 模式
與執行時和測試執行器一樣,打包器原生支援 watch 模式。
bun build ./index.tsx --outdir ./out --watch內容型別
與 Bun 執行時一樣,打包器開箱即用地支援各種檔案型別。下表分解了打包器的標準“載入器”集。有關完整文件,請參閱 Bundler > File types。
| 副檔名 | 詳細資訊 |
|---|---|
.js .jsx, .cjs .mjs .mts .cts .ts .tsx | 使用 Bun 內建的轉譯器解析檔案並將 TypeScript/JSX 語法轉譯為 vanilla JavaScript。打包器執行一組預設轉換,包括死程式碼消除和 tree shaking。目前 Bun 不會嘗試向下轉換語法;如果您使用最近的 ECMAScript 語法,則會在打包的程式碼中反映出來。 |
| JSON 檔案被解析並內聯到包中作為 JavaScript 物件。 |
| TOML 檔案被解析並內聯到包中作為 JavaScript 物件。 |
| 文字檔案的內容被讀取並作為字串內聯到包中。 |
.node .wasm | 這些檔案由 Bun 執行時支援,但在打包期間,它們被視為資源。 |
資源
如果打包器遇到具有未知副檔名的匯入,它會將匯入的檔案視為外部檔案。引用的檔案將按原樣複製到 outdir,並且匯入將解析為指向該檔案的路徑。
// bundle entrypoint
import logo from "./logo.svg";
console.log(logo);
// bundled output
var logo = "./logo-ab237dfe.svg";
console.log(logo);
檔案載入器的確切行為也受到 naming 和 publicPath 的影響。
有關檔案載入器的更完整文件,請參閱 Bundler > Loaders 頁面。
外掛
此表中描述的行為可以透過外掛覆蓋或擴充套件。有關完整文件,請參閱 Bundler > Loaders 頁面。
API
entrypoints
必填。 對應於應用程式入口點的路徑陣列。每個入口點將生成一個包。
const result = await Bun.build({
entrypoints: ["./index.ts"],
});
// => { success: boolean, outputs: BuildArtifact[], logs: BuildMessage[] }
bun build --entrypoints ./index.ts# the bundle will be printed to stdout
# <bundled code>outdir
輸出檔案將寫入的目錄。
const result = await Bun.build({
entrypoints: ['./index.ts'],
outdir: './out'
});
// => { success: boolean, outputs: BuildArtifact[], logs: BuildMessage[] }
bun build --entrypoints ./index.ts --outdir ./out# a summary of bundled files will be printed to stdout如果未將 outdir 傳遞給 JavaScript API,打包後的程式碼將不會寫入磁碟。打包後的檔案將在 BuildArtifact 物件陣列中返回。這些物件是帶有額外屬性的 Blob;有關完整文件,請參閱 Outputs。
const result = await Bun.build({
entrypoints: ["./index.ts"],
});
for (const res of result.outputs) {
// Can be consumed as blobs
await res.text();
// Bun will set Content-Type and Etag headers
new Response(res);
// Can be written manually, but you should use `outdir` in this case.
Bun.write(path.join("out", res.path), res);
}
當設定了 outdir 時,BuildArtifact 上的 path 屬性將是其寫入位置的絕對路徑。
target
包的預期執行環境。
await Bun.build({
entrypoints: ['./index.ts'],
outdir: './out',
target: 'browser', // default
})
bun build --entrypoints ./index.ts --outdir ./out --target browser根據目標,Bun 將應用不同的模組解析規則和最佳化。
模組解析
Bun 支援 NODE_PATH 環境變數以用於額外的模組解析路徑。
NODE_PATH=./src bun build ./entry.js --outdir ./dist
browser | 預設。 用於生成旨在供瀏覽器執行的包。在解析匯入時優先使用 "browser" 匯出條件。匯入任何內建模組(如 node:events 或 node:path)都可以正常工作,但呼叫某些函式(如 fs.readFile)將無法工作。 |
| 用於生成旨在由 Bun 執行時執行的包。在許多情況下,無需打包伺服器端程式碼;您可以直接執行原始碼而無需修改。但是,打包伺服器程式碼可以減少啟動時間並提高執行效能。這是用於構建全棧應用程式(具有構建時 HTML 匯入,其中伺服器端和客戶端程式碼一起打包)的目標。 使用 如果任何入口點包含 Bun shebang( 當同時使用 |
node | 用於生成旨在由 Node.js 執行的包。在解析匯入時優先使用 "node" 匯出條件,並輸出 .mjs。將來,這將自動 polyfill Bun 全域性變數和其他內建的 bun:* 模組,儘管這尚未實現。 |
format
指定在生成的包中使用的模組格式。
Bun 預設為 "esm",併為 "cjs" 和 "iife" 提供實驗性支援。
format: "esm" - ES 模組
這是預設格式,支援 ES 模組語法,包括頂層 await、import.meta 等。
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
format: "esm",
})
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 受到兩者的支援)。
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
format: "cjs",
})
bun build ./index.tsx --outdir ./out --format cjsformat: "iife" - IIFE
TODO:在支援 globalNames 後記錄 IIFE。
jsx
配置 JSX 轉換行為。允許對 JSX 的編譯方式進行細粒度控制。
經典執行時示例(使用 factory 和 fragment)
await Bun.build({
entrypoints: ['./app.tsx'],
outdir: './out',
jsx: {
factory: 'h',
fragment: 'Fragment',
runtime: 'classic',
},
})
# JSX configuration is handled via bunfig.toml or tsconfig.jsonbun build ./app.tsx --outdir ./out自動執行時示例(使用 importSource)
await Bun.build({
entrypoints: ['./app.tsx'],
outdir: './out',
jsx: {
importSource: 'preact',
runtime: 'automatic',
},
})
# JSX configuration is handled via bunfig.toml or tsconfig.jsonbun build ./app.tsx --outdir ./outsplitting
是否啟用程式碼拆分。
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
splitting: false, // default
})
bun build ./index.tsx --outdir ./out --splitting當設定為 true 時,打包器將啟用程式碼拆分。當多個入口點都匯入同一個檔案、模組或一組檔案/模組時,通常將共享程式碼拆分成單獨的包很有用。這個共享包被稱為塊。考慮以下檔案:
import { shared } from './shared.ts';
import { shared } from './shared.ts';
export const shared = 'shared';
要使用程式碼拆分啟用打包 entry-a.ts 和 entry-b.ts:
await Bun.build({
entrypoints: ['./entry-a.ts', './entry-b.ts'],
outdir: './out',
splitting: true,
})
bun build ./entry-a.ts ./entry-b.ts --outdir ./out --splitting執行此構建將產生以下檔案:
.
├── entry-a.tsx
├── entry-b.tsx
├── shared.tsx
└── out
├── entry-a.js
├── entry-b.js
└── chunk-2fce6291bf86559d.js
生成的 chunk-2fce6291bf86559d.js 檔案包含共享程式碼。為避免衝突,檔名預設會自動包含一個內容雜湊。這可以使用 naming 進行自定義。
plugins
要用於打包的外掛列表。
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
plugins: [/* ... */],
})
n/a
Bun 為 Bun 的執行時和打包器實現了通用的外掛系統。有關完整文件,請參閱 外掛文件。
env
控制打包過程中環境變數的處理方式。在內部,它使用 define 將環境變數注入到包中,但更容易指定要注入的環境變數。
env: "inline"
透過將 process.env.FOO 引用轉換為包含實際環境變數值的字串字面量,將環境變數注入到打包的輸出中。
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
env: "inline",
})
FOO=bar BAZ=123 bun build ./index.tsx --outdir ./out --env inline對於以下輸入
console.log(process.env.FOO);
console.log(process.env.BAZ);
生成的包將包含以下程式碼
console.log("bar");
console.log("123");
env: "PUBLIC_*" (字首)
內聯與給定字首(* 字元之前的部分)匹配的環境變數,將 process.env.FOO 替換為實際的環境變數值。這對於選擇性地內聯環境變數(例如用於面向公眾的 URL 或客戶端令牌)非常有用,而無需擔心將私有憑據注入到輸出包中。
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
// Inline all env vars that start with "ACME_PUBLIC_"
env: "ACME_PUBLIC_*",
})
FOO=bar BAZ=123 ACME_PUBLIC_URL=https://acme.com bun build ./index.tsx --outdir ./out --env 'ACME_PUBLIC_*'例如,給定以下環境變數
FOO=bar BAZ=123 ACME_PUBLIC_URL=https://acme.com和原始碼
console.log(process.env.FOO);
console.log(process.env.ACME_PUBLIC_URL);
console.log(process.env.BAZ);
生成的包將包含以下程式碼
console.log(process.env.FOO);
console.log("https://acme.com");
console.log(process.env.BAZ);
env: "disable"
完全停用環境變數注入。
例如,給定以下環境變數
FOO=bar BAZ=123 ACME_PUBLIC_URL=https://acme.com和原始碼
console.log(process.env.FOO);
console.log(process.env.ACME_PUBLIC_URL);
console.log(process.env.BAZ);
生成的包將包含以下程式碼
console.log(process.env.FOO);
console.log(process.env.BAZ);
sourcemap
指定要生成的 sourcemap 型別。
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
sourcemap: 'linked', // default 'none'
})
bun build ./index.tsx --outdir ./out --sourcemap=linked"none" | 預設。 不生成 sourcemap。 |
| 使用 |
"external" | 在每個 *.js 包旁邊建立一個單獨的 *.js.map 檔案,而不插入 //# sourceMappingURL 註釋。 |
生成的包包含一個 debug id,可用於將包與其對應的 sourcemap 關聯起來。此 debugId 作為註釋新增到檔案底部。
// <generated bundle code>
//# debugId=<DEBUG ID>
"inline"生成 sourcemap 並將其作為 base64 負載附加到生成的包的末尾。
// <bundled code here> //# sourceMappingURL=data:application/json;base64,<encoded sourcemap here>關聯的
*.js.mapsourcemap 將是一個 JSON 檔案,其中包含一個等效的debugId屬性。
minify
是否啟用程式碼壓縮。預設為 false。
當目標為 bun 時,識別符號將預設進行壓縮。
當啟用 minify.syntax 時,未使用的函式和類表示式名稱將被移除,除非將 minify.keepNames 設定為 true 或使用了 --keep-names 標誌。
啟用所有程式碼壓縮選項
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
minify: true, // default false
})
bun build ./index.tsx --outdir ./out --minify逐個啟用某些程式碼壓縮選項
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
minify: {
whitespace: true,
identifiers: true,
syntax: true,
keepNames: false, // default
},
})
bun build ./index.tsx --outdir ./out --minify-whitespace --minify-identifiers --minify-syntax
# To preserve function and class names during minification:bun build ./index.tsx --outdir ./out --minify --keep-namesexternal
將被視為外部的匯入路徑列表。預設為 []。
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
external: ["lodash", "react"], // default: []
})
bun build ./index.tsx --outdir ./out --external lodash --external react外部匯入是指不會包含在最終包中的匯入。相反,import 語句將保持原樣,在執行時解析。
例如,考慮以下入口檔案
import _ from "lodash";
import {z} from "zod";
const value = z.string().parse("Hello world!")
console.log(_.upperCase(value));
通常,打包 index.tsx 會生成一個包含 "zod" 包全部原始碼的包。如果相反,我們希望保留 import 語句原樣,可以將其標記為外部
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
external: ['zod'],
})
bun build ./index.tsx --outdir ./out --external zod生成的包將大致如下所示
import {z} from "zod";
// ...
// the contents of the "lodash" package
// including the `_.upperCase` function
var value = z.string().parse("Hello world!")
console.log(_.upperCase(value));
要將所有匯入標記為外部,請使用萬用字元 *
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
external: ['*'],
})
bun build ./index.tsx --outdir ./out --external '*'packages
控制是否將包依賴項包含在包中。可能的值:bundle (預設)、external。Bun 將任何路徑不以 .、.. 或 / 開頭的匯入視為包。
await Bun.build({
entrypoints: ['./index.ts'],
packages: 'external',
})
bun build ./index.ts --packages externalnaming
自定義生成的檔名。預設為 ./[dir]/[name].[ext]。
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
naming: "[dir]/[name].[ext]", // default
})
bun build ./index.tsx --outdir ./out --entry-naming [dir]/[name].[ext]預設情況下,生成的包的名稱基於關聯的入口點名稱。
.
├── index.tsx
└── out
└── index.js
使用多個入口點時,生成的檔案的層次結構將反映入口點的目錄結構。
.
├── index.tsx
└── nested
└── index.tsx
└── out
├── index.js
└── nested
└── index.js
可以使用 naming 欄位自定義生成檔案的名稱和位置。此欄位接受一個模板字串,用於為所有對應於入口點的包生成檔名,其中以下令牌將被替換為其相應的值
[name]- 入口點檔案的名稱,不包含副檔名。[ext]- 生成包的副檔名。[hash]- 包內容的雜湊值。[dir]- 從專案根目錄到原始檔父目錄的相對路徑。
例如
| 令牌 | [name] | [ext] | [hash] | [dir] |
|---|---|---|---|---|
./index.tsx | index | js | a1b2c3d4 | "" (空字串) |
./nested/entry.ts | entry | js | c3d4e5f6 | "nested" |
我們可以組合這些令牌來建立一個模板字串。例如,要在生成的包名稱中包含雜湊值
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
naming: 'files/[dir]/[name]-[hash].[ext]',
})
bun build ./index.tsx --outdir ./out --entry-naming [name]-[hash].[ext]此構建將導致以下檔案結構
.
├── index.tsx
└── out
└── files
└── index-a1b2c3d4.js
當為 naming 欄位提供了 string 時,它僅用於對應於入口點的包。塊和複製資源的名稱不受影響。使用 JavaScript API,可以為每種生成的檔案型別指定單獨的模板字串。
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
naming: {
// default values
entry: '[dir]/[name].[ext]',
chunk: '[name]-[hash].[ext]',
asset: '[name]-[hash].[ext]',
},
})
bun build ./index.tsx --outdir ./out --entry-naming "[dir]/[name].[ext]" --chunk-naming "[name]-[hash].[ext]" --asset-naming "[name]-[hash].[ext]"root
專案的根目錄。
await Bun.build({
entrypoints: ['./pages/a.tsx', './pages/b.tsx'],
outdir: './out',
root: '.',
})
n/a
如果未指定,則將其計算為所有入口點檔案的第一個共同祖先。考慮以下檔案結構
.
└── pages
└── index.tsx
└── settings.tsx
我們可以打包 pages 目錄中的兩個入口點
await Bun.build({
entrypoints: ['./pages/index.tsx', './pages/settings.tsx'],
outdir: './out',
})
bun build ./pages/index.tsx ./pages/settings.tsx --outdir ./out這將導致如下檔案結構
.
└── pages
└── index.tsx
└── settings.tsx
└── out
└── index.js
└── settings.js
由於 pages 目錄是入口點檔案的第一個共同祖先,因此它被視為專案根目錄。這意味著生成的包位於 out 目錄的頂層;沒有 out/pages 目錄。
可以透過指定 root 選項來覆蓋此行為
await Bun.build({
entrypoints: ['./pages/index.tsx', './pages/settings.tsx'],
outdir: './out',
root: '.',
})
bun build ./pages/index.tsx ./pages/settings.tsx --outdir ./out --root .透過將 . 指定為 root,生成的檔案結構將如下所示
.
└── pages
└── index.tsx
└── settings.tsx
└── out
└── pages
└── index.js
└── settings.js
publicPath
新增到打包程式碼中任何匯入路徑的字首。
在許多情況下,生成的包將不包含 import 語句。畢竟,打包的目標是將所有程式碼合併到一個檔案中。但是,在一些情況下,生成的包將包含 import 語句。
- 資源匯入 — 匯入未識別的檔案型別(如
*.svg)時,打包器會退回到fileloader,它將檔案按原樣複製到outdir。匯入將被轉換為變數 - 外部模組 — 檔案和模組可以被標記為
external,在這種情況下,它們不會被包含在包中。相反,import語句將保留在最終的包中。 - 程式碼拆分。啟用
splitting時,打包器可能會生成獨立的“塊”檔案,這些檔案代表多個入口點之間共享的程式碼。
在任何這些情況下,最終的包可能包含指向其他檔案的路徑。預設情況下,這些匯入是相對的。以下是一個簡單的資源匯入示例
import logo from './logo.svg';
console.log(logo);
// logo.svg is copied into <outdir>
// and hash is added to the filename to prevent collisions
var logo = './logo-a7305bdef.svg';
console.log(logo);
設定 publicPath 將在所有檔案路徑前加上指定的值。
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
publicPath: 'https://cdn.example.com/', // default is undefined
})
bun build ./index.tsx --outdir ./out --public-path https://cdn.example.com/輸出檔案現在看起來大致如下。
var logo = './logo-a7305bdef.svg';
var logo = 'https://cdn.example.com/logo-a7305bdef.svg';define
要在構建時替換的全域性識別符號的對映。此物件的鍵是識別符號名稱,值是將被內聯的 JSON 字串。
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
define: {
STRING: JSON.stringify("value"),
"nested.boolean": "true",
},
})
bun build ./index.tsx --outdir ./out --define 'STRING="value"' --define "nested.boolean=true"loader
副檔名到內建載入器名稱的對映。這可以用於快速自定義某些檔案的載入方式。
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
loader: {
".png": "dataurl",
".txt": "file",
},
})
bun build ./index.tsx --outdir ./out --loader .png:dataurl --loader .txt:filebanner
要新增到最終包的橫幅,這可以是指令,例如 React 的 "use client",或者像程式碼許可證這樣的註釋塊。
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
banner: '"use client";'
})
bun build ./index.tsx --outdir ./out --banner "\"use client\";"footer
要新增到最終包的頁尾,這可能是一個註釋塊,用於許可證,或者只是一個有趣的彩蛋。
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
footer: '// built with love in SF'
})
bun build ./index.tsx --outdir ./out --footer="// built with love in SF"drop
從包中移除函式呼叫。例如,--drop=console 將移除所有對 console.log 的呼叫。呼叫引數也將被移除,無論這些引數是否可能產生副作用。移除 debugger 將移除所有 debugger 語句。
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
drop: ["console", "debugger", "anyIdentifier.or.propertyAccess"],
})
bun build ./index.tsx --outdir ./out --drop=console --drop=debugger --drop=anyIdentifier.or.propertyAccessthrow
控制構建失敗時的錯誤處理行為。當設定為 true (預設) 時,返回的 Promise 會以 AggregateError 拒絕。當設定為 false 時,Promise 會以一個 success 為 false 的 BuildOutput 物件解析。
// Default behavior: throws on error
try {
await Bun.build({
entrypoints: ['./index.tsx'],
throw: true, // default
});
} catch (error) {
// Handle AggregateError
console.error("Build failed:", error);
}
// Alternative: handle errors via success property
const result = await Bun.build({
entrypoints: ['./index.tsx'],
throw: false,
});
if (!result.success) {
console.error("Build failed with errors:", result.logs);
}
輸出
Bun.build 函式返回一個 Promise<BuildOutput>,定義為
interface BuildOutput {
outputs: BuildArtifact[];
success: boolean;
logs: Array<object>; // see docs for details
}
interface BuildArtifact extends Blob {
kind: "entry-point" | "chunk" | "asset" | "sourcemap";
path: string;
loader: Loader;
hash: string | null;
sourcemap: BuildArtifact | null;
}
outputs 陣列包含構建生成的所有檔案。每個構件都實現了 Blob 介面。
const build = await Bun.build({
/* */
});
for (const output of build.outputs) {
await output.arrayBuffer(); // => ArrayBuffer
await output.bytes(); // => Uint8Array
await output.text(); // string
}
每個構件還包含以下屬性
kind | 此檔案是哪種型別的構建輸出。構建會生成打包的入口點、程式碼拆分的“塊”、sourcemaps、位元組碼和複製的資源(如影像)。 |
path | 檔案在磁碟上的絕對路徑 |
loader | 用於解釋檔案的載入器。請參閱 Bundler > Loaders 檢視 Bun 如何將副檔名對映到適當的內建載入器。 |
hash | 檔案內容的雜湊值。對於資源始終定義。 |
sourcemap | 與此檔案對應的 sourcemap 檔案(如果已生成)。僅為入口點和塊定義。 |
與 BunFile 類似,BuildArtifact 物件可以直接傳遞到 new Response() 中。
const build = await Bun.build({
/* */
});
const artifact = build.outputs[0];
// Content-Type header is automatically set
return new Response(artifact);
Bun 執行時實現了對 BuildArtifact 物件的特殊漂亮列印,以方便除錯。
// build.ts
const build = await Bun.build({/* */});
const artifact = build.outputs[0];
console.log(artifact);
bun run build.tsBuildArtifact (entry-point) {
path: "./index.js",
loader: "tsx",
kind: "entry-point",
hash: "824a039620219640",
Blob (114 bytes) {
type: "text/javascript;charset=utf-8"
},
sourcemap: null
}Bytecode
bytecode: boolean 選項可用於為任何 JavaScript/TypeScript 入口點生成位元組碼。這可以大大提高大型應用程式的啟動時間。僅支援 "cjs" 格式,僅支援 "target": "bun",並且依賴於匹配的 Bun 版本。這會在每個入口點旁邊新增一個對應的 .jsc 檔案。
await Bun.build({
entrypoints: ["./index.tsx"],
outdir: "./out",
bytecode: true,
})
bun build ./index.tsx --outdir ./out --bytecodeExecutables
Bun 支援將 JavaScript/TypeScript 入口點“編譯”為獨立的應用程式。此應用程式包含 Bun 二進位制檔案的副本。
bun build ./cli.tsx --outfile mycli --compile./mycli有關完整文件,請參閱 Bundler > Executables。
Logs and errors
失敗時,Bun.build 會返回一個帶有 AggregateError 的拒絕 Promise。這可以記錄到控制檯進行漂亮的錯誤列表列印,或者透過 try/catch 塊進行程式設計方式讀取。
try {
const result = await Bun.build({
entrypoints: ["./index.tsx"],
outdir: "./out",
});
} catch (e) {
// TypeScript does not allow annotations on the catch clause
const error = e as AggregateError;
console.error("Build Failed");
// Example: Using the built-in formatter
console.error(error);
// Example: Serializing the failure as a JSON string.
console.error(JSON.stringify(error, null, 2));
}
大多數情況下,不需要顯式的 try/catch,因為 Bun 會整齊地列印未捕獲的異常。只需對 Bun.build 呼叫使用頂層 await 即可。
error.errors 中的每個項都是 BuildMessage 或 ResolveMessage(Error 的子類)的例項,其中包含每個錯誤的詳細資訊。
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 屬性,其中包含打包器的警告和資訊訊息。
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 will pretty print the message object
console.warn(message);
}
}
Reference
interface Bun {
build(options: BuildOptions): Promise<BuildOutput>;
}
interface BuildConfig {
entrypoints: string[]; // list of file path
outdir?: string; // output directory
target?: Target; // default: "browser"
/**
* Output module format. Top-level await is only supported for `"esm"`.
*
* Can be:
* - `"esm"`
* - `"cjs"` (**experimental**)
* - `"iife"` (**experimental**)
*
* @default "esm"
*/
format?: "esm" | "cjs" | "iife";
/**
* JSX configuration object for controlling JSX transform behavior
*/
jsx?: {
factory?: string;
fragment?: string;
importSource?: string;
runtime?: "automatic" | "classic";
};
naming?:
| string
| {
chunk?: string;
entry?: string;
asset?: string;
};
root?: string; // project root
splitting?: boolean; // default true, enable code splitting
plugins?: BunPlugin[];
external?: string[];
packages?: "bundle" | "external";
publicPath?: string;
define?: Record<string, string>;
loader?: { [k in string]: Loader };
sourcemap?: "none" | "linked" | "inline" | "external" | "linked" | boolean; // default: "none", true -> "inline"
/**
* package.json `exports` conditions used when resolving imports
*
* Equivalent to `--conditions` in `bun build` or `bun run`.
*
* https://nodejs.com.tw/api/packages.html#exports
*/
conditions?: Array<string> | string;
/**
* Controls how environment variables are handled during bundling.
*
* Can be one of:
* - `"inline"`: Injects environment variables into the bundled output by converting `process.env.FOO`
* references to string literals containing the actual environment variable values
* - `"disable"`: Disables environment variable injection entirely
* - A string ending in `*`: Inlines environment variables that match the given prefix.
* For example, `"MY_PUBLIC_*"` will only include env vars starting with "MY_PUBLIC_"
*/
env?: "inline" | "disable" | `${string}*`;
minify?:
| boolean
| {
whitespace?: boolean;
syntax?: boolean;
identifiers?: boolean;
keepNames?: boolean;
};
/**
* Ignore dead code elimination/tree-shaking annotations such as @__PURE__ and package.json
* "sideEffects" fields. This should only be used as a temporary workaround for incorrect
* annotations in libraries.
*/
ignoreDCEAnnotations?: boolean;
/**
* Force emitting @__PURE__ annotations even if minify.whitespace is true.
*/
emitDCEAnnotations?: boolean;
/**
* Generate bytecode for the output. This can dramatically improve cold
* start times, but will make the final output larger and slightly increase
* memory usage.
*
* Bytecode is currently only supported for CommonJS (`format: "cjs"`).
*
* Must be `target: "bun"`
* @default false
*/
bytecode?: boolean;
/**
* Add a banner to the bundled code such as "use client";
*/
banner?: string;
/**
* Add a footer to the bundled code such as a comment block like
*
* `// made with bun!`
*/
footer?: string;
/**
* Drop function calls to matching property accesses.
*/
drop?: string[];
/**
* When set to `true`, the returned promise rejects with an AggregateError when a build failure happens.
* When set to `false`, the `success` property of the returned object will be `false` when a build failure happens.
*
* This defaults to `true`.
*/
throw?: boolean;
}
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"
| "json"
| "toml"
| "file"
| "napi"
| "wasm"
| "text";
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;
}