Lesson 07-Bun.js Building and Packaging

Application Build Basics

Project Initialization and Structure

Quick Project Creation:

# Initialize project with Bun
bun init -t default  # Create empty project template
# or
bun init -t express  # Create Express framework template

# Example project structure
my-bun-app/
├── src/
   ├── index.ts      # Application entry point
   ├── routes/       # Route definitions
   ├── controllers/  # Business logic
   └── services/     # Service layer
├── public/           # Static assets
├── package.json      # Project configuration
└── bunfig.toml       # Bun-specific configuration

bunfig.toml Configuration Example:

# Cache configuration
cache_dir = "~/.bun_cache"

# Installation configuration
install_global_bin_dir = "~/.bun_bin"

# Build configuration (optional)
[build]
target = "browser"  # or "node"
minify = true
sourcemap = true

Development Environment Setup

Installing Dependencies:

# Install production dependencies
bun add express typescript

# Install development dependencies
bun add -D @types/node @types/express bun-types

# Install global tools (optional)
bun install -g typescript

Development Scripts Configuration:

// package.json
{
  "scripts": {
    "dev": "bun run --watch src/index.ts",  # Hot reload for development
    "build": "bun build src/index.ts --outfile dist/app.js",  # Production build
    "start": "bun run dist/app.js",  # Production start
    "test": "bun test"  # Run tests
  }
}

Advanced Packaging Configuration

Basic Build Commands

Core Build Parameters:

# Basic build
bun build src/index.ts --outfile dist/app.js

# Production environment optimization
bun build src/index.ts \
  --outfile dist/app.js \
  --target browser \          # Target environment (browser/node)
  --minify \                  # Code minification
  --sourcemap \               # Generate sourcemap
  --watch \                   # Watch for file changes
  --external:@babel/runtime   # Exclude specific dependencies

# Multi-entry build
bun build src/client.ts src/server.ts \
  --outfile dist/[name].js \  # Use input filename as output name
  --target node

Target Environment Differences:

Target EnvironmentUse CaseKey Differences
browserFrontend applicationsIncludes polyfills, excludes Node.js-specific APIs
nodeBackend servicesRetains Node.js-specific APIs, excludes browser polyfills
neutralLibrary developmentNo environment assumptions, requires manual compatibility handling

Code Splitting and Dynamic Imports

Dynamic Import Implementation:

// src/utils/lazyLoad.ts
export async function loadComponent(componentName: string) {
  // Dynamic import of components (generates separate chunk)
  const module = await import(`./components/${componentName}.tsx`)
  return module.default
}

// Usage example
const Button = await loadComponent('Button')

Build Configuration Optimization:

# Enable code splitting (automatically detects dynamic imports)
bun build src/index.ts \
  --outfile dist/app.js \
  --splitting  # Enable code splitting (experimental feature)

# Manually specify chunking strategy
bun build src/index.ts \
  --outfile dist/app.js \
  --chunk-name:components/[name]  # Custom chunk naming

Asset Handling and Optimization

Static Asset Integration:

// src/server.ts
import { serve } from 'bun'
import path from 'path'

serve({
  port: 3000,
  fetch(request) {
    const url = new URL(request.url)

    // Handle static asset requests
    if (url.pathname.startsWith('/assets/')) {
      const filePath = path.join(process.cwd(), 'public', url.pathname)
      return Bun.file(filePath).response
    }

    // Other requests handled by application logic
    return handleAppRequest(request)
  }
})

Asset Optimization Strategies:

# Image compression (requires plugin)
bun build src/index.ts \
  --outfile dist/app.js \
  --asset-plugin=./plugins/image-compressor.js

# Example image compression plugin (proof of concept)
// plugins/image-compressor.js
export default {
  name: 'image-compressor',
  async transform(url, content) {
    if (url.endsWith('.png') || url.endsWith('.jpg')) {
      const compressed = await compressImage(content) // Implement compression logic
      return { content: compressed, contentType: 'image/jpeg' }
    }
    return { content, contentType: 'application/octet-stream' }
  }
}

Production Environment Optimization

Performance Optimization Strategies

Tree Shaking Configuration:

// src/index.ts
// Ensure ESM syntax for exports
export { Button } from './components/Button'  // Referenced exports will be retained
export * from './utils/helpers'             // All exports will be analyzed

// Avoid side effects (mark in package.json)
{
  "sideEffects": false  // or specify files with side effects
}

Build Optimization Parameters:

# Advanced optimization combination
bun build src/index.ts \
  --outfile dist/app.js \
  --minify \                  # Code minification
  --sourcemap \               # Generate sourcemap
  --target browser \          # Target environment
  --splitting \               # Code splitting
  --no-cache \                # Disable cache (force rebuild)
  --define:process.env.NODE_ENV="\"production\""  # Environment variable replacement

Caching and Incremental Builds

Utilizing Cache Mechanisms:

# Leverage Bun's built-in cache
bun build src/index.ts --outfile dist/app.js  # Initial build (full)
bun build src/index.ts --outfile dist/app.js  # Second build (uses cache)

# Clear cache
bun cache clean  # Clear global cache

Incremental Build Strategy:

// src/watch.ts
import { watch } from 'bun'

// Watch for file changes and rebuild
watch('src/**/*.ts', async (event) => {
  if (event.type === 'change') {
    console.log(`File changed: ${event.path}`)
    await bun.build('src/index.ts', {
      outfile: 'dist/app.js',
      watch: false  // Disable built-in watch (use custom logic)
    })
    console.log('Rebuild completed')
  }
})

console.log('Watching for file changes...')

Deployment and Monitoring

Docker Deployment Example:

# Multi-stage build
FROM node:18-alpine as builder

WORKDIR /app
COPY . .
RUN bun install --production
RUN bun build src/index.ts --outfile dist/app.js

FROM node:18-alpine

WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/package.json .
RUN bun install --production

EXPOSE 3000
CMD ["bun", "run", "--bun", "dist/app.js"]

Performance Monitoring Integration:

// src/middleware/perfMiddleware.ts
export function perfMiddleware(ctx: Context, next: Next) {
  const start = performance.now()

  await next()

  const duration = performance.now() - start
  ctx.response.headers.set('X-Response-Time', `${duration.toFixed(2)}ms`)

  // Report performance data (example)
  if (duration > 1000) {  // Requests taking over 1 second
    console.warn(`Slow request: ${ctx.request.url} took ${duration}ms`)
    // Can integrate with Sentry/Datadog or other monitoring tools
  }
}

// Usage in application
import { perfMiddleware } from './middleware/perfMiddleware'
app.use(perfMiddleware)

Advanced Packaging Techniques

Micro-Frontend Support

Module Federation Configuration:

// src/remoteEntry.ts
// Expose modules to other applications
import { Button } from './components/Button'

const exposed = {
  Button
}

// Dynamic export (conforms to Module Federation specification)
self['webpackChunk_micro_frontend'] = self['webpackChunk_micro_frontend'] || []
self['webpackChunk_micro_frontend'].push([
  ['exposed'],
  {
    './Button': () => Promise.resolve(exposed.Button)
  }
])

Packaging Micro-Frontend Application:

# Package as micro-frontend module
bun build src/remoteEntry.ts \
  --outfile dist/remoteEntry.js \
  --target browser \
  --format esm  # Must use ESM format

SSR (Server-Side Rendering) Support

SSR Build Configuration:

// src/server/render.ts
import { renderToString } from 'react-dom/server'
import App from '../client/App'

export async function renderApp(req: Request) {
  const html = renderToString(<App />)
  return `
    <!DOCTYPE html>
    <html>
      <body>
        <div id="root">${html}</div>
        <script src="/client.js"></script>
      </body>
    </html>
  `
}

// Package client code (for browser hydration)
bun build src/client/index.tsx \
  --outfile dist/client.js \
  --target browser \
  --minify

# Package server code
bun build src/server/render.ts \
  --outfile dist/server.js \
  --target node

Library Development Packaging

Best Practices for Library Packaging:

# Package TypeScript library
bun build src/index.ts \
  --outfile dist/library.js \
  --target neutral \          # No environment assumptions
  --format esm,cjs \         # Output both ESM and CommonJS
  --external:react \         # Exclude peerDependencies
  --external:react-dom

# package.json configuration example
{
  "name": "my-library",
  "main": "dist/library.cjs.js",  # CommonJS entry
  "module": "dist/library.esm.js", # ESM entry
  "types": "dist/index.d.ts",     # Type declarations
  "files": ["dist"],              # Published files
  "peerDependencies": {           # Declare peer dependencies
    "react": ">=16.8.0",
    "react-dom": ">=16.8.0"
  }
}

Debugging and Troubleshooting

Build Issue Diagnosis

Debugging the Build Process:

# Enable verbose logging
BUN_DEBUG=1 bun build src/index.ts --outfile dist/app.js

# Generate build analysis report
bun build src/index.ts \
  --outfile dist/app.js \
  --profile  # Generate performance analysis data

# Use Chrome DevTools for analysis
# 1. Generate CPU profile
BUN_CPU_PROFILE=profile.cpuprofile bun build src/index.ts
# 2. Analyze in Chrome via chrome://inspect

# Memory analysis
BUN_HEAP_PROFILE=heap.heapsnapshot bun build src/index.ts

Common Issue Resolution

Typical Problem Solutions:

IssuePossible CauseSolution
Excessive bundle sizeIncorrect Tree ShakingCheck ESM export methods, ensure no side effects
Runtime module missingIncorrect target environmentConfirm --target parameter (browser/node)
Dynamic import failureCode splitting not enabledAdd --splitting parameter
Missing type declarationsType declarations not generatedUse bun types to generate type declarations

Type Declaration Generation:

# Generate TypeScript type declarations
bun types

# Output to specific directory
bun types --outDir ./dist/types
Share your love