mindrally

esbuild-bundler

3
0
# Install this skill:
npx skills add Mindrally/skills --skill "esbuild-bundler"

Install specific skill from multi-skill repository

# Description

Best practices and guidelines for esbuild, the ultra-fast JavaScript and TypeScript bundler and minifier

# SKILL.md


name: esbuild-bundler
description: Best practices and guidelines for esbuild, the ultra-fast JavaScript and TypeScript bundler and minifier


esbuild Bundler

You are an expert in esbuild, the extremely fast JavaScript and TypeScript bundler written in Go. Follow these guidelines when working with esbuild configurations.

Core Principles

  • esbuild is 10-100x faster than traditional bundlers
  • Zero configuration needed for most use cases
  • Native TypeScript and JSX support without additional setup
  • Focus on speed while maintaining code quality
  • Written in Go for native performance

Project Structure

project/
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ index.ts          # Main entry point
β”‚   β”œβ”€β”€ components/       # UI components
β”‚   └── utils/            # Utility functions
β”œβ”€β”€ dist/                 # Build output
β”œβ”€β”€ esbuild.config.mjs    # Build script (optional)
β”œβ”€β”€ tsconfig.json         # TypeScript config
└── package.json

Basic Usage

Command Line

# Basic bundle
esbuild src/index.ts --bundle --outfile=dist/bundle.js

# Production build
esbuild src/index.ts --bundle --minify --sourcemap --outfile=dist/bundle.js

# Watch mode
esbuild src/index.ts --bundle --watch --outfile=dist/bundle.js

JavaScript API

import * as esbuild from 'esbuild';

await esbuild.build({
  entryPoints: ['src/index.ts'],
  bundle: true,
  minify: true,
  sourcemap: true,
  outfile: 'dist/bundle.js'
});

TypeScript Configuration

tsconfig.json Best Practices

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "Bundler",
    "esModuleInterop": true,
    "isolatedModules": true,
    "strict": true,
    "skipLibCheck": true,
    "noEmit": true,
    "verbatimModuleSyntax": true,
    "noUncheckedIndexedAccess": true
  },
  "include": ["src/**/*"]
}

Important TypeScript Settings

  • isolatedModules: true - Required for esbuild compatibility
  • esModuleInterop: true - Better ESM compatibility
  • noEmit: true - Let esbuild handle output, use tsc for type checking only

Build Configuration

Browser Build

await esbuild.build({
  entryPoints: ['src/index.ts'],
  bundle: true,
  minify: true,
  sourcemap: true,
  target: ['chrome90', 'firefox88', 'safari14', 'edge90'],
  outfile: 'dist/bundle.js'
});

Node.js Build

await esbuild.build({
  entryPoints: ['src/index.ts'],
  bundle: true,
  platform: 'node',
  target: 'node18',
  format: 'esm',
  outfile: 'dist/index.js'
});

Multiple Entry Points

await esbuild.build({
  entryPoints: ['src/index.ts', 'src/worker.ts'],
  bundle: true,
  outdir: 'dist',
  splitting: true,
  format: 'esm'
});

Output Formats

ESM (ES Modules)

await esbuild.build({
  format: 'esm',
  // Outputs: import/export syntax
});

CommonJS

await esbuild.build({
  format: 'cjs',
  // Outputs: require/module.exports
});

IIFE (Browser Scripts)

await esbuild.build({
  format: 'iife',
  globalName: 'MyApp',
  // Outputs: self-executing function
});

Loaders

Built-in Loaders

await esbuild.build({
  loader: {
    '.png': 'file',
    '.svg': 'text',
    '.json': 'json',
    '.woff': 'dataurl'
  }
});

Loader Types

  • js - JavaScript
  • ts - TypeScript
  • jsx - JavaScript with JSX
  • tsx - TypeScript with JSX
  • json - JSON data
  • text - Plain text
  • file - Copy file, return path
  • dataurl - Inline as data URL
  • binary - Inline as Uint8Array
  • base64 - Inline as base64
  • copy - Copy file, no reference

External Dependencies

Mark as External

await esbuild.build({
  external: ['react', 'react-dom', 'lodash']
});

External Patterns

await esbuild.build({
  external: ['*.png', '@aws-sdk/*']
});

Code Splitting

await esbuild.build({
  entryPoints: ['src/index.ts'],
  bundle: true,
  splitting: true,
  format: 'esm',
  outdir: 'dist'
});

Note: Code splitting requires format: 'esm' and outdir (not outfile).

Plugins

Plugin Structure

const myPlugin = {
  name: 'my-plugin',
  setup(build) {
    // On resolve - intercept import paths
    build.onResolve({ filter: /^env$/ }, args => ({
      path: args.path,
      namespace: 'env-ns'
    }));

    // On load - provide module contents
    build.onLoad({ filter: /.*/, namespace: 'env-ns' }, () => ({
      contents: JSON.stringify(process.env),
      loader: 'json'
    }));
  }
};

await esbuild.build({
  plugins: [myPlugin]
});

Common Plugins

import esbuildPluginTsc from 'esbuild-plugin-tsc';

await esbuild.build({
  plugins: [
    esbuildPluginTsc({
      force: true
    })
  ]
});

Development Server

Serve API

const ctx = await esbuild.context({
  entryPoints: ['src/index.ts'],
  bundle: true,
  outdir: 'dist'
});

await ctx.serve({
  servedir: 'dist',
  port: 3000
});

Watch Mode

const ctx = await esbuild.context({
  entryPoints: ['src/index.ts'],
  bundle: true,
  outfile: 'dist/bundle.js'
});

await ctx.watch();
console.log('Watching for changes...');

Environment Variables

Define API

await esbuild.build({
  define: {
    'process.env.NODE_ENV': '"production"',
    'process.env.API_URL': JSON.stringify(process.env.API_URL)
  }
});

Optimization

Minification

await esbuild.build({
  minify: true,
  // Or granular control:
  minifyWhitespace: true,
  minifyIdentifiers: true,
  minifySyntax: true
});

Tree Shaking

await esbuild.build({
  treeShaking: true,
  // Mark files as side-effect free
  ignoreAnnotations: false
});

Drop Console and Debugger

await esbuild.build({
  drop: ['console', 'debugger']
});

Type Checking

esbuild does not perform type checking. Run TypeScript separately:

{
  "scripts": {
    "typecheck": "tsc --noEmit",
    "build": "npm run typecheck && node esbuild.config.mjs",
    "dev": "concurrently \"tsc --noEmit --watch\" \"node esbuild.config.mjs --watch\""
  }
}

Build Script Example

// esbuild.config.mjs
import * as esbuild from 'esbuild';

const isProduction = process.env.NODE_ENV === 'production';
const isWatch = process.argv.includes('--watch');

const config = {
  entryPoints: ['src/index.ts'],
  bundle: true,
  platform: 'browser',
  target: ['es2020'],
  format: 'esm',
  outdir: 'dist',
  sourcemap: !isProduction,
  minify: isProduction,
  splitting: true,
  define: {
    'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development')
  }
};

if (isWatch) {
  const ctx = await esbuild.context(config);
  await ctx.watch();
  console.log('Watching for changes...');
} else {
  await esbuild.build(config);
  console.log('Build complete!');
}

Best Practices

Do

  • Use isolatedModules: true in TypeScript config
  • Run type checking separately with tsc --noEmit
  • Use the context API for watch mode
  • Leverage native TypeScript and JSX support
  • Use external for peer dependencies in libraries

Avoid

  • Relying on esbuild for type checking
  • Using features that require type information (decorators with metadata)
  • Ignoring the isolatedModules requirement
  • Over-configuring when defaults work

Common Patterns

Library Build

await esbuild.build({
  entryPoints: ['src/index.ts'],
  bundle: true,
  external: ['react', 'react-dom'],
  format: 'esm',
  outfile: 'dist/index.js',
  sourcemap: true
});

Application Build

await esbuild.build({
  entryPoints: ['src/index.tsx'],
  bundle: true,
  splitting: true,
  format: 'esm',
  outdir: 'dist',
  minify: true,
  sourcemap: true,
  target: ['chrome90', 'firefox88', 'safari14']
});

Performance Tips

  • esbuild parallelizes work automatically
  • File system caching is built-in
  • Use incremental builds in development
  • Avoid unnecessary plugins that slow builds

# Supported AI Coding Agents

This skill is compatible with the SKILL.md standard and works with all major AI coding agents:

Learn more about the SKILL.md standard and how to use these skills with your preferred AI coding agent.