Skip to content

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: --watch für inkrementelle Builds
  • Targets: --target browser|bun|node
  • Formate: --format esm|cjs|iife (experimentell für cjs/iife)
ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './build',
});
bash
bun build ./index.tsx --outdir ./build

Es 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_modules kann 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 getServerSideProps oder 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.

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>;
}

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:

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

Fü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:

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

Der Inhalt von out/index.js sieht ungefähr so aus:

out/index.js
js
// 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.

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

Inhaltstypen

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.

ErweiterungenDetails
.js .jsx .cjs .mjs .mts .cts .ts .tsxVerwendet 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.
.jsonJSON-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/>
.jsoncJSON 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/>
.tomlTOML-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 .ymlYAML-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/>
.txtDer 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/>
.htmlHTML-Dateien werden verarbeitet und alle referenzierten Assets (Scripts, Stylesheets, Bilder) werden gebündelt.
.cssCSS-Dateien werden zu einer einzigen .css-Datei im Ausgabeverzeichnis gebündelt.
.node .wasmDiese 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.

ts
// Bundle-Einstiegspunkt
import logo from "./logo.svg";
console.log(logo);
ts
// 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.

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

outdir

Das Verzeichnis, in das Ausgabedateien geschrieben werden.

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

Wenn 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.

ts
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.

ts
await Bun.build({
  entrypoints: ['./index.ts'],
  outdir: './out',
  target: 'browser', // Standard
})
bash
bun build ./index.ts --outdir ./out --target browser

Je 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.

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

Um 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).

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

format: "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):

ts
await Bun.build({
  entrypoints: ["./app.tsx"],
  outdir: "./out",
  jsx: {
    factory: "h",
    fragment: "Fragment",
    runtime: "classic",
  },
});
bash
# JSX-Konfiguration wird über bunfig.toml oder tsconfig.json gehandhabt
bun build ./app.tsx --outdir ./out

Automatic Runtime Beispiel (verwendet importSource):

ts
await Bun.build({
  entrypoints: ["./app.tsx"],
  outdir: "./out",
  jsx: {
    importSource: "preact",
    runtime: "automatic",
  },
});
bash
# JSX-Konfiguration wird über bunfig.toml oder tsconfig.json gehandhabt
bun build ./app.tsx --outdir ./out

splitting

Ob Code-Splitting aktiviert werden soll.

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  splitting: false, // Standard
})
bash
bun build ./index.tsx --outdir ./out --splitting

Wenn 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:

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

Um entry-a.ts und entry-b.ts mit aktiviertem Code-Splitting zu bündeln:

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

Die Ausführung dieses Builds ergibt folgende Dateien:

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

Die 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.

ts
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.

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

Für die folgende Eingabe:

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

Enthält das generierte Bundle den folgenden Code:

output.js
js
// 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.

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  
  // Alle Umgebungsvariablen inline einfügen, die mit "ACME_PUBLIC_" beginnen
  env: "ACME_PUBLIC_*",
})
bash
bun build ./index.tsx --outdir ./out --env ACME_PUBLIC_*

Zum Beispiel, bei folgenden Umgebungsvariablen:

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

Und Quellcode:

tsx
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:

output.js
js
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.

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  sourcemap: 'linked', // Standard 'none'
})
bash
bun build ./index.tsx --outdir ./out --sourcemap linked
WertBeschreibung
"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:

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  minify: true, // Standard false
})
bash
bun build ./index.tsx --outdir ./out --minify

Um bestimmte Minifizierungen granular zu aktivieren:

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

external

Eine Liste von Importpfaden, die als extern betrachtet werden sollen. Standard [].

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

Ein 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:

tsx
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:

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

Das generierte Bundle sieht ungefähr so aus:

out/index.js
js
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 *:

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  external: ['*'],
})
bash
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.

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

naming

Passt die generierten Dateinamen an. Standard ./[dir]/[name].[ext].

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  naming: "[dir]/[name].[ext]", // Standard
})
bash
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.

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

Bei mehreren Einstiegspunkten spiegelt die generierte Dateihierarchie die Verzeichnisstruktur der Einstiegspunkte wider.

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

Die 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.tsxindexjsa1b2c3d4"" (leerer String)
./nested/entry.tsentryjsc3d4e5f6"nested"

Wir können diese Token kombinieren, um eine Template-Zeichenfolge zu erstellen. Zum Beispiel, um den Hash in die generierten Bundle-Namen aufzunehmen:

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

Dieser Build würde folgende Dateistruktur ergeben:

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

Wenn 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.

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  naming: {
    // Standardwerte
    entry: '[dir]/[name].[ext]',
    chunk: '[name]-[hash].[ext]',
    asset: '[name]-[hash].[ext]',
  },
})
bash
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.

ts
await Bun.build({
  entrypoints: ['./pages/a.tsx', './pages/b.tsx'],
  outdir: './out',
  root: '.',
})
bash
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:

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

Wir können beide Einstiegspunkte im pages-Verzeichnis erstellen:

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

Dies würde eine Dateistruktur wie diese ergeben:

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

Da 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:

js
await Bun.build({
  entrypoints: ['./pages/index.tsx', './pages/settings.tsx'],
  outdir: './out',
  root: '.',
})
bash
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.js

publicPath

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 *.svg verweist der Bundler an den Datei-Loader, der die Datei unverändert in outdir kopiert. 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 splitting aktiviert 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:

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

Das Setzen von publicPath stellt allen Dateipfaden den angegebenen Wert voran.

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  publicPath: 'https://cdn.example.com/', // Standard ist undefined
})
bash
bun build ./index.tsx --outdir ./out --public-path 'https://cdn.example.com/'

Die Ausgabedatei würde jetzt ungefähr so aussehen:

out/index.js
js
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.

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

loader

Eine Zuordnung von Dateierweiterungen zu integrierten Loader-Namen. Dies kann verwendet werden, um schnell anzupassen, wie bestimmte Dateien geladen werden.

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

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.

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

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.

ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './out',
  footer: '// built with love in SF'
})
bash
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.

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

Outputs

Die Bun.build-Funktion gibt ein Promise<BuildOutput> zurück, definiert als:

ts
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.

ts
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:

EigenschaftBeschreibung
kindWelche Art von Build-Ausgabe diese Datei ist. Ein Build generiert gebündelte Einstiegspunkte, Code-Split-"Chunks", Sourcemaps, Bytecode und kopierte Assets (wie Bilder).
pathAbsoluter Pfad zur Datei auf der Festplatte
loaderDer Loader wurde verwendet, um die Datei zu interpretieren. Siehe Bundler > Loader, um zu sehen, wie Bun Dateierweiterungen dem entsprechenden integrierten Loader zuordnet.
hashDer Hash des Datei-Inhalts. Immer für Assets definiert.
sourcemapDie 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.

ts
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.

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

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.

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

Executables

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.

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

Vollstä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.

ts
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.

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;
}

Bei erfolgreichem Build enthält das zurückgegebene Objekt eine logs-Eigenschaft, die Bundler-Warnungen und Info-Nachrichten enthält.

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 gibt die Nachricht schön formatiert aus
    console.warn(message);
  }
}

Referenz

ts
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;
}

Bun von www.bunjs.com.cn bearbeitet