-
-
Notifications
You must be signed in to change notification settings - Fork 0
Build Optimization
Master Bun's build system - Learn to create optimized production builds, configure advanced bundling options, and analyze bundle performance with Arsenal Lab's interactive playground.
This comprehensive tutorial covers:
- Interactive Bun.build() API exploration
- Production-ready build configuration
- Bundle size optimization techniques
- Code splitting and lazy loading
- Source maps and debugging
- Performance analysis and monitoring
- CLI integration and automation
- Arsenal Lab running (Getting Started)
- Basic understanding of bundlers
- Node.js/npm experience
- 20-25 minutes available
cd Arsenal-Lab
bun run devNavigate to http://localhost:3655 and select "Build Configuration Arsenal".
- Configuration Tabs: Core, Environment, JSX, Optimization, Output, Advanced, CLI
- Live Code Generation: Real-time config updates
- CLI Command Preview: Copy-paste ready commands
- Build Execution: Test configurations instantly
- Click "Core Options" tab
- Set Entry points:
["./src/index.ts", "./src/worker.ts"] - Choose Target:
browser(try different targets) - Select Format:
esm
What you'll see:
// Generated configuration
{
"entrypoints": ["./src/index.ts", "./src/worker.ts"],
"target": "browser",
"format": "esm"
}- browser: Web applications, uses DOM APIs
- bun: Bun runtime, access to Bun APIs
- node: Node.js applications, uses Node APIs
- esm: ES modules (recommended)
- cjs: CommonJS modules
- iife: Immediately Invoked Function Expression
- Switch to "Environment Options"
- Add Define:
{"__DEV__": "true", "API_URL": "https://api.example.com"} - Set Env mode:
inline
Generated code:
{
"define": {
"__DEV__": "true",
"API_URL": "https://api.example.com"
},
"env": "inline"
}// In your code
if (__DEV__) {
console.log('Development mode');
}
const apiUrl = API_URL; // Replaced at build time// Advanced environment setup
{
"conditions": ["browser", "development"],
"env": {
"inline": ["NODE_ENV", "API_URL"],
"external": ["SECRET_KEY"] // Not inlined
}
}- Click "JSX Options"
- Set Runtime:
automatic - Configure Factory:
React.createElement - Set Fragment:
React.Fragment
JSX configuration:
{
"jsx": {
"runtime": "automatic",
"factory": "React.createElement",
"fragment": "React.Fragment",
"importSource": "@emotion/react" // For CSS-in-JS
}
}- automatic: Modern JSX transform (recommended)
- classic: Legacy JSX transform
// With CSS-in-JS libraries
{
"jsx": {
"runtime": "automatic",
"importSource": "@emotion/react"
}
}
// Custom JSX pragma
{
"jsx": {
"factory": "h",
"fragment": "Fragment"
}
}- Go to "Optimization" tab
- Enable Minify:
true - Configure detailed options:
-
Whitespace:
true -
Syntax:
true -
Identifiers:
true
-
Whitespace:
Optimization config:
{
"minify": {
"whitespace": true,
"syntax": true,
"identifiers": true
}
}// Enable code splitting
{
"splitting": true,
"format": "esm" // Required for splitting
}
// Lazy loading example
import { lazy } from 'react';
const LazyComponent = lazy(() =>
import('./components/HeavyComponent')
);// Externalize large libraries
{
"external": ["react", "react-dom", "lodash"],
"packages": "external" // Externalize all node_modules
}- Click "Output" tab
- Configure Naming:
-
Entry:
"[name]-[hash].js" -
Chunk:
"chunk-[hash].js" -
Asset:
"asset-[name]-[hash].[ext]"
-
Entry:
Output configuration:
{
"outdir": "./dist",
"naming": {
"entry": "[name]-[hash].js",
"chunk": "chunk-[hash].js",
"asset": "asset-[name]-[hash].[ext]"
},
"publicPath": "/assets/",
"sourcemap": "linked"
}- none: No source maps (production)
- linked: Separate .map files
- inline: Embedded in bundle
- external: External source maps
- Go to "Advanced" tab
- Enable Bytecode:
true(Bun feature)
Advanced options:
{
"bytecode": true,
"throw": false,
"banner": "// Built with Arsenal Lab",
"footer": "// End of bundle",
"drop": ["console", "debugger"],
"ignoreDCEAnnotations": false,
"emitDCEAnnotations": true
}// Mark code for elimination
/* @__PURE__ */ function unusedFunction() {
return 'This will be removed';
}
// Conditional dead code
if (__DEV__) {
console.log('Development only');
}- Switch to "CLI Options" tab
- Enable Watch mode:
true - Set Production:
true
Generated CLI command:
bun build ./src/index.ts \
--target=browser \
--format=esm \
--minify \
--outdir=./dist \
--sourcemap=linked \
--watch \
--production- --watch: Rebuild on file changes
- --production: Enable production optimizations
- --compile: Create standalone executable
- --no-clear-screen: Keep terminal output
// Analyze bundle composition
const { build } = await import('bun');
const result = await build({
entrypoints: ['./src/index.ts'],
target: 'browser',
minify: true,
// ... other options
});
console.log('Build completed:');
console.log(`- Output files: ${result.outputs.length}`);
console.log(`- Total size: ${result.outputs.reduce((sum, out) => sum + out.size, 0)} bytes`);// Track build performance
class BuildMonitor {
constructor() {
this.builds = [];
}
async timeBuild(config) {
const start = performance.now();
const result = await Bun.build(config);
const duration = performance.now() - start;
this.builds.push({
timestamp: new Date(),
duration,
config,
outputSize: result.outputs.reduce((sum, out) => sum + out.size, 0),
success: !result.logs.some(log => log.level === 'error')
});
return result;
}
getBuildStats() {
const successful = this.builds.filter(b => b.success);
return {
totalBuilds: this.builds.length,
successfulBuilds: successful.length,
avgDuration: successful.reduce((sum, b) => sum + b.duration, 0) / successful.length,
fastestBuild: Math.min(...successful.map(b => b.duration)),
slowestBuild: Math.max(...successful.map(b => b.duration))
};
}
}// Development configuration
const devConfig = {
entrypoints: ['./src/index.ts'],
target: 'browser',
minify: false,
sourcemap: 'linked',
define: { __DEV__: 'true' }
};
// Production configuration
const prodConfig = {
...devConfig,
minify: { whitespace: true, syntax: true, identifiers: true },
sourcemap: 'external',
define: { __DEV__: 'false' },
drop: ['console']
};// Test different targets
const targets = ['browser', 'bun', 'node'];
const formats = ['esm', 'cjs', 'iife'];
for (const target of targets) {
for (const format of formats) {
try {
const result = await Bun.build({
entrypoints: ['./src/index.ts'],
target,
format,
outdir: `./dist/${target}-${format}`
});
console.log(`β
${target}-${format}: ${result.outputs.length} files`);
} catch (error) {
console.log(`β ${target}-${format}: ${error.message}`);
}
}
}// Optimize for CDN deployment
const cdnConfig = {
entrypoints: ['./src/index.ts'],
target: 'browser',
format: 'esm',
minify: true,
splitting: true,
publicPath: 'https://cdn.example.com/assets/',
naming: {
entry: '[name]-[hash].js',
chunk: 'chunk-[hash].js'
}
};// Generate service worker-friendly build
const swConfig = {
...cdnConfig,
banner: `
// Service Worker Cache Version: ${Date.now()}
const CACHE_NAME = 'app-v${Date.now()}';
`,
footer: `
// Register service worker
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js');
}
`
};// Define performance budgets
const budgets = {
bundleSize: 500 * 1024, // 500KB
vendorSize: 200 * 1024, // 200KB
initialChunk: 100 * 1024, // 100KB
buildTime: 30 * 1000 // 30 seconds
};
function checkBudgets(result, buildTime) {
const violations = [];
const totalSize = result.outputs.reduce((sum, out) => sum + out.size, 0);
if (totalSize > budgets.bundleSize) {
violations.push(`Bundle too large: ${totalSize} > ${budgets.bundleSize}`);
}
if (buildTime > budgets.buildTime) {
violations.push(`Build too slow: ${buildTime}ms > ${budgets.buildTime}ms`);
}
return violations;
}# CI build script
#!/bin/bash
echo "ποΈ Building application..."
start_time=$(date +%s%3N)
bun build ./src/index.ts --target=browser --minify --outdir=./dist
build_time=$(( $(date +%s%3N) - start_time ))
echo "β
Build completed in ${build_time}ms"
# Check bundle size
bundle_size=$(du -bc dist/* | tail -1 | awk '{print $1}')
echo "π¦ Bundle size: ${bundle_size} bytes"
# Performance assertions
if [ "$bundle_size" -gt 524288 ]; then
echo "β Bundle size exceeds 512KB limit"
exit 1
fi
if [ "$build_time" -gt 30000 ]; then
echo "β Build time exceeds 30s limit"
exit 1
fi
echo "π All performance budgets passed!"β Core build configuration with Bun.build() API β Environment and JSX setup for different targets β Optimization techniques for production builds β Output configuration and source map management β Advanced features like bytecode and DCE β CLI integration and automation β Performance monitoring and budget enforcement
- Configuration matters - Fine-tune settings for your use case
- Target selection impacts available APIs and optimizations
- Code splitting reduces initial bundle size
- Source maps enable debugging in production
- Performance budgets prevent regressions
- Automation ensures consistent builds
- Development: Fast rebuilds, source maps, no minification
- Staging: Production config, debugging enabled
- Production: Full optimization, error tracking, CDN deployment
Build Optimization Expert π You've mastered Bun's build system and learned to:
- Configure advanced build options
- Optimize bundle size and performance
- Implement code splitting and lazy loading
- Set up CI/CD pipelines
- Monitor build performance
- Create deployment-ready configurations
- Performance Testing Tutorial - Benchmark your builds
- Integration Guides - Framework-specific builds
- Deployment Guide - Production deployment
- Bun Discord - Real-time help
- GitHub Issues - Bug reports
- Awesome Bun - Tools and libraries
Questions? Join our GitHub Discussions or check the Troubleshooting Guide.
Built with β€οΈ for the Bun ecosystem β’ Last updated: October 21, 2025