Bun ist nicht nur Runtime, sondern auch Bundler. Kein Webpack, kein Rollup, keine separate Konfigurationsdatei. Der Bundler ist in die Runtime integriert und nutzt dieselbe schnelle Zig-basierte Architektur.
Grundlegende Nutzung
Ein einfacher Build:
bun build ./src/index.ts --outdir ./dist
Oder programmatisch:
const result = await Bun.build({
entrypoints: ["./src/index.ts"],
outdir: "./dist",
});
if (!result.success) {
console.error("Build failed:", result.logs);
}
Das Ergebnis ist ein optimiertes JavaScript-Bundle.
Build-Optionen
Die wichtigsten Konfigurationsoptionen:
await Bun.build({
entrypoints: ["./src/index.ts"],
outdir: "./dist",
// Zielumgebung
target: "browser", // oder "bun", "node"
// Optimierungen
minify: true,
sourcemap: "external",
// Splitting für Code-Splitting
splitting: true,
// Externe Pakete nicht bundlen
external: ["react", "react-dom"],
// Umgebungsvariablen inlinen
define: {
"process.env.NODE_ENV": JSON.stringify("production"),
},
});
Plugins entwickeln
Plugins erweitern den Build-Prozess. Die API ist einfach:
import type { BunPlugin } from "bun";
const myPlugin: BunPlugin = {
name: "my-plugin",
setup(build) {
// Hooks registrieren
},
};
await Bun.build({
entrypoints: ["./src/index.ts"],
outdir: "./dist",
plugins: [myPlugin],
});
onLoad Hook
Der häufigste Hook transformiert Dateien:
const textPlugin: BunPlugin = {
name: "text-loader",
setup(build) {
build.onLoad({ filter: /\.txt$/ }, async (args) => {
const content = await Bun.file(args.path).text();
return {
contents: `export default ${JSON.stringify(content)}`,
loader: "js",
};
});
},
};
Jetzt können .txt-Dateien importiert werden:
import readme from "./README.txt";
console.log(readme);
onResolve Hook
Für Custom Module Resolution:
const aliasPlugin: BunPlugin = {
name: "alias",
setup(build) {
build.onResolve({ filter: /^@components\// }, (args) => {
const path = args.path.replace("@components/", "./src/components/");
return { path };
});
},
};
Praktisches Beispiel: YAML-Loader
import { parse } from "yaml";
const yamlPlugin: BunPlugin = {
name: "yaml-loader",
setup(build) {
build.onLoad({ filter: /\.ya?ml$/ }, async (args) => {
const text = await Bun.file(args.path).text();
const data = parse(text);
return {
contents: `export default ${JSON.stringify(data)}`,
loader: "js",
};
});
},
};
Tree-Shaking
Tree-Shaking ist standardmäßig aktiviert. Der Bundler entfernt ungenutzte Exports automatisch.
ESM-Module
Bei ES-Modulen funktioniert Tree-Shaking optimal:
// utils.ts
export const used = () => "wird genutzt";
export const unused = () => "wird entfernt";
// index.ts
import { used } from "./utils";
console.log(used());
// unused wird aus dem Bundle entfernt
CommonJS-Einschränkungen
Bei CommonJS ist statische Analyse schwieriger:
// Problematisch - dynamischer Export
module.exports = require("./dynamic");
// Besser - statischer Export
module.exports = {
foo: require("./foo"),
bar: require("./bar"),
};
Bun konvertiert CommonJS zu ESM wo möglich, aber dynamische Patterns verhindern Tree-Shaking.
Seiteneffekte markieren
Für optimales Tree-Shaking in package.json:
{
"sideEffects": false
}
Oder spezifische Dateien mit Seiteneffekten:
{
"sideEffects": ["./src/polyfills.js", "*.css"]
}
Code-Splitting
Mit splitting: true erzeugt Bun separate Chunks:
await Bun.build({
entrypoints: ["./src/index.ts"],
outdir: "./dist",
splitting: true,
});
Dynamische Imports werden automatisch in separate Dateien extrahiert:
// Wird als separater Chunk gebundelt
const module = await import("./heavy-module");
Sourcemaps
Für Debugging in Production:
await Bun.build({
entrypoints: ["./src/index.ts"],
outdir: "./dist",
sourcemap: "external", // oder "inline", "none"
minify: true,
});
Externe Sourcemaps landen als .js.map-Dateien im Output-Verzeichnis.
Build-Artefakte
Bun.build gibt ein Array von BuildArtifact-Objekten zurück:
const result = await Bun.build({
entrypoints: ["./src/index.ts"],
outdir: "./dist",
});
for (const artifact of result.outputs) {
console.log(artifact.path); // Ausgabepfad
console.log(artifact.kind); // "entry-point", "chunk", "asset"
console.log(artifact.loader); // "js", "css", etc.
// Inhalt lesen
const text = await artifact.text();
}
Vergleich mit anderen Bundlern
| Feature | Bun | Webpack | Rollup | esbuild |
|---|---|---|---|---|
| Zero-Config | Ja | Nein | Nein | Ja |
| TypeScript | Native | Loader | Plugin | Native |
| Tree-Shaking | Ja | Ja | Ja | Ja |
| Code-Splitting | Ja | Ja | Ja | Ja |
| Plugin-API | Einfach | Komplex | Mittel | Einfach |
| Speed | Sehr schnell | Langsam | Mittel | Sehr schnell |
Bun und esbuild sind ähnlich schnell. Buns Vorteil: Es ist gleichzeitig Runtime, Bundler und Package Manager.