Bun Bundler
Bun includes a high-performance bundler that can package JavaScript/TypeScript code for browser or server environments. This chapter introduces how to use the Bun bundler.
Basic Bundling
Command Line Bundling
bash
# Basic bundling
bun build ./src/index.ts --outdir ./dist
# Specify output file
bun build ./src/index.ts --outfile ./dist/bundle.js
# Generate source map
bun build ./src/index.ts --outdir ./dist --sourcemap
# Minify code
bun build ./src/index.ts --outdir ./dist --minifyAPI Bundling
typescript
// build.ts
const result = await Bun.build({
entrypoints: ["./src/index.ts"],
outdir: "./dist",
});
if (!result.success) {
console.error("Build failed:");
for (const log of result.logs) {
console.error(log);
}
} else {
console.log("Build successful!");
for (const output of result.outputs) {
console.log("Output:", output.path);
}
}Build Options
Full Configuration
typescript
const result = await Bun.build({
// Entry files (can be multiple)
entrypoints: ["./src/index.ts", "./src/worker.ts"],
// Output directory
outdir: "./dist",
// Target environment
target: "browser", // "browser" | "bun" | "node"
// Module format
format: "esm", // "esm" | "cjs" | "iife"
// Code splitting
splitting: true,
// Minification
minify: true,
// Or set separately
// minify: {
// whitespace: true,
// identifiers: true,
// syntax: true,
// },
// Source Map
sourcemap: "external", // "none" | "inline" | "external"
// Naming pattern
naming: {
entry: "[name].[hash].js",
chunk: "[name]-[hash].js",
asset: "[name]-[hash][ext]",
},
// External dependencies (not bundled)
external: ["react", "react-dom"],
// Define global constants
define: {
"process.env.NODE_ENV": JSON.stringify("production"),
__VERSION__: JSON.stringify("1.0.0"),
},
// Plugins
plugins: [],
// Loader configuration
loader: {
".png": "file",
".svg": "text",
},
// Public path
publicPath: "/assets/",
// Root directory
root: "./src",
});Target Environment
Browser Target
typescript
await Bun.build({
entrypoints: ["./src/app.ts"],
outdir: "./dist",
target: "browser",
// Browser-specific options
format: "esm",
splitting: true,
minify: true,
});Node.js Target
typescript
await Bun.build({
entrypoints: ["./src/server.ts"],
outdir: "./dist",
target: "node",
// Node.js specific
format: "cjs", // or "esm"
external: ["*"], // don't bundle node_modules
});Bun Target
typescript
await Bun.build({
entrypoints: ["./src/app.ts"],
outdir: "./dist",
target: "bun",
// Bun runtime optimizations
});Code Splitting
Automatic Code Splitting
typescript
await Bun.build({
entrypoints: ["./src/index.ts"],
outdir: "./dist",
splitting: true, // Enable code splitting
});Dynamic Import
typescript
// src/index.ts
// Dynamic imports will be automatically split into separate chunks
const module = await import("./heavy-module.ts");
module.doSomething();
// Conditional import
if (needFeature) {
const feature = await import("./feature.ts");
feature.init();
}Multi-Entry Splitting
typescript
await Bun.build({
entrypoints: [
"./src/pages/home.ts",
"./src/pages/about.ts",
"./src/pages/contact.ts",
],
outdir: "./dist",
splitting: true,
});
// Shared code will be automatically extracted into common chunksAsset Handling
Built-in Loaders
typescript
await Bun.build({
entrypoints: ["./src/index.ts"],
outdir: "./dist",
loader: {
// Output as files (return URL)
".png": "file",
".jpg": "file",
".gif": "file",
".woff2": "file",
// Import as text
".txt": "text",
".md": "text",
".html": "text",
// Import as JSON
".json": "json",
// Import as Base64 data URL
".svg": "dataurl",
// Import as binary data
".bin": "binary",
// JavaScript/TypeScript
".js": "js",
".ts": "ts",
".jsx": "jsx",
".tsx": "tsx",
// CSS
".css": "css",
},
});Importing Assets
typescript
// Import images (returns URL)
import logoUrl from "./logo.png";
const img = document.createElement("img");
img.src = logoUrl;
// Import text
import readme from "./README.md" with { type: "text" };
console.log(readme);
// Import JSON
import config from "./config.json";
console.log(config.version);CSS Handling
Importing CSS
typescript
// Import CSS file
import "./styles.css";
// CSS modules (experimental)
import styles from "./component.module.css";
element.className = styles.container;CSS Bundling
typescript
await Bun.build({
entrypoints: ["./src/index.ts"],
outdir: "./dist",
// CSS will be bundled automatically
});External Dependencies
Excluding Dependencies
typescript
await Bun.build({
entrypoints: ["./src/index.ts"],
outdir: "./dist",
// Don't bundle these dependencies
external: ["react", "react-dom", "lodash"],
});Excluding All node_modules
typescript
await Bun.build({
entrypoints: ["./src/index.ts"],
outdir: "./dist",
// Use wildcard to exclude all
external: ["*"],
});Dynamic Exclusion
typescript
import { dependencies } from "./package.json";
await Bun.build({
entrypoints: ["./src/index.ts"],
outdir: "./dist",
external: Object.keys(dependencies),
});Environment Variable Replacement
define Option
typescript
await Bun.build({
entrypoints: ["./src/index.ts"],
outdir: "./dist",
define: {
"process.env.NODE_ENV": JSON.stringify("production"),
"process.env.API_URL": JSON.stringify("https://api.example.com"),
__DEV__: "false",
__VERSION__: JSON.stringify("1.0.0"),
},
});Usage in Code
typescript
// src/index.ts
if (process.env.NODE_ENV === "development") {
console.log("Development mode");
}
console.log("Version:", __VERSION__);
console.log("API:", process.env.API_URL);Plugin System
Plugin Interface
typescript
import type { BunPlugin } from "bun";
const myPlugin: BunPlugin = {
name: "my-plugin",
setup(build) {
// Intercept module resolution
build.onResolve({ filter: /^virtual:/ }, (args) => {
return {
path: args.path,
namespace: "virtual",
};
});
// Intercept module loading
build.onLoad({ filter: /.*/, namespace: "virtual" }, (args) => {
return {
contents: `export default "${args.path}"`,
loader: "js",
};
});
},
};
await Bun.build({
entrypoints: ["./src/index.ts"],
outdir: "./dist",
plugins: [myPlugin],
});YAML Plugin Example
typescript
import { parse as parseYaml } 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 = parseYaml(text);
return {
contents: `export default ${JSON.stringify(data)}`,
loader: "js",
};
});
},
};
// Usage
import config from "./config.yaml";
console.log(config);Environment Variable Plugin
typescript
const envPlugin: BunPlugin = {
name: "env-plugin",
setup(build) {
build.onResolve({ filter: /^env:/ }, (args) => {
return {
path: args.path.slice(4), // Remove "env:" prefix
namespace: "env",
};
});
build.onLoad({ filter: /.*/, namespace: "env" }, (args) => {
const value = Bun.env[args.path] || "";
return {
contents: `export default ${JSON.stringify(value)}`,
loader: "js",
};
});
},
};
// Usage
import apiKey from "env:API_KEY";Build Scripts
package.json Configuration
json
{
"scripts": {
"build": "bun run build.ts",
"build:dev": "bun run build.ts --mode development",
"build:prod": "bun run build.ts --mode production"
}
}Complete Build Script
typescript
// build.ts
const mode = Bun.argv.includes("--mode")
? Bun.argv[Bun.argv.indexOf("--mode") + 1]
: "production";
const isDev = mode === "development";
console.log(`Build mode: ${mode}`);
// Clean output directory
await Bun.$`rm -rf dist`;
// Build client code
const clientResult = await Bun.build({
entrypoints: ["./src/client/index.tsx"],
outdir: "./dist/public",
target: "browser",
format: "esm",
splitting: true,
minify: !isDev,
sourcemap: isDev ? "inline" : "external",
define: {
"process.env.NODE_ENV": JSON.stringify(mode),
},
naming: {
entry: isDev ? "[name].js" : "[name].[hash].js",
chunk: isDev ? "[name].js" : "[name].[hash].js",
},
});
if (!clientResult.success) {
console.error("Client build failed");
process.exit(1);
}
// Build server code
const serverResult = await Bun.build({
entrypoints: ["./src/server/index.ts"],
outdir: "./dist",
target: "bun",
format: "esm",
minify: !isDev,
external: ["*"], // Don't bundle dependencies
});
if (!serverResult.success) {
console.error("Server build failed");
process.exit(1);
}
// Copy static files
await Bun.$`cp -r ./public/* ./dist/public/`;
console.log("Build complete!");
console.log("Client files:");
clientResult.outputs.forEach(o => console.log(" ", o.path));
console.log("Server files:");
serverResult.outputs.forEach(o => console.log(" ", o.path));Comparison with Other Tools
Speed Comparison
Bundling React app (with dependencies):
┌────────────────────────────────────────────┐
│ webpack ██████████████████████████ 12s │
│ esbuild ████ 1.5s │
│ bun ███ 1.1s │
└────────────────────────────────────────────┘Feature Comparison
| Feature | Bun | esbuild | webpack | Vite |
|---|---|---|---|---|
| Speed | Very Fast | Very Fast | Slow | Fast |
| Config Complexity | Low | Low | High | Medium |
| Plugin Ecosystem | Growing | Limited | Rich | Rich |
| Code Splitting | ✅ | ✅ | ✅ | ✅ |
| HMR | ✅ | ❌ | ✅ | ✅ |
| TypeScript | ✅ | ✅ | Plugin needed | ✅ |
Summary
This chapter covered:
- ✅ Command line and API bundling
- ✅ Build options and target environments
- ✅ Code splitting and asset handling
- ✅ External dependencies and environment variables
- ✅ Plugin system
- ✅ Complete build script examples
Next Steps
Continue reading Test Runner to learn about Bun's built-in testing framework.