import Build from "/snippets/cli/build.mdx";
Buns schneller nativer Bundler kann über den bun build CLI-Befehl oder die Bun.build() JavaScript-API verwendet werden.
Auf einen Blick
- JS-API:
await Bun.build({ entrypoints, outdir }) - CLI:
bun build <entry> --outdir ./out - Watch:
--watchfür inkrementelle Builds - Targets:
--target browser|bun|node - Formate:
--format esm|cjs|iife(experimentell für cjs/iife)
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './build',
});bun build ./index.tsx --outdir ./buildEs ist schnell. Die untenstehenden Zahlen repräsentieren die Leistung bei esbuilds three.js Benchmark.

Warum bündeln?
Der Bundler ist ein Schlüsselelement der Infrastruktur im JavaScript-Ökosystem. Als kurze Übersicht, warum das Bündeln so wichtig ist:
- Reduzierung von HTTP-Anfragen. Ein einzelnes Paket in
node_moduleskann aus Hunderten von Dateien bestehen, und große Anwendungen können Dutzende solcher Abhängigkeiten haben. Das Laden jeder dieser Dateien mit einer separaten HTTP-Anfrage wird sehr schnell untragbar, daher werden Bundler verwendet, um unseren Anwendungsquellcode in eine kleinere Anzahl von selbstständigen "Bundles" zu konvertieren, die mit einer einzigen Anfrage geladen werden können. - Code-Transformationen. Moderne Apps werden häufig mit Sprachen oder Tools wie TypeScript, JSX und CSS-Modulen erstellt, die alle in einfaches JavaScript und CSS konvertiert werden müssen, bevor sie von einem Browser konsumiert werden können. Der Bundler ist der natürliche Ort, um diese Transformationen zu konfigurieren.
- Framework-Funktionen. Frameworks verlassen sich auf Bundler-Plugins und Code-Transformationen, um gängige Muster wie Dateisystem-Routing, Client-Server-Code-Co-Location (denken Sie an
getServerSidePropsoder Remix Loader) und Server-Komponenten zu implementieren. - Fullstack-Anwendungen. Buns Bundler kann sowohl Server- als auch Client-Code in einem einzigen Befehl verarbeiten und ermöglicht optimierte Produktions-Builds und Einzeldatei-Executables. Mit HTML-Importen zur Build-Zeit können Sie Ihre gesamte Anwendung – Frontend-Assets und Backend-Server – zu einer einzigen bereitstellbaren Einheit bündeln.
Lassen Sie uns in die Bundler-API eintauchen.
NOTE
Der Bun Bundler ist nicht dazu gedacht, `tsc` für die Typprüfung oder das Generieren von Typdeklarationen zu ersetzen.Grundlegendes Beispiel
Lassen Sie uns unser erstes Bundle erstellen. Sie haben die folgenden zwei Dateien, die eine einfache clientseitig gerenderte React-App implementieren.
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 <h1>{props.message}</h1>;
}Hier ist index.tsx der "Einstiegspunkt" unserer Anwendung. Üblicherweise ist dies ein Skript, das einen Seiteneffekt ausführt, wie das Starten eines Servers oder – in diesem Fall – das Initialisieren einer React-Root. Da wir TypeScript & JSX verwenden, müssen wir unseren Code bündeln, bevor er an den Browser gesendet werden kann.
Um unser Bundle zu erstellen:
await Bun.build({
entrypoints: ["./index.tsx"],
outdir: "./out",
});bun build ./index.tsx --outdir ./outFür jede in entrypoints angegebene Datei generiert Bun ein neues Bundle. Dieses Bundle wird im ./out-Verzeichnis (wie vom aktuellen Arbeitsverzeichnis aufgelöst) auf die Festplatte geschrieben. Nach dem Ausführen des Builds sieht das Dateisystem so aus:
.
├── index.tsx
├── Component.tsx
└── out
└── index.jsDer Inhalt von out/index.js sieht ungefähr so aus:
// out/index.js
// ...
// ~20k Codezeilen
// einschließlich des Inhalts von `react-dom/client` und all seiner Abhängigkeiten
// hier werden die $jsxDEV und $createRoot Funktionen definiert
// 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-Modus
Wie die Runtime und der Test-Runner unterstützt der Bundler nativ den Watch-Modus.
bun build ./index.tsx --outdir ./out --watchInhaltstypen
Wie die Bun-Runtime unterstützt der Bundler eine Reihe von Dateitypen ab Werk. Die folgende Tabelle zeigt die Standard-"Loader" des Bundlers. Siehe Bundler > Dateitypen für die vollständige Dokumentation.
| Erweiterungen | Details |
|---|---|
.js .jsx .cjs .mjs .mts .cts .ts .tsx | Verwendet Buns integrierten Transpiler, um die Datei zu parsen und TypeScript/JSX-Syntax in Vanilla-JavaScript zu transpilieren. Der Bundler führt eine Reihe von Standardtransformationen durch, einschließlich Dead-Code-Eliminierung und Tree-Shaking. Derzeit versucht Bun nicht, Syntax abwärts zu konvertieren; wenn Sie neuere ECMAScript-Syntax verwenden, wird dies im gebündelten Code reflektiert. |
.json | JSON-Dateien werden geparst und als JavaScript-Objekt in das Bundle eingefügt.js<br/>import pkg from "./package.json";<br/>pkg.name; // => "my-package"<br/> |
.jsonc | JSON mit Kommentaren. Dateien werden geparst und als JavaScript-Objekt in das Bundle eingefügt.js<br/>import config from "./config.jsonc";<br/>config.name; // => "my-config"<br/> |
.toml | TOML-Dateien werden geparst und als JavaScript-Objekt in das Bundle eingefügt.js<br/>import config from "./bunfig.toml";<br/>config.logLevel; // => "debug"<br/> |
.yaml .yml | YAML-Dateien werden geparst und als JavaScript-Objekt in das Bundle eingefügt.js<br/>import config from "./config.yaml";<br/>config.name; // => "my-app"<br/> |
.txt | Der Inhalt der Textdatei wird gelesen und als String in das Bundle eingefügt.js<br/>import contents from "./file.txt";<br/>console.log(contents); // => "Hello, world!"<br/> |
.html | HTML-Dateien werden verarbeitet und alle referenzierten Assets (Scripts, Stylesheets, Bilder) werden gebündelt. |
.css | CSS-Dateien werden zu einer einzigen .css-Datei im Ausgabeverzeichnis gebündelt. |
.node .wasm | Diese Dateien werden von der Bun-Runtime unterstützt, aber während des Bündelns werden sie als Assets behandelt. |
Assets
Wenn der Bundler auf einen Import mit einer nicht erkannten Erweiterung stößt, behandelt er die importierte Datei als externe Datei. Die referenzierte Datei wird unverändert in outdir kopiert, und der Import wird als Pfad zur Datei aufgelöst.
// Bundle-Einstiegspunkt
import logo from "./logo.svg";
console.log(logo);// gebündelte Ausgabe
var logo = "./logo-a7305bdef.svg";
console.log(logo);Das genaue Verhalten des Datei-Loaders wird auch von naming und publicPath beeinflusst.
Plugins
Das in dieser Tabelle beschriebene Verhalten kann mit Plugins überschrieben oder erweitert werden. Vollständige Dokumentation finden Sie auf der Seite Bundler > Loader.
API
entrypoints
Ein Array von Pfaden, die den Einstiegspunkten unserer Anwendung entsprechen. Für jeden Einstiegspunkt wird ein Bundle generiert.
const result = await Bun.build({
entrypoints: ["./index.ts"]
});bun build ./index.tsoutdir
Das Verzeichnis, in das Ausgabedateien geschrieben werden.
const result = await Bun.build({
entrypoints: ['./index.ts'],
outdir: './out'
});
// => { success: boolean, outputs: `BuildArtifact[]`, logs: `BuildMessage[]` }bun build ./index.ts --outdir ./outWenn outdir nicht an die JavaScript-API übergeben wird, wird der gebündelte Code nicht auf die Festplatte geschrieben. Gebündelte Dateien werden in einem Array von BuildArtifact-Objekten zurückgegeben. Diese Objekte sind Blobs mit zusätzlichen Eigenschaften; siehe Outputs für die vollständige Dokumentation.
const result = await Bun.build({
entrypoints: ["./index.ts"],
});
for (const res of result.outputs) {
// Kann als Blobs konsumiert werden
await res.text();
// Bun setzt Content-Type und Etag-Header
new Response(res);
// Kann manuell geschrieben werden, aber Sie sollten in diesem Fall `outdir` verwenden.
Bun.write(path.join("out", res.path), res);
}Wenn outdir gesetzt ist, ist die path-Eigenschaft eines BuildArtifact der absolute Pfad, an den es geschrieben wurde.
target
Die beabsichtigte Ausführungsumgebung für das Bundle.
await Bun.build({
entrypoints: ['./index.ts'],
outdir: './out',
target: 'browser', // Standard
})bun build ./index.ts --outdir ./out --target browserJe nach Target wendet Bun unterschiedliche Modulauflösungsregeln und Optimierungen an.
Standard. Zum Generieren von Bundles, die für die Ausführung durch einen Browser bestimmt sind. Priorisiert die "browser" Exportbedingung beim Auflösen von Importen. Das Importieren von integrierten Modulen wie node:events oder node:path funktioniert, aber das Aufrufen einiger Funktionen wie fs.readFile funktioniert nicht.
Zum Generieren von Bundles, die von der Bun-Runtime ausgeführt werden sollen. In vielen Fällen ist es nicht notwendig, Server-seitigen Code zu bündeln; Sie können den Quellcode direkt ohne Änderung ausführen. Das Bündeln Ihres Server-Codes kann jedoch die Startzeiten verkürzen und die Laufleistung verbessern. Dies ist das Target, das Sie für die Erstellung von Fullstack-Anwendungen mit HTML-Importen zur Build-Zeit verwenden, bei denen sowohl Server- als auch Client-Code zusammen gebündelt werden.
Alle mit target: "bun" generierten Bundles sind mit einer speziellen // @bun-Pragma markiert, die der Bun-Runtime anzeigt, dass die Datei vor der Ausführung nicht erneut transpiliert werden muss.
Wenn Einstiegspunkte einen Bun-Shebang (#!/usr/bin/env bun) enthalten, verwendet der Bundler standardmäßig target: "bun" anstelle von "browser".
Bei Verwendung von target: "bun" und format: "cjs" zusammen wird die // @bun @bun-cjs-Pragma hinzugefügt und die CommonJS-Wrapper-Funktion ist nicht mit Node.js kompatibel.
Zum Generieren von Bundles, die von Node.js ausgeführt werden sollen. Priorisiert die "node" Exportbedingung beim Auflösen von Importen und gibt .mjs aus. In Zukunft wird dies automatisch das Bun-Global und andere integrierte bun:*-Module polyfillen, obwohl dies noch nicht implementiert ist.
format
Gibt das Modulformat an, das in den generierten Bundles verwendet werden soll.
Bun verwendet standardmäßig "esm" und bietet experimentelle Unterstützung für "cjs" und "iife".
format: "esm" - ES-Modul
Dies ist das Standardformat, das ES-Modul-Syntax einschließlich Top-Level-Await, import.meta und mehr unterstützt.
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
format: "esm",
})bun build ./index.tsx --outdir ./out --format esmUm ES-Modul-Syntax in Browsern zu verwenden, setzen Sie format auf "esm" und stellen Sie sicher, dass Ihr <script type="module">-Tag type="module" gesetzt hat.
format: "cjs" - CommonJS
Um ein CommonJS-Modul zu erstellen, setzen Sie format auf "cjs". Bei Auswahl von "cjs" ändert sich das Standard-Target von "browser" (esm) zu "node" (cjs). CommonJS-Module, die mit format: "cjs", target: "node" transpiliert werden, können sowohl in Bun als auch in Node.js ausgeführt werden (vorausgesetzt, die verwendeten APIs werden von beiden unterstützt).
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
format: "cjs",
})bun build ./index.tsx --outdir ./out --format cjsformat: "iife" - IIFE
TODO: IIFE dokumentieren, sobald wir globalNames unterstützen.
jsx
Konfigurieren Sie das JSX-Transformationsverhalten. Ermöglicht eine feinkörnige Kontrolle darüber, wie JSX kompiliert wird.
Classic Runtime Beispiel (verwendet factory und fragment):
await Bun.build({
entrypoints: ["./app.tsx"],
outdir: "./out",
jsx: {
factory: "h",
fragment: "Fragment",
runtime: "classic",
},
});# JSX-Konfiguration wird über bunfig.toml oder tsconfig.json gehandhabt
bun build ./app.tsx --outdir ./outAutomatic Runtime Beispiel (verwendet importSource):
await Bun.build({
entrypoints: ["./app.tsx"],
outdir: "./out",
jsx: {
importSource: "preact",
runtime: "automatic",
},
});# JSX-Konfiguration wird über bunfig.toml oder tsconfig.json gehandhabt
bun build ./app.tsx --outdir ./outsplitting
Ob Code-Splitting aktiviert werden soll.
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
splitting: false, // Standard
})bun build ./index.tsx --outdir ./out --splittingWenn true, aktiviert der Bundler Code-Splitting. Wenn mehrere Einstiegspunkte dieselbe Datei, dasselbe Modul oder denselben Satz von Dateien/Modulen importieren, ist es oft nützlich, den gemeinsamen Code in ein separates Bundle aufzuteilen. Dieses gemeinsame Bundle wird als Chunk bezeichnet. Betrachten Sie die folgenden Dateien:
import { shared } from "./shared.ts";import { shared } from "./shared.ts";export const shared = "shared";Um entry-a.ts und entry-b.ts mit aktiviertem Code-Splitting zu bündeln:
await Bun.build({
entrypoints: ['./entry-a.ts', './entry-b.ts'],
outdir: './out',
splitting: true,
})bun build ./entry-a.ts ./entry-b.ts --outdir ./out --splittingDie Ausführung dieses Builds ergibt folgende Dateien:
.
├── entry-a.tsx
├── entry-b.tsx
├── shared.tsx
└── out
├── entry-a.js
├── entry-b.js
└── chunk-2fce6291bf86559d.jsDie generierte chunk-2fce6291bf86559d.js-Datei enthält den gemeinsamen Code. Um Kollisionen zu vermeiden, enthält der Dateiname standardmäßig automatisch einen Inhalts-Hash. Dies kann mit naming angepasst werden.
plugins
Eine Liste von Plugins, die während des Bündelns verwendet werden sollen.
await Bun.build({
entrypoints: ["./index.tsx"],
outdir: "./out",
plugins: [
/* ... */
],
});Bun implementiert ein universelles Plugin-System für sowohl Buns Runtime als auch Bundler. Vollständige Dokumentation finden Sie in der Plugin-Dokumentation.
env
Steuert, wie Umgebungsvariablen während des Bündelns gehandhabt werden. Intern verwendet dies define, um Umgebungsvariablen in das Bundle zu injizieren, macht es aber einfacher, die zu injizierenden Umgebungsvariablen anzugeben.
env: "inline"
Injiziert Umgebungsvariablen in die gebündelte Ausgabe, indem process.env.FOO-Referenzen in String-Literale umgewandelt werden, die die tatsächlichen Umgebungsvariablenwerte enthalten.
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
env: "inline",
})bun build ./index.tsx --outdir ./out --env inlineFür die folgende Eingabe:
// input.js
console.log(process.env.FOO);
console.log(process.env.BAZ);Enthält das generierte Bundle den folgenden Code:
// output.js
console.log("bar");
console.log("123");env: "PUBLIC_*" (Präfix)
Fügt Umgebungsvariablen inline ein, die mit dem angegebenen Präfix (der Teil vor dem *-Zeichen) übereinstimmen, und ersetzt process.env.FOO durch den tatsächlichen Umgebungsvariablenwert. Dies ist nützlich, um selektiv Umgebungsvariablen für Dinge wie öffentlich zugängliche URLs oder clientseitige Tokens inline einzufügen, ohne sich Sorgen zu machen, private Anmeldeinformationen in Ausgabe-Bundles zu injizieren.
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
// Alle Umgebungsvariablen inline einfügen, die mit "ACME_PUBLIC_" beginnen
env: "ACME_PUBLIC_*",
})bun build ./index.tsx --outdir ./out --env ACME_PUBLIC_*Zum Beispiel, bei folgenden Umgebungsvariablen:
FOO=bar BAZ=123 ACME_PUBLIC_URL=https://acme.comUnd Quellcode:
console.log(process.env.FOO);
console.log(process.env.ACME_PUBLIC_URL);
console.log(process.env.BAZ);Enthält das generierte Bundle den folgenden Code:
console.log(process.env.FOO);
console.log("https://acme.com");
console.log(process.env.BAZ);env: "disable"
Deaktiviert die Umgebungsvariablen-Injektion vollständig.
sourcemap
Gibt den Typ der zu generierenden Sourcemap an.
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
sourcemap: 'linked', // Standard 'none'
})bun build ./index.tsx --outdir ./out --sourcemap linked| Wert | Beschreibung |
|---|---|
"none" | Standard. Es wird keine Sourcemap generiert. |
"linked" | Eine separate *.js.map-Datei wird neben jedem *.js-Bundle erstellt, wobei ein //# sourceMappingURL-Kommentar die beiden verknüpft. Erfordert, dass --outdir gesetzt ist. Die Basis-URL kann mit --public-path angepasst werden.js<br/>// <gebündelter Code hier><br/><br/>//# sourceMappingURL=bundle.js.map<br/> |
"external" | Eine separate *.js.map-Datei wird neben jedem *.js-Bundle erstellt, ohne einen //# sourceMappingURL-Kommentar einzufügen.Generierte Bundles enthalten eine Debug-ID, die verwendet werden kann, um ein Bundle mit seiner entsprechenden Sourcemap zu verknüpfen. Diese debugId wird als Kommentar am Ende der Datei hinzugefügt.js<br/>// <generierter Bundle-Code><br/><br/>//# debugId=<DEBUG ID><br/> |
"inline" | Eine Sourcemap wird generiert und als Base64-Payload an das Ende des generierten Bundles angehängt.js<br/>// <gebündelter Code hier><br/><br/>//# sourceMappingURL=data:application/json;base64,<kodierte Sourcemap hier><br/> |
Die zugehörige *.js.map-Sourcemap ist eine JSON-Datei, die eine äquivalente debugId-Eigenschaft enthält.
minify
Ob Minifizierung aktiviert werden soll. Standard false.
NOTE
Beim Targeting von `bun` werden Bezeichner standardmäßig minifiziert.Um alle Minifizierungsoptionen zu aktivieren:
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
minify: true, // Standard false
})bun build ./index.tsx --outdir ./out --minifyUm bestimmte Minifizierungen granular zu aktivieren:
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
minify: {
whitespace: true,
identifiers: true,
syntax: true,
},
})bun build ./index.tsx --outdir ./out --minify-whitespace --minify-identifiers --minify-syntaxexternal
Eine Liste von Importpfaden, die als extern betrachtet werden sollen. Standard [].
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
external: ["lodash", "react"], // Standard: []
})bun build ./index.tsx --outdir ./out --external lodash --external reactEin externer Import ist einer, der nicht im endgültigen Bundle enthalten ist. Stattdessen bleibt die Import-Anweisung unverändert, um zur Laufzeit aufgelöst zu werden.
Betrachten Sie zum Beispiel die folgende Einstiegspunkt-Datei:
import _ from "lodash";
import { z } from "zod";
const value = z.string().parse("Hello world!");
console.log(_.upperCase(value));Normalerweise würde das Bündeln von index.tsx ein Bundle generieren, das den gesamten Quellcode des "zod"-Pakets enthält. Wenn wir stattdessen die Import-Anweisung unverändert lassen möchten, können wir sie als extern markieren:
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
external: ['zod'],
})bun build ./index.tsx --outdir ./out --external zodDas generierte Bundle sieht ungefähr so aus:
import { z } from "zod";
// ...
// der Inhalt des "lodash"-Pakets
// einschließlich der `_.upperCase`-Funktion
var value = z.string().parse("Hello world!");
console.log(_.upperCase(value));Um alle Importe als extern zu markieren, verwenden Sie den Platzhalter *:
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
external: ['*'],
})bun build ./index.tsx --outdir ./out --external '*'packages
Steuert, ob Paketabhängigkeiten im Bundle enthalten sind oder nicht. Mögliche Werte: bundle (Standard), external. Bun behandelt jeden Import, dessen Pfad nicht mit ., .. oder / beginnt, als Paket.
await Bun.build({
entrypoints: ['./index.ts'],
packages: 'external',
})bun build ./index.ts --packages externalnaming
Passt die generierten Dateinamen an. Standard ./[dir]/[name].[ext].
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
naming: "[dir]/[name].[ext]", // Standard
})bun build ./index.tsx --outdir ./out --entry-naming "[dir]/[name].[ext]"Standardmäßig basieren die Namen der generierten Bundles auf dem Namen des zugehörigen Einstiegspunkts.
.
├── index.tsx
└── out
└── index.jsBei mehreren Einstiegspunkten spiegelt die generierte Dateihierarchie die Verzeichnisstruktur der Einstiegspunkte wider.
.
├── index.tsx
└── nested
└── index.tsx
└── out
├── index.js
└── nested
└── index.jsDie Namen und Speicherorte der generierten Dateien können mit dem naming-Feld angepasst werden. Dieses Feld akzeptiert eine Template-Zeichenfolge, die verwendet wird, um die Dateinamen für alle Bundles zu generieren, die Einstiegspunkten entsprechen, wobei die folgenden Token durch ihre entsprechenden Werte ersetzt werden:
[name]- Der Name der Einstiegspunktdatei ohne Erweiterung.[ext]- Die Erweiterung des generierten Bundles.[hash]- Ein Hash des Bundle-Inhalts.[dir]- Der relative Pfad vom Projektstamm zum übergeordneten Verzeichnis der Quelldatei.
Zum Beispiel:
| Token | [name] | [ext] | [hash] | [dir] |
|---|---|---|---|---|
./index.tsx | index | js | a1b2c3d4 | "" (leerer String) |
./nested/entry.ts | entry | js | c3d4e5f6 | "nested" |
Wir können diese Token kombinieren, um eine Template-Zeichenfolge zu erstellen. Zum Beispiel, um den Hash in die generierten Bundle-Namen aufzunehmen:
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
naming: 'files/[dir]/[name]-[hash].[ext]',
})bun build ./index.tsx --outdir ./out --entry-naming 'files/[dir]/[name]-[hash].[ext]'Dieser Build würde folgende Dateistruktur ergeben:
.
├── index.tsx
└── out
└── files
└── index-a1b2c3d4.jsWenn eine Zeichenfolge für das naming-Feld bereitgestellt wird, wird sie nur für Bundles verwendet, die Einstiegspunkten entsprechen. Die Namen von Chunks und kopierten Assets werden nicht beeinflusst. Mit der JavaScript-API können separate Template-Zeichenfolgen für jeden Typ von generierter Datei angegeben werden.
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
naming: {
// Standardwerte
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
Das Stammverzeichnis des Projekts.
await Bun.build({
entrypoints: ['./pages/a.tsx', './pages/b.tsx'],
outdir: './out',
root: '.',
})bun build ./pages/a.tsx ./pages/b.tsx --outdir ./out --root .Wenn nicht angegeben, wird es als erster gemeinsamer Vorfahre aller Einstiegspunktdateien berechnet. Betrachten Sie die folgende Dateistruktur:
.
└── pages
└── index.tsx
└── settings.tsxWir können beide Einstiegspunkte im pages-Verzeichnis erstellen:
await Bun.build({
entrypoints: ['./pages/index.tsx', './pages/settings.tsx'],
outdir: './out',
})bun build ./pages/index.tsx ./pages/settings.tsx --outdir ./outDies würde eine Dateistruktur wie diese ergeben:
.
└── pages
└── index.tsx
└── settings.tsx
└── out
└── index.js
└── settings.jsDa das pages-Verzeichnis der erste gemeinsame Vorfahre der Einstiegspunktdateien ist, wird es als Projektstamm betrachtet. Dies bedeutet, dass die generierten Bundles auf der obersten Ebene des out-Verzeichnisses leben; es gibt kein out/pages-Verzeichnis.
Dieses Verhalten kann durch Angeben der root-Option überschrieben werden:
await Bun.build({
entrypoints: ['./pages/index.tsx', './pages/settings.tsx'],
outdir: './out',
root: '.',
})bun build ./pages/index.tsx ./pages/settings.tsx --outdir ./out --root .Durch Angeben von . als root sieht die generierte Dateistruktur so aus:
.
└── pages
└── index.tsx
└── settings.tsx
└── out
└── pages
└── index.js
└── settings.jspublicPath
Ein Präfix, das an alle Importpfade im gebündelten Code angehängt wird.
In vielen Fällen enthalten generierte Bundles keine Import-Anweisungen. Schließlich ist das Ziel des Bündelns, den gesamten Code in einer einzigen Datei zu kombinieren. Es gibt jedoch eine Reihe von Fällen, in denen die generierten Bundles Import-Anweisungen enthalten.
- Asset-Importe — Beim Importieren eines nicht erkannten Dateityps wie
*.svgverweist der Bundler an den Datei-Loader, der die Datei unverändert inoutdirkopiert. Der Import wird in eine Variable konvertiert - Externe Module — Dateien und Module können als extern markiert werden, in welchem Fall sie nicht im Bundle enthalten sind. Stattdessen bleibt die Import-Anweisung im endgültigen Bundle.
- Chunking. Wenn
splittingaktiviert ist, kann der Bundler separate "Chunk"-Dateien generieren, die Code darstellen, der zwischen mehreren Einstiegspunkten geteilt wird.
In jedem dieser Fälle können die endgültigen Bundles Pfade zu anderen Dateien enthalten. Standardmäßig sind diese Importe relativ. Hier ist ein Beispiel für einen einfachen Asset-Import:
import logo from "./logo.svg";
console.log(logo);var logo = "./logo-a7305bdef.svg";
console.log(logo);Das Setzen von publicPath stellt allen Dateipfaden den angegebenen Wert voran.
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
publicPath: 'https://cdn.example.com/', // Standard ist undefined
})bun build ./index.tsx --outdir ./out --public-path 'https://cdn.example.com/'Die Ausgabedatei würde jetzt ungefähr so aussehen:
var logo = "https://cdn.example.com/logo-a7305bdef.svg";define
Eine Zuordnung von globalen Bezeichnern, die zur Build-Zeit ersetzt werden sollen. Schlüssel dieses Objekts sind Bezeichnernamen, und Werte sind JSON-Strings, die inline eingefügt werden.
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=trueloader
Eine Zuordnung von Dateierweiterungen zu integrierten Loader-Namen. Dies kann verwendet werden, um schnell anzupassen, wie bestimmte Dateien geladen werden.
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
Ein Banner, das dem endgültigen Bundle hinzugefügt wird, dies kann eine Direktive wie use client für React oder ein Kommentarblock wie eine Lizenz für den Code sein.
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
banner: 'use client;'
})bun build ./index.tsx --outdir ./out --banner 'use client";'footer
Ein Footer, der dem endgültigen Bundle hinzugefügt wird, dies kann etwas wie ein Kommentarblock für eine Lizenz oder nur ein lustiges Easter Egg sein.
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
Entfernt Funktionsaufrufe aus einem Bundle. Zum Beispiel entfernt --drop=console alle Aufrufe von console.log. Argumente für Aufrufe werden ebenfalls entfernt, unabhängig davon, ob diese Argumente Seiteneffekte haben können. Das Droppen von debugger entfernt alle debugger-Anweisungen.
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
drop: ["console", "debugger", "anyIdentifier.or.propertyAccess"],
})bun build ./index.tsx --outdir ./out --drop console --drop debuggerOutputs
Die Bun.build-Funktion gibt ein Promise<BuildOutput> zurück, definiert als:
interface BuildOutput {
outputs: BuildArtifact[];
success: boolean;
logs: Array<object>; // siehe docs für Details
}
interface BuildArtifact extends Blob {
kind: "entry-point" | "chunk" | "asset" | "sourcemap";
path: string;
loader: Loader;
hash: string | null;
sourcemap: BuildArtifact | null;
}Das outputs-Array enthält alle Dateien, die vom Build generiert wurden. Jedes Artifact implementiert die Blob-Schnittstelle.
const build = await Bun.build({
/* */
});
for (const output of build.outputs) {
await output.arrayBuffer(); // => ArrayBuffer
await output.bytes(); // => Uint8Array
await output.text(); // string
}Jedes Artifact enthält auch die folgenden Eigenschaften:
| Eigenschaft | Beschreibung |
|---|---|
kind | Welche Art von Build-Ausgabe diese Datei ist. Ein Build generiert gebündelte Einstiegspunkte, Code-Split-"Chunks", Sourcemaps, Bytecode und kopierte Assets (wie Bilder). |
path | Absoluter Pfad zur Datei auf der Festplatte |
loader | Der Loader wurde verwendet, um die Datei zu interpretieren. Siehe Bundler > Loader, um zu sehen, wie Bun Dateierweiterungen dem entsprechenden integrierten Loader zuordnet. |
hash | Der Hash des Datei-Inhalts. Immer für Assets definiert. |
sourcemap | Die Sourcemap-Datei, die zu dieser Datei gehört, falls generiert. Nur für Einstiegspunkte und Chunks definiert. |
Ähnlich wie BunFile können BuildArtifact-Objekte direkt an new Response() übergeben werden.
const build = await Bun.build({
/* */
});
const artifact = build.outputs[0];
// Content-Type-Header wird automatisch gesetzt
return new Response(artifact);Die Bun-Runtime implementiert spezielles Pretty-Printing von BuildArtifact-Objekten, um das Debuggen zu erleichtern.
// build.ts
const build = await Bun.build({
/* */
});
const artifact = build.outputs[0];
console.log(artifact);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
Die bytecode: boolean-Option kann verwendet werden, um Bytecode für JavaScript/TypeScript-Einstiegspunkte zu generieren. Dies kann die Startzeiten für große Anwendungen erheblich verbessern. Wird nur für das "cjs"-Format unterstützt, unterstützt nur "target": "bun" und ist von einer übereinstimmenden Version von Bun abhängig. Dies fügt eine entsprechende .jsc-Datei für jeden Einstiegspunkt hinzu.
await Bun.build({
entrypoints: ["./index.tsx"],
outdir: "./out",
bytecode: true,
})bun build ./index.tsx --outdir ./out --bytecodeExecutables
Bun unterstützt das "Kompilieren" eines JavaScript/TypeScript-Einstiegspunkts in eine eigenständige ausführbare Datei. Diese ausführbare Datei enthält eine Kopie der Bun-Binärdatei.
bun build ./cli.tsx --outfile mycli --compile
./mycliVollständige Dokumentation finden Sie unter Bundler > Executables.
Logs und Fehler
Bei einem Fehler gibt Bun.build ein abgelehntes Promise mit einem AggregateError zurück. Dies kann zur schönen Ausgabe der Fehlerliste an die Console protokolliert oder programmatisch mit einem try/catch-Block gelesen werden.
try {
const result = await Bun.build({
entrypoints: ["./index.tsx"],
outdir: "./out",
});
} catch (e) {
// TypeScript erlaubt keine Annotationen in der catch-Klausel
const error = e as AggregateError;
console.error("Build Failed");
// Beispiel: Verwendung des integrierten Formatters
console.error(error);
// Beispiel: Serialisierung des Fehlers als JSON-String.
console.error(JSON.stringify(error, null, 2));
}Meistens ist ein expliziter try/catch nicht erforderlich, da Bun nicht abgefangene Ausnahmen ordentlich ausgibt. Es reicht, einfach ein Top-Level-Await auf dem Bun.build-Aufruf zu verwenden.
Jedes Element in error.errors ist eine Instanz von BuildMessage oder ResolveMessage (Unterklassen von Error), die detaillierte Informationen für jeden Fehler enthalten.
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;
}Bei erfolgreichem Build enthält das zurückgegebene Objekt eine logs-Eigenschaft, die Bundler-Warnungen und Info-Nachrichten enthält.
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 gibt die Nachricht schön formatiert aus
console.warn(message);
}
}Referenz
interface Bun {
build(options: BuildOptions): Promise<BuildOutput>;
}
interface BuildConfig {
entrypoints: string[]; // Liste der Dateipfade
outdir?: string; // Ausgabeverzeichnis
target?: Target; // Standard: "browser"
/**
* Ausgabe-Modulformat. Top-Level-Await wird nur für `"esm"` unterstützt.
*
* Kann sein:
* - `"esm"`
* - `"cjs"` (**experimentell**)
* - `"iife"` (**experimentell**)
*
* @default "esm"
*/
format?: "esm" | "cjs" | "iife";
/**
* JSX-Konfigurationsobjekt zur Steuerung des JSX-Transformationsverhaltens
*/
jsx?: {
runtime?: "automatic" | "classic";
importSource?: string;
factory?: string;
fragment?: string;
sideEffects?: boolean;
development?: boolean;
};
naming?:
| string
| {
chunk?: string;
entry?: string;
asset?: string;
};
root?: string; // Projektstamm
splitting?: boolean; // Standard true, Code-Splitting aktivieren
plugins?: BunPlugin[];
external?: string[];
packages?: "bundle" | "external";
publicPath?: string;
define?: Record<string, string>;
loader?: { [k in string]: Loader };
sourcemap?: "none" | "linked" | "inline" | "external" | boolean; // Standard: "none", true -> "inline"
/**
* package.json `exports`-Bedingungen, die beim Auflösen von Importen verwendet werden
*
* Entspricht `--conditions` in `bun build` oder `bun run`.
*
* https://nodejs.org/api/packages.html#exports
*/
conditions?: Array<string> | string;
/**
* Steuert, wie Umgebungsvariablen während des Bündelns gehandhabt werden.
*
* Kann einer der folgenden Werte sein:
* - `"inline"`: Injiziert Umgebungsvariablen in die gebündelte Ausgabe, indem `process.env.FOO`-
* Referenzen in String-Literale umgewandelt werden, die die tatsächlichen Umgebungsvariablenwerte enthalten
* - `"disable"`: Deaktiviert die Umgebungsvariablen-Injektion vollständig
* - Ein String, der mit `*` endet: Fügt Umgebungsvariablen inline ein, die mit dem angegebenen Präfix übereinstimmen.
* Zum Beispiel werden bei `"MY_PUBLIC_*"` nur Umgebungsvariablen eingefügt, die mit "MY_PUBLIC_" beginnen
*/
env?: "inline" | "disable" | `${string}*`;
minify?:
| boolean
| {
whitespace?: boolean;
syntax?: boolean;
identifiers?: boolean;
};
/**
* Ignoriere Dead-Code-Eliminierung/Tree-Shaking-Annotationen wie @__PURE__ und package.json
* "sideEffects"-Felder. Dies sollte nur als vorübergehende Lösung für falsche
* Annotationen in Bibliotheken verwendet werden.
*/
ignoreDCEAnnotations?: boolean;
/**
* @__PURE__-Annotationen auch dann ausgeben, wenn minify.whitespace true ist.
*/
emitDCEAnnotations?: boolean;
/**
* Bytecode für die Ausgabe generieren. Dies kann die Kaltstartzeiten erheblich verbessern,
* macht aber die endgültige Ausgabe größer und erhöht leicht den Speicherverbrauch.
*
* Bytecode wird derzeit nur für CommonJS unterstützt (`format: "cjs"`).
*
* Muss `target: "bun"` sein
* @default false
*/
bytecode?: boolean;
/**
* Ein Banner zum gebündelten Code hinzufügen, wie "use client";
*/
banner?: string;
/**
* Ein Footer zum gebündelten Code hinzufügen, wie einen Kommentarblock
*
* `// made with bun!`
*/
footer?: string;
/**
* Funktionsaufrufe für übereinstimmende Eigenschaftszugriffe entfernen.
*/
drop?: string[];
/**
* - Wenn auf `true` gesetzt, lehnt das zurückgegebene Promise bei einem Build-Fehler mit einem AggregateError ab.
* - Wenn auf `false` gesetzt, gibt es ein {@link BuildOutput} mit `{success: false}` zurück
*
* @default true
*/
throw?: boolean;
/**
* Benutzerdefinierter tsconfig.json-Dateipfad zur Verwendung für die Pfadauflösung.
* Entspricht `--tsconfig-override` in der CLI.
*/
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;
}