JavaScript Tools

JavaScript Build Tools: Webpack, Vite, Rollup Complete Guide

Master modern JavaScript build tools. Learn Webpack, Vite, Rollup, esbuild configuration, optimization, and build pipeline best practices.

By JavaScript Document Team
build-toolswebpackviterollupbundlingoptimization

Modern JavaScript development relies heavily on build tools to bundle, optimize, and transform code. This comprehensive guide covers popular build tools including Webpack, Vite, Rollup, and esbuild with practical configurations and optimization techniques.

Why Build Tools Matter

Build tools serve several critical purposes in modern JavaScript development:

// Before build tools - manual script inclusion
<!DOCTYPE html>
<html>
<head>
  <script src="lodash.js"></script>
  <script src="jquery.js"></script>
  <script src="utils.js"></script>
  <script src="components.js"></script>
  <script src="app.js"></script>
</head>
</html>

// With build tools - single optimized bundle
<!DOCTYPE html>
<html>
<head>
  <script src="bundle.min.js"></script>
</head>
</html>

// Modern module syntax
import { debounce } from 'lodash';
import $ from 'jquery';
import { fetchUser } from './utils';
import Header from './components/Header';

// Build tools handle:
// - Module bundling
// - Code transformation (TypeScript, JSX)
// - Optimization (minification, tree shaking)
// - Asset processing (images, CSS)
// - Development server
// - Hot module replacement

Webpack

Basic Webpack Configuration

// webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');

module.exports = (env, argv) => {
  const isProduction = argv.mode === 'production';

  return {
    entry: {
      main: './src/index.js',
      vendor: ['react', 'react-dom']
    },

    output: {
      path: path.resolve(__dirname, 'dist'),
      filename: isProduction ? '[name].[contenthash].js' : '[name].js',
      chunkFilename: isProduction ? '[name].[contenthash].chunk.js' : '[name].chunk.js',
      clean: true,
      publicPath: '/'
    },

    module: {
      rules: [
        {
          test: /\.(js|jsx)$/,
          exclude: /node_modules/,
          use: {
            loader: 'babel-loader',
            options: {
              presets: [
                ['@babel/preset-env', {
                  useBuiltIns: 'usage',
                  corejs: 3
                }],
                '@babel/preset-react'
              ],
              plugins: [
                '@babel/plugin-proposal-class-properties',
                isProduction && 'babel-plugin-transform-react-remove-prop-types'
              ].filter(Boolean)
            }
          }
        },
        {
          test: /\.css$/,
          use: [
            isProduction ? MiniCssExtractPlugin.loader : 'style-loader',
            {
              loader: 'css-loader',
              options: {
                modules: {
                  localIdentName: isProduction ? '[hash:base64]' : '[name]__[local]__[hash:base64:5]'
                }
              }
            },
            'postcss-loader'
          ]
        },
        {
          test: /\.scss$/,
          use: [
            isProduction ? MiniCssExtractPlugin.loader : 'style-loader',
            'css-loader',
            'postcss-loader',
            'sass-loader'
          ]
        },
        {
          test: /\.(png|jpe?g|gif|svg)$/,
          type: 'asset',
          parser: {
            dataUrlCondition: {
              maxSize: 8 * 1024 // 8kb
            }
          },
          generator: {
            filename: 'images/[name].[hash][ext]'
          }
        },
        {
          test: /\.(woff|woff2|eot|ttf|otf)$/,
          type: 'asset/resource',
          generator: {
            filename: 'fonts/[name].[hash][ext]'
          }
        }
      ]
    },

    plugins: [
      new HtmlWebpackPlugin({
        template: './public/index.html',
        minify: isProduction ? {
          removeComments: true,
          collapseWhitespace: true,
          removeRedundantAttributes: true,
          removeScriptTypeAttributes: true,
          removeStyleLinkTypeAttributes: true,
          minifyJS: true,
          minifyCSS: true
        } : false
      }),

      isProduction && new MiniCssExtractPlugin({
        filename: '[name].[contenthash].css',
        chunkFilename: '[name].[contenthash].chunk.css'
      })
    ].filter(Boolean),

    optimization: {
      minimizer: isProduction ? [
        new TerserPlugin({
          terserOptions: {
            compress: {
              drop_console: true
            }
          }
        }),
        new OptimizeCSSAssetsPlugin()
      ] : [],

      splitChunks: {
        chunks: 'all',
        cacheGroups: {
          vendor: {
            test: /[\\/]node_modules[\\/]/,
            name: 'vendors',
            priority: 10,
            enforce: true
          },
          common: {
            minChunks: 2,
            priority: 5,
            reuseExistingChunk: true
          }
        }
      },

      runtimeChunk: {
        name: 'runtime'
      }
    },

    resolve: {
      extensions: ['.js', '.jsx', '.ts', '.tsx'],
      alias: {
        '@': path.resolve(__dirname, 'src'),
        '@components': path.resolve(__dirname, 'src/components'),
        '@utils': path.resolve(__dirname, 'src/utils'),
        '@assets': path.resolve(__dirname, 'src/assets')
      }
    },

    devServer: {
      contentBase: path.join(__dirname, 'dist'),
      historyApiFallback: true,
      hot: true,
      port: 3000,
      open: true,
      overlay: {
        warnings: false,
        errors: true
      }
    },

    devtool: isProduction ? 'source-map' : 'eval-source-map'
  };
};

// package.json scripts
{
  "scripts": {
    "dev": "webpack serve --mode development",
    "build": "webpack --mode production",
    "analyze": "webpack-bundle-analyzer dist/static/js/*.js"
  }
}

Advanced Webpack Features

// webpack.config.js - Advanced configuration
const webpack = require('webpack');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
const CompressionPlugin = require('compression-webpack-plugin');
const WorkboxPlugin = require('workbox-webpack-plugin');

// Custom plugin for build timing
class BuildTimePlugin {
  apply(compiler) {
    compiler.hooks.run.tap('BuildTimePlugin', () => {
      console.log('Build started at:', new Date().toLocaleTimeString());
    });

    compiler.hooks.done.tap('BuildTimePlugin', (stats) => {
      console.log('Build completed at:', new Date().toLocaleTimeString());
      console.log('Build duration:', stats.endTime - stats.startTime, 'ms');
    });
  }
}

module.exports = {
  // ... previous config

  plugins: [
    // Previous plugins...

    // Environment variables
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
      'process.env.API_URL': JSON.stringify(
        process.env.API_URL || 'https://api.example.com'
      ),
      __DEV__: process.env.NODE_ENV === 'development',
    }),

    // Bundle analysis
    process.env.ANALYZE &&
      new BundleAnalyzerPlugin({
        analyzerMode: 'server',
        openAnalyzer: true,
      }),

    // Compression
    new CompressionPlugin({
      algorithm: 'gzip',
      test: /\.(js|css|html|svg)$/,
      threshold: 8192,
      minRatio: 0.8,
    }),

    // Service Worker
    new WorkboxPlugin.GenerateSW({
      clientsClaim: true,
      skipWaiting: true,
      runtimeCaching: [
        {
          urlPattern: /^https:\/\/api\.example\.com/,
          handler: 'NetworkFirst',
          options: {
            cacheName: 'api-cache',
            expiration: {
              maxEntries: 50,
              maxAgeSeconds: 300,
            },
          },
        },
      ],
    }),

    // Custom plugin
    new BuildTimePlugin(),
  ].filter(Boolean),

  // Performance budgets
  performance: {
    maxAssetSize: 250000,
    maxEntrypointSize: 250000,
    hints: process.env.NODE_ENV === 'production' ? 'warning' : false,
  },

  // Module federation (micro-frontends)
  plugins: [
    new webpack.container.ModuleFederationPlugin({
      name: 'shell',
      remotes: {
        mfe1: 'mfe1@http://localhost:3001/remoteEntry.js',
        mfe2: 'mfe2@http://localhost:3002/remoteEntry.js',
      },
      shared: {
        react: { singleton: true },
        'react-dom': { singleton: true },
      },
    }),
  ],
};

// webpack.dev.js - Development specific config
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');

module.exports = merge(common, {
  mode: 'development',
  devtool: 'eval-source-map',

  devServer: {
    hot: true,
    port: 3000,
    historyApiFallback: true,
    proxy: {
      '/api': {
        target: 'http://localhost:8080',
        changeOrigin: true,
        secure: false,
      },
    },
  },

  optimization: {
    removeAvailableModules: false,
    removeEmptyChunks: false,
    splitChunks: false,
  },
});

// webpack.prod.js - Production specific config
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');

module.exports = merge(common, {
  mode: 'production',
  devtool: 'source-map',

  optimization: {
    minimize: true,
    sideEffects: false,
    concatenateModules: true,

    splitChunks: {
      chunks: 'all',
      minSize: 20000,
      maxSize: 244000,
      cacheGroups: {
        default: {
          minChunks: 2,
          priority: -20,
          reuseExistingChunk: true,
        },
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          priority: -10,
          chunks: 'initial',
        },
      },
    },
  },
});

Vite

Vite Configuration

// vite.config.js
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { resolve } from 'path';
import { visualizer } from 'rollup-plugin-visualizer';

export default defineConfig(({ command, mode }) => {
  const isProduction = mode === 'production';

  return {
    plugins: [
      react(),

      // Bundle analyzer
      isProduction && visualizer({
        filename: 'dist/stats.html',
        open: true
      })
    ].filter(Boolean),

    // Development server
    server: {
      port: 3000,
      open: true,
      cors: true,
      proxy: {
        '/api': {
          target: 'http://localhost:8080',
          changeOrigin: true,
          secure: false
        }
      }
    },

    // Build configuration
    build: {
      outDir: 'dist',
      sourcemap: true,
      minify: 'terser',

      terserOptions: {
        compress: {
          drop_console: isProduction,
          drop_debugger: isProduction
        }
      },

      rollupOptions: {
        output: {
          manualChunks: {
            vendor: ['react', 'react-dom'],
            utils: ['lodash', 'date-fns']
          }
        }
      },

      chunkSizeWarningLimit: 1000
    },

    // Path resolution
    resolve: {
      alias: {
        '@': resolve(__dirname, 'src'),
        '@components': resolve(__dirname, 'src/components'),
        '@utils': resolve(__dirname, 'src/utils'),
        '@assets': resolve(__dirname, 'src/assets')
      }
    },

    // CSS configuration
    css: {
      modules: {
        localsConvention: 'camelCase'
      },
      preprocessorOptions: {
        scss: {
          additionalData: `@import "@/styles/variables.scss";`
        }
      }
    },

    // Environment variables
    define: {
      __APP_VERSION__: JSON.stringify(process.env.npm_package_version),
      __API_URL__: JSON.stringify(process.env.VITE_API_URL || 'https://api.example.com')
    },

    // Optimization
    optimizeDeps: {
      include: ['react', 'react-dom'],
      exclude: ['some-large-dependency']
    }
  };
});

// Custom Vite plugin
function customPlugin() {
  return {
    name: 'custom-plugin',

    buildStart() {
      console.log('Build started with Vite');
    },

    generateBundle(options, bundle) {
      // Custom bundle manipulation
      console.log('Generated bundle with', Object.keys(bundle).length, 'chunks');
    },

    writeBundle() {
      console.log('Bundle written to disk');
    }
  };
}

// Environment-specific configs
// vite.config.dev.js
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [react()],

  server: {
    hmr: {
      overlay: false
    }
  },

  build: {
    sourcemap: true,
    minify: false
  }
});

// vite.config.prod.js
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { resolve } from 'path';

export default defineConfig({
  plugins: [react()],

  build: {
    minify: 'terser',
    rollupOptions: {
      input: {
        main: resolve(__dirname, 'index.html'),
        admin: resolve(__dirname, 'admin.html')
      }
    }
  }
});

Vite Plugin Development

// plugins/vite-plugin-custom.js
import { createFilter } from '@rollup/pluginutils';
import MagicString from 'magic-string';

export function customTransformPlugin(options = {}) {
  const filter = createFilter(options.include, options.exclude);

  return {
    name: 'custom-transform',

    transform(code, id) {
      if (!filter(id)) return null;

      // Custom code transformation
      const magicString = new MagicString(code);

      // Example: Replace console.log with custom logger
      if (options.replaceConsole) {
        magicString.replace(/console\.log/g, 'customLogger');
      }

      // Example: Add development helpers
      if (options.addHelpers && process.env.NODE_ENV === 'development') {
        magicString.prepend('// Development helpers injected\n');
      }

      return {
        code: magicString.toString(),
        map: magicString.generateMap({ hires: true }),
      };
    },

    generateBundle(options, bundle) {
      // Post-process bundle
      Object.keys(bundle).forEach((fileName) => {
        const chunk = bundle[fileName];
        if (chunk.type === 'chunk') {
          console.log(
            `Generated chunk: ${fileName} (${chunk.code.length} bytes)`
          );
        }
      });
    },
  };
}

// Usage in vite.config.js
import { customTransformPlugin } from './plugins/vite-plugin-custom.js';

export default defineConfig({
  plugins: [
    react(),
    customTransformPlugin({
      include: ['src/**/*.js', 'src/**/*.jsx'],
      replaceConsole: true,
      addHelpers: true,
    }),
  ],
});

Rollup

Rollup Configuration

// rollup.config.js
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import babel from '@rollup/plugin-babel';
import terser from '@rollup/plugin-terser';
import postcss from 'rollup-plugin-postcss';
import { visualizer } from 'rollup-plugin-visualizer';
import copy from 'rollup-plugin-copy';

const isProduction = process.env.NODE_ENV === 'production';

export default [
  // Main application bundle
  {
    input: 'src/index.js',

    output: [
      {
        file: 'dist/bundle.cjs.js',
        format: 'cjs',
        sourcemap: true
      },
      {
        file: 'dist/bundle.esm.js',
        format: 'esm',
        sourcemap: true
      },
      {
        file: 'dist/bundle.umd.js',
        format: 'umd',
        name: 'MyLibrary',
        sourcemap: true,
        globals: {
          react: 'React',
          'react-dom': 'ReactDOM'
        }
      }
    ],

    plugins: [
      resolve({
        browser: true,
        preferBuiltins: false
      }),

      commonjs(),

      babel({
        babelHelpers: 'bundled',
        exclude: 'node_modules/**',
        presets: [
          ['@babel/preset-env', {
            modules: false,
            targets: {
              browsers: ['> 1%', 'last 2 versions']
            }
          }],
          '@babel/preset-react'
        ]
      }),

      postcss({
        extract: 'styles.css',
        minimize: isProduction,
        sourceMap: true
      }),

      isProduction && terser({
        compress: {
          drop_console: true
        }
      }),

      copy({
        targets: [
          { src: 'public/*', dest: 'dist' }
        ]
      }),

      visualizer({
        filename: 'dist/bundle-analysis.html',
        open: true
      })
    ].filter(Boolean),

    external: ['react', 'react-dom'],

    watch: {
      include: 'src/**',
      clearScreen: false
    }
  },

  // Library bundle
  {
    input: 'src/lib/index.js',

    output: {
      file: 'dist/lib.js',
      format: 'esm',
      sourcemap: true
    },

    plugins: [
      resolve(),
      babel({
        babelHelpers: 'bundled',
        exclude: 'node_modules/**'
      }),
      isProduction && terser()
    ].filter(Boolean),

    external: id => !id.startsWith('.') && !id.startsWith('/')
  }
];

// rollup.config.dev.js - Development configuration
import serve from 'rollup-plugin-serve';
import livereload from 'rollup-plugin-livereload';

export default {
  input: 'src/index.js',

  output: {
    file: 'dist/bundle.js',
    format: 'iife',
    sourcemap: true
  },

  plugins: [
    resolve({ browser: true }),
    commonjs(),
    babel({ babelHelpers: 'bundled' }),

    serve({
      contentBase: 'dist',
      port: 3000,
      open: true
    }),

    livereload('dist')
  ]
};

Custom Rollup Plugins

// plugins/rollup-plugin-environment.js
export function environmentPlugin(options = {}) {
  return {
    name: 'environment',

    buildStart() {
      console.log(
        `Building for ${process.env.NODE_ENV || 'development'} environment`
      );
    },

    transform(code, id) {
      // Replace environment variables
      let transformedCode = code;

      Object.keys(process.env).forEach((key) => {
        if (key.startsWith('APP_')) {
          transformedCode = transformedCode.replace(
            new RegExp(`process\\.env\\.${key}`, 'g'),
            JSON.stringify(process.env[key])
          );
        }
      });

      return transformedCode !== code ? { code: transformedCode } : null;
    },
  };
}

// plugins/rollup-plugin-asset-size.js
export function assetSizePlugin(options = {}) {
  const { threshold = 100000 } = options; // 100KB default

  return {
    name: 'asset-size',

    generateBundle(outputOptions, bundle) {
      Object.keys(bundle).forEach((fileName) => {
        const asset = bundle[fileName];

        if (asset.type === 'chunk') {
          const size = Buffer.byteLength(asset.code, 'utf8');

          if (size > threshold) {
            this.warn(
              `Large chunk detected: ${fileName} (${(size / 1000).toFixed(1)}KB)`
            );
          }

          console.log(`${fileName}: ${(size / 1000).toFixed(1)}KB`);
        }
      });
    },
  };
}

// Usage
import { environmentPlugin, assetSizePlugin } from './plugins';

export default {
  // ... config
  plugins: [environmentPlugin(), assetSizePlugin({ threshold: 50000 })],
};

esbuild

esbuild Configuration

// build.js - esbuild script
const esbuild = require('esbuild');
const { sassPlugin } = require('esbuild-sass-plugin');
const { copy } = require('esbuild-plugin-copy');

const isProduction = process.env.NODE_ENV === 'production';

// Basic build
async function build() {
  try {
    await esbuild.build({
      entryPoints: ['src/index.js'],
      bundle: true,
      outfile: 'dist/bundle.js',
      minify: isProduction,
      sourcemap: true,
      format: 'esm',
      target: ['es2020'],

      plugins: [
        sassPlugin(),
        copy({
          assets: {
            from: ['./public/*'],
            to: ['./dist']
          }
        })
      ],

      define: {
        'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
        'process.env.API_URL': JSON.stringify(process.env.API_URL || 'https://api.example.com')
      },

      external: ['react', 'react-dom'],

      loader: {
        '.png': 'file',
        '.jpg': 'file',
        '.svg': 'text'
      }
    });

    console.log('Build completed successfully');
  } catch (error) {
    console.error('Build failed:', error);
    process.exit(1);
  }
}

// Development server
async function serve() {
  const ctx = await esbuild.context({
    entryPoints: ['src/index.js'],
    bundle: true,
    outdir: 'dist',
    sourcemap: true,
    format: 'esm',

    plugins: [sassPlugin()]
  });

  await ctx.watch();

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

  console.log(`Server running at http://${host}:${port}`);
}

// Advanced esbuild configuration
const buildConfig = {
  entryPoints: {
    main: 'src/index.js',
    admin: 'src/admin.js'
  },

  bundle: true,
  outdir: 'dist',

  splitting: true,
  format: 'esm',

  minify: isProduction,
  keepNames: !isProduction,

  sourcemap: true,

  metafile: true,

  plugins: [
    {
      name: 'build-timer',
      setup(build) {
        let startTime;

        build.onStart(() => {
          startTime = Date.now();
          console.log('Build started...');
        });

        build.onEnd(result => {
          const duration = Date.now() - startTime;
          console.log(`Build completed in ${duration}ms`);

          if (result.metafile) {
            console.log('Bundle analysis:', esbuild.analyzeMetafileSync(result.metafile));
          }
        });
      }
    }
  ],

  loader: {
    '.js': 'jsx',
    '.ts': 'tsx'
  },

  alias: {
    '@': './src',
    '@components': './src/components'
  }
};

if (process.argv.includes('--serve')) {
  serve();
} else {
  build();
}

// package.json scripts
{
  "scripts": {
    "dev": "node build.js --serve",
    "build": "NODE_ENV=production node build.js",
    "analyze": "esbuild-visualizer --metadata=meta.json --open"
  }
}

Build Optimization Techniques

// webpack-optimization.js
class BuildOptimizer {
  // Bundle splitting strategies
  static getSplitChunksConfig() {
    return {
      chunks: 'all',
      minSize: 20000,
      maxSize: 244000,

      cacheGroups: {
        // Vendor libraries
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          priority: 10,
          enforce: true,
        },

        // Common modules
        common: {
          minChunks: 2,
          priority: 5,
          reuseExistingChunk: true,
        },

        // React ecosystem
        react: {
          test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/,
          name: 'react',
          priority: 20,
          enforce: true,
        },

        // UI libraries
        ui: {
          test: /[\\/]node_modules[\\/](@mui|antd|bootstrap)[\\/]/,
          name: 'ui',
          priority: 15,
          enforce: true,
        },
      },
    };
  }

  // Tree shaking configuration
  static getTreeShakingConfig() {
    return {
      optimization: {
        usedExports: true,
        sideEffects: false,

        // Mark specific packages as side-effect free
        sideEffects: ['*.css', '*.scss', './src/polyfills.js'],
      },

      resolve: {
        // Enable tree shaking for these modules
        mainFields: ['es2015', 'module', 'main'],
      },
    };
  }

  // Lazy loading implementation
  static createLazyComponent(importFn, fallback = null) {
    return React.lazy(() => {
      return importFn().catch((error) => {
        console.error('Lazy loading failed:', error);

        // Return error boundary component
        return {
          default: () =>
            React.createElement('div', null, 'Failed to load component'),
        };
      });
    });
  }

  // Resource hints generation
  static generateResourceHints(chunks) {
    const hints = [];

    chunks.forEach((chunk) => {
      if (chunk.isInitial) {
        hints.push(`<link rel="preload" href="${chunk.files[0]}" as="script">`);
      } else {
        hints.push(`<link rel="prefetch" href="${chunk.files[0]}">`);
      }
    });

    return hints.join('\n');
  }

  // Performance monitoring
  static monitorBuildPerformance(stats) {
    const assets = stats.compilation.assets;
    const chunks = stats.compilation.chunks;

    console.log('=== Build Performance Report ===');

    // Asset sizes
    Object.keys(assets).forEach((name) => {
      const size = assets[name].size();
      if (size > 250000) {
        // 250KB
        console.warn(
          `Large asset detected: ${name} (${(size / 1000).toFixed(1)}KB)`
        );
      }
    });

    // Chunk analysis
    chunks.forEach((chunk) => {
      const modules = chunk.getModules();
      console.log(`Chunk ${chunk.name}: ${modules.length} modules`);
    });

    // Build timing
    console.log(`Build time: ${stats.endTime - stats.startTime}ms`);
  }
}

// Dynamic imports and code splitting
class ComponentLoader {
  static cache = new Map();

  static async loadComponent(name) {
    if (this.cache.has(name)) {
      return this.cache.get(name);
    }

    try {
      let componentModule;

      switch (name) {
        case 'Dashboard':
          componentModule = await import('./components/Dashboard');
          break;
        case 'Settings':
          componentModule = await import('./components/Settings');
          break;
        case 'Reports':
          componentModule = await import('./components/Reports');
          break;
        default:
          throw new Error(`Unknown component: ${name}`);
      }

      const Component = componentModule.default;
      this.cache.set(name, Component);

      return Component;
    } catch (error) {
      console.error(`Failed to load component ${name}:`, error);
      return null;
    }
  }

  static preloadComponents(names) {
    names.forEach((name) => {
      this.loadComponent(name).catch(() => {
        // Silently fail for preloading
      });
    });
  }
}

// Progressive loading strategy
class ProgressiveLoader {
  constructor() {
    this.loadQueue = [];
    this.loading = false;
  }

  async loadInBatches(modules, batchSize = 3) {
    const batches = this.createBatches(modules, batchSize);

    for (const batch of batches) {
      await Promise.all(batch.map((module) => this.loadModule(module)));

      // Small delay between batches to prevent overwhelming
      await new Promise((resolve) => setTimeout(resolve, 100));
    }
  }

  createBatches(array, size) {
    const batches = [];
    for (let i = 0; i < array.length; i += size) {
      batches.push(array.slice(i, i + size));
    }
    return batches;
  }

  async loadModule(modulePath) {
    try {
      const module = await import(modulePath);
      console.log(`Loaded module: ${modulePath}`);
      return module;
    } catch (error) {
      console.error(`Failed to load module ${modulePath}:`, error);
      return null;
    }
  }
}

Build Pipeline Automation

// build-pipeline.js
const fs = require('fs').promises;
const path = require('path');
const { execSync } = require('child_process');

class BuildPipeline {
  constructor(config) {
    this.config = {
      buildDir: 'dist',
      sourceDir: 'src',
      ...config,
    };
  }

  async runPipeline() {
    console.log('Starting build pipeline...');

    try {
      await this.preBuild();
      await this.build();
      await this.postBuild();
      await this.validate();

      console.log('Build pipeline completed successfully!');
    } catch (error) {
      console.error('Build pipeline failed:', error);
      process.exit(1);
    }
  }

  async preBuild() {
    console.log('Pre-build tasks...');

    // Clean build directory
    await this.cleanBuildDir();

    // Check dependencies
    await this.checkDependencies();

    // Run linting
    await this.runLinting();

    // Run tests
    await this.runTests();
  }

  async build() {
    console.log('Building application...');

    const buildCommand =
      process.env.NODE_ENV === 'production'
        ? 'npm run build:prod'
        : 'npm run build';

    execSync(buildCommand, { stdio: 'inherit' });
  }

  async postBuild() {
    console.log('Post-build tasks...');

    // Generate build manifest
    await this.generateBuildManifest();

    // Optimize assets
    await this.optimizeAssets();

    // Generate service worker
    await this.generateServiceWorker();

    // Copy additional files
    await this.copyStaticFiles();
  }

  async validate() {
    console.log('Validating build...');

    // Check bundle sizes
    await this.checkBundleSizes();

    // Validate HTML
    await this.validateHTML();

    // Check for missing files
    await this.checkRequiredFiles();
  }

  async cleanBuildDir() {
    try {
      await fs.rmdir(this.config.buildDir, { recursive: true });
      await fs.mkdir(this.config.buildDir, { recursive: true });
      console.log('Build directory cleaned');
    } catch (error) {
      // Directory might not exist, that's okay
    }
  }

  async checkDependencies() {
    try {
      execSync('npm audit --audit-level moderate', { stdio: 'pipe' });
      console.log('Dependencies check passed');
    } catch (error) {
      console.warn('Dependency vulnerabilities detected');
    }
  }

  async runLinting() {
    try {
      execSync('npm run lint', { stdio: 'pipe' });
      console.log('Linting passed');
    } catch (error) {
      throw new Error('Linting failed');
    }
  }

  async runTests() {
    try {
      execSync('npm test -- --coverage --watchAll=false', { stdio: 'pipe' });
      console.log('Tests passed');
    } catch (error) {
      throw new Error('Tests failed');
    }
  }

  async generateBuildManifest() {
    const buildInfo = {
      buildTime: new Date().toISOString(),
      version: process.env.npm_package_version || '1.0.0',
      environment: process.env.NODE_ENV || 'development',
      commit: this.getGitCommit(),
      branch: this.getGitBranch(),
    };

    await fs.writeFile(
      path.join(this.config.buildDir, 'build-manifest.json'),
      JSON.stringify(buildInfo, null, 2)
    );

    console.log('Build manifest generated');
  }

  async optimizeAssets() {
    // Compress images
    try {
      execSync('npm run optimize:images', { stdio: 'pipe' });
      console.log('Images optimized');
    } catch (error) {
      console.warn('Image optimization failed');
    }
  }

  async generateServiceWorker() {
    if (this.config.pwa) {
      try {
        execSync('npm run build:sw', { stdio: 'pipe' });
        console.log('Service worker generated');
      } catch (error) {
        console.warn('Service worker generation failed');
      }
    }
  }

  async copyStaticFiles() {
    const staticFiles = ['robots.txt', 'sitemap.xml', '.htaccess'];

    for (const file of staticFiles) {
      try {
        await fs.copyFile(
          path.join('public', file),
          path.join(this.config.buildDir, file)
        );
      } catch (error) {
        // File might not exist, that's okay
      }
    }

    console.log('Static files copied');
  }

  async checkBundleSizes() {
    const bundleFiles = await fs.readdir(this.config.buildDir);
    const jsFiles = bundleFiles.filter((file) => file.endsWith('.js'));

    for (const file of jsFiles) {
      const filePath = path.join(this.config.buildDir, file);
      const stats = await fs.stat(filePath);
      const sizeKB = stats.size / 1024;

      if (sizeKB > 250) {
        console.warn(`Large bundle detected: ${file} (${sizeKB.toFixed(1)}KB)`);
      }
    }

    console.log('Bundle sizes checked');
  }

  async validateHTML() {
    try {
      const htmlFiles = await fs.readdir(this.config.buildDir);
      const htmlFile = htmlFiles.find((file) => file.endsWith('.html'));

      if (htmlFile) {
        const content = await fs.readFile(
          path.join(this.config.buildDir, htmlFile),
          'utf8'
        );

        // Basic HTML validation
        if (!content.includes('<!DOCTYPE html>')) {
          throw new Error('Missing DOCTYPE declaration');
        }

        console.log('HTML validation passed');
      }
    } catch (error) {
      console.warn('HTML validation failed:', error.message);
    }
  }

  async checkRequiredFiles() {
    const requiredFiles = ['index.html'];

    for (const file of requiredFiles) {
      try {
        await fs.access(path.join(this.config.buildDir, file));
      } catch (error) {
        throw new Error(`Required file missing: ${file}`);
      }
    }

    console.log('Required files check passed');
  }

  getGitCommit() {
    try {
      return execSync('git rev-parse HEAD', { encoding: 'utf8' }).trim();
    } catch {
      return 'unknown';
    }
  }

  getGitBranch() {
    try {
      return execSync('git rev-parse --abbrev-ref HEAD', {
        encoding: 'utf8',
      }).trim();
    } catch {
      return 'unknown';
    }
  }
}

// Usage
const pipeline = new BuildPipeline({
  buildDir: 'dist',
  pwa: true,
});

pipeline.runPipeline();

Conclusion

Modern JavaScript build tools are essential for creating optimized, production-ready applications. Each tool has its strengths: Webpack for complex configurations and extensive plugin ecosystem, Vite for fast development and modern defaults, Rollup for libraries and tree-shaking, and esbuild for speed. Understanding how to configure and optimize these tools enables you to create efficient build pipelines that improve development experience and application performance. Choose the right tool based on your project requirements, team expertise, and performance needs.