Skip to content

Build Optimization

Brenda Willams edited this page Oct 22, 2025 · 2 revisions

πŸ”§ Build Optimization Tutorial

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.

Advanced Time Build Focus

🎯 Tutorial Overview

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

πŸ“‹ Prerequisites

  • Arsenal Lab running (Getting Started)
  • Basic understanding of bundlers
  • Node.js/npm experience
  • 20-25 minutes available

πŸš€ Step 1: Launch Build Configuration Arsenal

cd Arsenal-Lab
bun run dev

Navigate to http://localhost:3655 and select "Build Configuration Arsenal".

Interface Overview

  • 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

βš™οΈ Step 2: Core Build Configuration

Entry Points & Targets

  1. Click "Core Options" tab
  2. Set Entry points: ["./src/index.ts", "./src/worker.ts"]
  3. Choose Target: browser (try different targets)
  4. Select Format: esm

What you'll see:

// Generated configuration
{
  "entrypoints": ["./src/index.ts", "./src/worker.ts"],
  "target": "browser",
  "format": "esm"
}

Understanding Targets

  • browser: Web applications, uses DOM APIs
  • bun: Bun runtime, access to Bun APIs
  • node: Node.js applications, uses Node APIs

Format Options

  • esm: ES modules (recommended)
  • cjs: CommonJS modules
  • iife: Immediately Invoked Function Expression

🎨 Step 3: Environment Configuration

Define Variables

  1. Switch to "Environment Options"
  2. Add Define: {"__DEV__": "true", "API_URL": "https://api.example.com"}
  3. Set Env mode: inline

Generated code:

{
  "define": {
    "__DEV__": "true",
    "API_URL": "https://api.example.com"
  },
  "env": "inline"
}

Environment Handling

// In your code
if (__DEV__) {
  console.log('Development mode');
}

const apiUrl = API_URL; // Replaced at build time

Conditions Configuration

// Advanced environment setup
{
  "conditions": ["browser", "development"],
  "env": {
    "inline": ["NODE_ENV", "API_URL"],
    "external": ["SECRET_KEY"] // Not inlined
  }
}

βš›οΈ Step 4: JSX Configuration

JSX Setup

  1. Click "JSX Options"
  2. Set Runtime: automatic
  3. Configure Factory: React.createElement
  4. Set Fragment: React.Fragment

JSX configuration:

{
  "jsx": {
    "runtime": "automatic",
    "factory": "React.createElement",
    "fragment": "React.Fragment",
    "importSource": "@emotion/react" // For CSS-in-JS
  }
}

JSX Runtime Options

  • automatic: Modern JSX transform (recommended)
  • classic: Legacy JSX transform

Advanced JSX Features

// With CSS-in-JS libraries
{
  "jsx": {
    "runtime": "automatic",
    "importSource": "@emotion/react"
  }
}

// Custom JSX pragma
{
  "jsx": {
    "factory": "h",
    "fragment": "Fragment"
  }
}

πŸš€ Step 5: Optimization Techniques

Minification

  1. Go to "Optimization" tab
  2. Enable Minify: true
  3. Configure detailed options:
    • Whitespace: true
    • Syntax: true
    • Identifiers: true

Optimization config:

{
  "minify": {
    "whitespace": true,
    "syntax": true,
    "identifiers": true
  }
}

Code Splitting

// Enable code splitting
{
  "splitting": true,
  "format": "esm" // Required for splitting
}

// Lazy loading example
import { lazy } from 'react';

const LazyComponent = lazy(() =>
  import('./components/HeavyComponent')
);

External Dependencies

// Externalize large libraries
{
  "external": ["react", "react-dom", "lodash"],
  "packages": "external" // Externalize all node_modules
}

πŸ“¦ Step 6: Output Configuration

Naming Patterns

  1. Click "Output" tab
  2. Configure Naming:
    • Entry: "[name]-[hash].js"
    • Chunk: "chunk-[hash].js"
    • Asset: "asset-[name]-[hash].[ext]"

Output configuration:

{
  "outdir": "./dist",
  "naming": {
    "entry": "[name]-[hash].js",
    "chunk": "chunk-[hash].js",
    "asset": "asset-[name]-[hash].[ext]"
  },
  "publicPath": "/assets/",
  "sourcemap": "linked"
}

Source Maps

  • none: No source maps (production)
  • linked: Separate .map files
  • inline: Embedded in bundle
  • external: External source maps

πŸ”§ Step 7: Advanced Build Features

Bytecode Compilation

  1. Go to "Advanced" tab
  2. 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
}

Dead Code Elimination

// Mark code for elimination
/* @__PURE__ */ function unusedFunction() {
  return 'This will be removed';
}

// Conditional dead code
if (__DEV__) {
  console.log('Development only');
}

πŸ’» Step 8: CLI Integration

Command Generation

  1. Switch to "CLI Options" tab
  2. Enable Watch mode: true
  3. Set Production: true

Generated CLI command:

bun build ./src/index.ts \
  --target=browser \
  --format=esm \
  --minify \
  --outdir=./dist \
  --sourcemap=linked \
  --watch \
  --production

CLI Options Explained

  • --watch: Rebuild on file changes
  • --production: Enable production optimizations
  • --compile: Create standalone executable
  • --no-clear-screen: Keep terminal output

πŸ“Š Step 9: Build Analysis & Optimization

Bundle Size Analysis

// 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`);

Performance Monitoring

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

πŸ§ͺ Step 10: Testing Build Configurations

Development vs Production

// 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']
};

Cross-Platform Testing

// 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}`);
    }
  }
}

πŸš€ Step 11: Deployment Optimization

CDN Optimization

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

Service Worker Integration

// 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');
    }
  `
};

πŸ“ˆ Step 12: Performance Budgets

Size Limits

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

Continuous Integration

# 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!"

🎯 Tutorial Summary

Build Optimization Mastery

βœ… 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

Key Takeaways

  1. Configuration matters - Fine-tune settings for your use case
  2. Target selection impacts available APIs and optimizations
  3. Code splitting reduces initial bundle size
  4. Source maps enable debugging in production
  5. Performance budgets prevent regressions
  6. Automation ensures consistent builds

Production-Ready Patterns

  • Development: Fast rebuilds, source maps, no minification
  • Staging: Production config, debugging enabled
  • Production: Full optimization, error tracking, CDN deployment

πŸ† Achievement Unlocked!

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

πŸ“š Continue Your Journey

Advanced Topics

Reference Materials

Community Resources


Questions? Join our GitHub Discussions or check the Troubleshooting Guide.

Built with ❀️ for the Bun ecosystem β€’ Last updated: October 21, 2025

Clone this wiki locally