Skip to content

Buns Bundler implementiert eine --compile-Flagge zum Generieren einer eigenständigen Binärdatei aus einer TypeScript- oder JavaScript-Datei.

bash
bun build ./cli.ts --compile --outfile mycli
ts
console.log("Hallo Welt!");

Dies bündelt cli.ts in eine ausführbare Datei, die direkt ausgeführt werden kann:

bash
./mycli
txt
Hallo Welt!

Alle importierten Dateien und Pakete werden zusammen mit einer Kopie der Bun-Laufzeit in die ausführbare Datei gebündelt. Alle integrierten Bun- und Node.js-APIs werden unterstützt.


Cross-Compile für andere Plattformen

Die --target-Flagge ermöglicht es Ihnen, Ihre eigenständige ausführbare Datei für ein anderes Betriebssystem, eine andere Architektur oder eine andere Bun-Version als den Computer zu kompilieren, auf dem Sie bun build ausführen.

So erstellen Sie eine Build für Linux x64 (die meisten Server):

bash
bun build --compile --target=bun-linux-x64 ./index.ts --outfile myapp

# Um CPUs von vor 2013 zu unterstützen, verwenden Sie die Baseline-Version (nehalem)
bun build --compile --target=bun-linux-x64-baseline ./index.ts --outfile myapp

# Um explizit nur CPUs von 2013 und später zu unterstützen, verwenden Sie die moderne Version (haswell)
# modern ist schneller, aber baseline ist kompatibler.
bun build --compile --target=bun-linux-x64-modern ./index.ts --outfile myapp

So erstellen Sie eine Build für Linux ARM64 (z.B. Graviton oder Raspberry Pi):

bash
# Hinweis: Die Standardarchitektur ist x64, wenn keine Architektur angegeben wird.
bun build --compile --target=bun-linux-arm64 ./index.ts --outfile myapp

So erstellen Sie eine Build für Windows x64:

bash
bun build --compile --target=bun-windows-x64 ./path/to/my/app.ts --outfile myapp

# Um CPUs von vor 2013 zu unterstützen, verwenden Sie die Baseline-Version (nehalem)
bun build --compile --target=bun-windows-x64-baseline ./path/to/my/app.ts --outfile myapp

# Um explizit nur CPUs von 2013 und später zu unterstützen, verwenden Sie die moderne Version (haswell)
bun build --compile --target=bun-windows-x64-modern ./path/to/my/app.ts --outfile myapp

# Hinweis: Wenn keine .exe-Erweiterung angegeben wird, fügt Bun sie automatisch für Windows-Executables hinzu

So erstellen Sie eine Build für macOS arm64:

bash
bun build --compile --target=bun-darwin-arm64 ./path/to/my/app.ts --outfile myapp

So erstellen Sie eine Build für macOS x64:

bash
bun build --compile --target=bun-darwin-x64 ./path/to/my/app.ts --outfile myapp

Unterstützte Ziele

Die Reihenfolge der --target-Flagge spielt keine Rolle, solange sie durch ein - getrennt sind.

--targetBetriebssystemArchitekturModernBaselineLibc
bun-linux-x64Linuxx64glibc
bun-linux-arm64Linuxarm64N/Aglibc
bun-windows-x64Windowsx64-
bun-windows-arm64Windowsarm64-
bun-darwin-x64macOSx64-
bun-darwin-arm64macOSarm64N/A-
bun-linux-x64-muslLinuxx64musl
bun-linux-arm64-muslLinuxarm64N/Amusl

Build-Zeit-Konstanten

Verwenden Sie die --define-Flagge, um Build-Zeit-Konstanten in Ihre ausführbare Datei zu injizieren, wie Versionsnummern, Build-Zeitstempel oder Konfigurationswerte:

bash
bun build --compile --define BUILD_VERSION='"1.2.3"' --define BUILD_TIME='"2024-01-15T10:30:00Z"' src/cli.ts --outfile mycli

Diese Konstanten werden zur Build-Zeit direkt in Ihre kompilierte Binärdatei eingebettet, was keine Laufzeit-Overhead bietet und Optimierungen zur Eliminierung toten Codes ermöglicht.

NOTE

Für umfassende Beispiele und fortgeschrittene Muster siehe den [Leitfaden zu Build-Zeit-Konstanten](/guides/runtime/build-time-constants).

Bereitstellung in der Produktion

Kompilierte ausführbare Dateien reduzieren die Speichernutzung und verbessern die Startzeit von Bun.

Normalerweise liest und transpiliert Bun JavaScript- und TypeScript-Dateien bei import und require. Dies ist Teil dessen, was so viel von Bun "einfach funktionieren" lässt, aber es ist nicht kostenlos. Es kostet Zeit und Speicher, Dateien von der Festplatte zu lesen, Dateipfade aufzulösen, Quellcode zu parsen, zu transpilieren und zu drucken.

Mit kompilierten ausführbaren Dateien können Sie diese Kosten von der Laufzeit zur Build-Zeit verschieben.

Bei der Bereitstellung in der Produktion empfehlen wir Folgendes:

bash
bun build --compile --minify --sourcemap ./path/to/my/app.ts --outfile myapp

Bytecode-Kompilierung

Um die Startzeit zu verbessern, aktivieren Sie die Bytecode-Kompilierung:

bash
bun build --compile --minify --sourcemap --bytecode ./path/to/my/app.ts --outfile myapp

Mit Bytecode-Kompilierung startet tsc 2x schneller:

Die Bytecode-Kompilierung verschiebt den Parsing-Overhead für große Eingabedateien von der Laufzeit zur Bündelungszeit. Ihre App startet schneller, im Gegenzug wird der bun build-Befehl etwas langsamer. Es verschleiert den Quellcode nicht.

Was machen diese Flags?

Das --minify-Argument optimiert die Größe des transpilierten Ausgabe-Codes. Wenn Sie eine große Anwendung haben, kann dies Megabytes an Speicherplatz sparen. Bei kleineren Anwendungen kann es dennoch die Startzeit etwas verbessern.

Das --sourcemap-Argument bettet eine mit zstd komprimierte Sourcemap ein, sodass Fehler und Stacktraces auf ihre ursprünglichen Speicherorte statt auf die transpilierte Position verweisen. Bun dekomprimiert und löst die Sourcemap automatisch auf, wenn ein Fehler auftritt.

Das --bytecode-Argument aktiviert die Bytecode-Kompilierung. Jedes Mal, wenn Sie JavaScript-Code in Bun ausführen, kompiliert JavaScriptCore (die Engine) Ihren Quellcode in Bytecode. Wir können diese Parsing-Arbeit von der Laufzeit zur Bündelungszeit verschieben und Ihnen Startzeit sparen.


Einbetten von Laufzeit-Argumenten

--compile-exec-argv="args" - Betten Sie Laufzeit-Argumente ein, die über process.execArgv verfügbar sind:

bash
bun build --compile --compile-exec-argv="--smol --user-agent=MyBot" ./app.ts --outfile myapp
ts
// In der kompilierten App
console.log(process.execArgv); // ["--smol", "--user-agent=MyBot"]

Deaktivieren des automatischen Konfigurationsladens

Standardmäßig suchen eigenständige ausführbare Dateien nach .env- und bunfig.toml-Dateien im Verzeichnis, in dem die ausführbare Datei ausgeführt wird. Sie können dieses Verhalten zur Build-Zeit deaktivieren, um eine deterministische Ausführung unabhängig vom Arbeitsverzeichnis des Benutzers zu erreichen.

bash
# .env-Laden deaktivieren
bun build --compile --no-compile-autoload-dotenv ./app.ts --outfile myapp

# bunfig.toml-Laden deaktivieren
bun build --compile --no-compile-autoload-bunfig ./app.ts --outfile myapp

# Beides deaktivieren
bun build --compile --no-compile-autoload-dotenv --no-compile-autoload-bunfig ./app.ts --outfile myapp

Sie können dies auch über die JavaScript-API konfigurieren:

ts
await Bun.build({
  entrypoints: ["./app.ts"],
  compile: {
    autoloadDotenv: false, // .env-Laden deaktivieren
    autoloadBunfig: false, // bunfig.toml-Laden deaktivieren
  },
});

Als Bun-CLI fungieren

NOTE

Neu in Bun v1.2.16

Sie können eine eigenständige ausführbare Datei so ausführen, als wäre sie die bun-CLI selbst, indem Sie die Umgebungsvariable BUN_BE_BUN=1 setzen. Wenn diese Variable gesetzt ist, ignoriert die ausführbare Datei ihren gebündelten Einstiegspunkt und stellt stattdessen alle Funktionen der Bun-CLI bereit.

Betrachten Sie zum Beispiel eine ausführbare Datei, die aus einem einfachen Skript kompiliert wurde:

bash
echo "console.log(\"das sollten Sie nicht sehen\");" > such-bun.js
bun build --compile ./such-bun.js
txt
[3ms] bundle 1 modules
[89ms] compile such-bun

Normalerweise würde die Ausführung von ./such-bun mit Argumenten das Skript ausführen.

bash
# Executable führt standardmäßig seinen eigenen Einstiegspunkt aus
./such-bun install
txt
das sollten Sie nicht sehen

Mit der Umgebungsvariable BUN_BE_BUN=1 verhält sie sich jedoch genau wie die bun-Binärdatei:

bash
# Mit der Umgebungsvariable verhält sich die ausführbare Datei wie die `bun`-CLI
BUN_BE_BUN=1 ./such-bun install
txt
bun install v1.2.16-canary.1 (1d1db811)
Checked 63 installs across 64 packages (no changes) [5.00ms]

Dies ist nützlich für die Erstellung von CLI-Tools auf Basis von Bun, die Pakete installieren, Abhängigkeiten bündeln, verschiedene oder lokale Dateien ausführen und mehr benötigen, ohne eine separate Binärdatei herunterladen oder Bun installieren zu müssen.


Full-Stack-ausführbare Dateien

NOTE

Neu in Bun v1.2.17

Buns --compile-Flagge kann eigenständige ausführbare Dateien erstellen, die sowohl Server- als auch Client-Code enthalten, was sie ideal für Full-Stack-Anwendungen macht. Wenn Sie eine HTML-Datei in Ihrem Server-Code importieren, bündelt Bun automatisch alle Frontend-Assets (JavaScript, CSS usw.) und bettet sie in die ausführbare Datei ein. Wenn Bun den HTML-Import auf dem Server sieht, startet es einen Frontend-Build-Prozess, um JavaScript, CSS und andere Assets zu bündeln.

ts
import { serve } from "bun";
import index from "./index.html";

const server = serve({
  routes: {
    "/": index,
    "/api/hello": { GET: () => Response.json({ message: "Hallo von der API" }) },
  },
});

console.log(`Server läuft unter http://localhost:${server.port}`);
html
<!DOCTYPE html>
<html>
  <head>
    <title>Meine App</title>
    <link rel="stylesheet" href="./styles.css" />
  </head>
  <body>
    <h1>Hallo Welt</h1>
    <script src="./app.ts"></script>
  </body>
</html>
ts
console.log("Hallo vom Client!");
css
body {
  background-color: #f0f0f0;
}

Um dies in eine einzelne ausführbare Datei zu bauen:

bash
bun build --compile ./server.ts --outfile myapp

Dies erstellt eine in sich geschlossene Binärdatei, die Folgendes enthält:

  • Ihren Server-Code
  • Die Bun-Laufzeit
  • Alle Frontend-Assets (HTML, CSS, JavaScript)
  • Alle npm-Pakete, die von Ihrem Server verwendet werden

Das Ergebnis ist eine einzelne Datei, die überall bereitgestellt werden kann, ohne dass Node.js, Bun oder Abhängigkeiten installiert sein müssen. Einfach ausführen:

bash
./myapp

Bun übernimmt automatisch das Bereitstellen der Frontend-Assets mit den richtigen MIME-Typen und Cache-Headern. Der HTML-Import wird durch ein Manifest-Objekt ersetzt, das Bun.serve verwendet, um vorgebündelte Assets effizient bereitzustellen.

Für weitere Details zum Erstellen von Full-Stack-Anwendungen mit Bun siehe den Full-Stack-Leitfaden.


Worker

Um Worker in einer eigenständigen ausführbaren Datei zu verwenden, fügen Sie den Einstiegspunkt des Workers zu den CLI-Argumenten hinzu:

bash
bun build --compile ./index.ts ./my-worker.ts --outfile myapp

Referenzieren Sie dann den Worker in Ihrem Code:

ts
console.log("Hallo von Bun!");

// Jede davon funktioniert:
new Worker("./my-worker.ts");
new Worker(new URL("./my-worker.ts", import.meta.url));
new Worker(new URL("./my-worker.ts", import.meta.url).href);

Wenn Sie mehrere Einstiegspunkte zu einer eigenständigen ausführbaren Datei hinzufügen, werden diese separat in die ausführbare Datei gebündelt.

In Zukunft werden wir möglicherweise Verwendungen von statisch bekannten Pfaden in new Worker(path) automatisch erkennen und diese dann in die ausführbare Datei bündeln, aber im Moment müssen Sie sie manuell zum Shell-Befehl hinzufügen wie im obigen Beispiel.

Wenn Sie einen relativen Pfad zu einer Datei verwenden, die nicht in der eigenständigen ausführbaren Datei enthalten ist, wird versucht, diesen Pfad von der Festplatte relativ zum aktuellen Arbeitsverzeichnis des Prozesses zu laden (und dann einen Fehler zu werfen, wenn er nicht existiert).


SQLite

Sie können bun:sqlite-Importe mit bun build --compile verwenden.

Standardmäßig wird die Datenbank relativ zum aktuellen Arbeitsverzeichnis des Prozesses aufgelöst.

ts
import db from "./my.db" with { type: "sqlite" };

console.log(db.query("select * from users LIMIT 1").get());

Das bedeutet, wenn sich die ausführbare Datei unter /usr/bin/hello befindet und sich das Terminal des Benutzers unter /home/me/Desktop befindet, wird nach /home/me/Desktop/my.db gesucht.

bash
cd /home/me/Desktop
./hello

Einbetten von Assets und Dateien

Eigenständige ausführbare Dateien unterstützen das Einbetten von Dateien.

Um Dateien in eine ausführbare Datei mit bun build --compile einzubetten, importieren Sie die Datei in Ihrem Code.

ts
// dies wird zu einem internen Dateipfad
import icon from "./icon.png" with { type: "file" };
import { file } from "bun";

export default {
  fetch(req) {
    // Eingebettete Dateien können von Response-Objekten gestreamt werden
    return new Response(file(icon));
  },
};

Eingebettete Dateien können mit den Funktionen von Bun.file oder der Node.js fs.readFile-Funktion (in "node:fs") gelesen werden.

Um beispielsweise den Inhalt der eingebetteten Datei zu lesen:

ts
import icon from "./icon.png" with { type: "file" };
import { file } from "bun";

const bytes = await file(icon).arrayBuffer();
// await fs.promises.readFile(icon)
// fs.readFileSync(icon)

Einbetten von SQLite-Datenbanken

Wenn Ihre Anwendung eine SQLite-Datenbank einbetten möchte, setzen Sie type: "sqlite" im Import-Attribut und das embed-Attribut auf "true".

ts
import myEmbeddedDb from "./my.db" with { type: "sqlite", embed: "true" };

console.log(myEmbeddedDb.query("select * from users LIMIT 1").get());

Diese Datenbank ist lesbar und schreibbar, aber alle Änderungen gehen verloren, wenn die ausführbare Datei beendet wird (da sie im Speicher gespeichert ist).

Einbetten von N-API-Addons

Sie können .node-Dateien in ausführbare Dateien einbetten.

ts
const addon = require("./addon.node");

console.log(addon.hello());

Leider müssen Sie, wenn Sie @mapbox/node-pre-gyp oder andere ähnliche Tools verwenden, sicherstellen, dass die .node-Datei direkt erforderlich ist, da sie sonst nicht korrekt gebündelt wird.

Einbetten von Verzeichnissen

Um ein Verzeichnis mit bun build --compile einzubetten, verwenden Sie einen Shell-Glob in Ihrem bun build-Befehl:

bash
bun build --compile ./index.ts ./public/**/*.png

Dann können Sie die Dateien in Ihrem Code referenzieren:

ts
import icon from "./public/assets/icon.png" with { type: "file" };
import { file } from "bun";

export default {
  fetch(req) {
    // Eingebettete Dateien können von Response-Objekten gestreamt werden
    return new Response(file(icon));
  },
};

Dies ist ehrlich gesagt ein Workaround, und wir erwarten, dies in der Zukunft mit einer direkteren API zu verbessern.

Auflisten eingebetteter Dateien

Um eine Liste aller eingebetteten Dateien zu erhalten, verwenden Sie Bun.embeddedFiles:

ts
import "./icon.png" with { type: "file" };
import { embeddedFiles } from "bun";

console.log(embeddedFiles[0].name); // `icon-${hash}.png`

Bun.embeddedFiles gibt ein Array von Blob-Objekten zurück, mit dem Sie die Größe, den Inhalt und andere Eigenschaften der Dateien abrufen können.

ts
embeddedFiles: Blob[]

Die Liste der eingebetteten Dateien schließt gebündelten Quellcode wie .ts- und .js-Dateien aus.

Inhalts-Hash

Standardmäßig haben eingebettete Dateien einen Inhalts-Hash, der an ihren Namen angehängt wird. Dies ist nützlich für Situationen, in denen Sie die Datei von einer URL oder einem CDN bereitstellen möchten und weniger Cache-Invalidierungsprobleme haben. Aber manchmal ist dies unerwartet und Sie möchten stattdessen den ursprünglichen Namen haben:

Um den Inhalts-Hash zu deaktivieren, übergeben Sie --asset-naming an bun build --compile wie folgt:

bash
bun build --compile --asset-naming="[name].[ext]" ./index.ts

Minifizierung

Um die Größe der ausführbaren Datei etwas zu reduzieren, übergeben Sie --minify an bun build --compile. Dies verwendet Buns Minifizierer, um die Codegröße zu reduzieren. Insgesamt ist Buns Binärdatei jedoch immer noch viel zu groß und wir müssen sie kleiner machen.


Windows-spezifische Flags

Beim Kompilieren einer eigenständigen ausführbaren Datei unter Windows gibt es zwei plattformspezifische Optionen, die zum Anpassen der Metadaten der generierten .exe-Datei verwendet werden können:

  • --windows-icon=path/to/icon.ico zum Anpassen des Symbols der ausführbaren Datei.
  • --windows-hide-console zum Deaktivieren des Hintergrundterminals, was für Anwendungen verwendet werden kann, die kein TTY benötigen.

Code-Signierung unter macOS

Um eine eigenständige ausführbare Datei unter macOS zu signieren (was Gatekeeper-Warnungen behebt), verwenden Sie den codesign-Befehl.

bash
codesign --deep --force -vvvv --sign "XXXXXXXXXX" ./myapp

Wir empfehlen, eine entitlements.plist-Datei mit JIT-Berechtigungen einzufügen.

xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>com.apple.security.cs.allow-jit</key>
    <true/>
    <key>com.apple.security.cs.allow-unsigned-executable-memory</key>
    <true/>
    <key>com.apple.security.cs.disable-executable-page-protection</key>
    <true/>
    <key>com.apple.security.cs.allow-dyld-environment-variables</key>
    <true/>
    <key>com.apple.security.cs.disable-library-validation</key>
    <true/>
</dict>
</plist>

Um mit JIT-Unterstützung zu signieren, übergeben Sie die --entitlements-Flagge an codesign.

bash
codesign --deep --force -vvvv --sign "XXXXXXXXXX" --entitlements entitlements.plist ./myapp

Überprüfen Sie nach der Code-Signierung die ausführbare Datei:

bash
codesign -vvv --verify ./myapp
./myapp: valid on disk
./myapp: satisfies its Designated Requirement

Code-Splitting

Eigenständige ausführbare Dateien unterstützen Code-Splitting. Verwenden Sie --compile mit --splitting, um eine ausführbare Datei zu erstellen, die zur Laufzeit code-geteilteChunks lädt.

bash
bun build --compile --splitting ./src/entry.ts --outdir ./build
ts
console.log("Einstiegspunkt geladen");
const lazy = await import("./lazy.ts");
lazy.hello();
ts
export function hello() {
  console.log("Fauler Modul geladen");
}
bash
./build/entry
txt
Einstiegspunkt geladen
Fauler Modul geladen

Nicht unterstützte CLI-Argumente

Derzeit kann die --compile-Flagge nur einen einzigen Einstiegspunkt gleichzeitig akzeptieren und unterstützt die folgenden Flags nicht:

  • --outdir — verwenden Sie stattdessen outfile (außer bei Verwendung mit --splitting).
  • --public-path
  • --target=node oder --target=browser
  • --no-bundle - wir bündeln immer alles in die ausführbare Datei.

Bun von www.bunjs.com.cn bearbeitet