Courses / JavaScript / Module Bundlers
    Back to Course

    ๐Ÿ’ก Hands-On Practice

    Bundler configurations require a local development environment. To practice:

    • Install Node.js on your computer
    • Create a new project folder and run npm init -y
    • Try npm create vite@latest for the easiest start

    Module Bundlers: Webpack, Parcel & Vite

    Master the tools that power modern JavaScript development. Learn bundling, code splitting, tree shaking, HMR, and production optimization across Webpack, Vite, and Parcel.

    What You'll Learn

    • Webpack configuration
    • Vite for fast development
    • Code splitting & lazy loading
    • Tree shaking dead code
    • Hot Module Replacement
    • Production optimization

    Why Module Bundlers?

    Modern apps use ES modules, TypeScript, JSX, SCSS, and hundreds of dependencies. Browsers can't handle all of this natively. Bundlers transform your development code into optimized, browser-ready production builds.

    What Bundlers Do

    • โœ“ Combine modules into bundles
    • โœ“ Transform TS/JSX โ†’ JavaScript
    • โœ“ Minify and compress code
    • โœ“ Remove unused code (tree shaking)
    • โœ“ Handle images, fonts, CSS
    • โœ“ Enable hot module replacement

    The Big Three

    • Webpack โ€” Most powerful & configurable
    • Vite โ€” Fastest dev experience (modern default)
    • Parcel โ€” Zero configuration needed

    Webpack Configuration

    Webpack is the most flexible bundler with a massive plugin ecosystem. It requires configuration but gives you complete control over every aspect of your build.

    Webpack Configuration

    Explore basic Webpack configuration patterns

    Try it Yourself ยป
    JavaScript
    // webpack.config.js - Basic Webpack Configuration
    const path = require("path");
    const HtmlWebpackPlugin = require("html-webpack-plugin");
    const MiniCssExtractPlugin = require("mini-css-extract-plugin");
    
    module.exports = {
      // Entry point - where bundler starts
      entry: "./src/index.js",
    
      // Output configuration
      output: {
        filename: "[name].[contenthash].js",
        path: path.resolve(__dirname, "dist"),
        clean: true // Clean /dist folder before each build
      },
    
      // Development or prod
    ...

    ๐Ÿ’ก Key Concepts: Entry points define where bundling starts. Loaders transform files (babel-loader, css-loader). Plugins extend functionality (HtmlWebpackPlugin, MiniCssExtractPlugin).

    Webpack Production Optimization

    Production builds require aggressive optimization: minification, code splitting, tree shaking, and vendor chunking for optimal caching.

    Webpack Production Optimization

    Advanced production optimization patterns

    Try it Yourself ยป
    JavaScript
    // webpack.config.js - Production Optimization
    const TerserPlugin = require("terser-webpack-plugin");
    const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
    const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer");
    
    module.exports = {
      mode: "production",
      
      // Multiple entry points for large apps
      entry: {
        main: "./src/main.js",
        admin: "./src/admin.js",
        analytics: "./src/analytics.js"
      },
    
      output: {
        filename: "[name].[contenthash].js",
        path: __
    ...

    Vite Configuration

    Vite uses native ES modules during development for instant server start and updates. It's the fastest development experience available and the modern default choice.

    Vite Configuration

    Modern Vite bundler configuration

    Try it Yourself ยป
    JavaScript
    // vite.config.js - Vite Configuration
    import { defineConfig } from "vite";
    import react from "@vitejs/plugin-react";
    import { resolve } from "path";
    
    export default defineConfig({
      // Plugins
      plugins: [react()],
    
      // Path aliases
      resolve: {
        alias: {
          "@": resolve(__dirname, "src"),
          "@components": resolve(__dirname, "src/components"),
          "@utils": resolve(__dirname, "src/utils")
        }
      },
    
      // Development server
      server: {
        port: 3000,
        open: true,
        // Proxy A
    ...

    โœ… Why Vite is Fast: During development, Vite serves raw ES modules to the browser โ€” no bundling required! For production, it uses Rollup with ESBuild for lightning-fast builds.

    Writing Vite Plugins

    Vite plugins follow Rollup's plugin interface with additional Vite-specific hooks. You can transform code, inject scripts, and customize the build process.

    Writing Vite Plugins

    Custom Vite plugin development

    Try it Yourself ยป
    JavaScript
    // Writing a Custom Vite Plugin
    function myVitePlugin() {
      return {
        name: "my-vite-plugin",
    
        // Runs during config resolution
        config(config, { command }) {
          console.log("Building for:", command);
        },
    
        // Transform source code
        transform(code, id) {
          // Convert .txt files to JS modules
          if (id.endsWith(".txt")) {
            return {
              code: `export default ${JSON.stringify(code)}`,
              map: null
            };
          }
        },
    
        // Modify the HTML
       
    ...

    Code Splitting & Lazy Loading

    Code splitting creates separate chunks that load on demand, dramatically improving initial load times. Use dynamic imports to load routes, features, and heavy libraries only when needed.

    Code Splitting & Lazy Loading

    Dynamic imports and lazy loading patterns

    Try it Yourself ยป
    JavaScript
    // Code Splitting with Dynamic Imports
    
    // 1. Route-based code splitting
    const routes = [
      {
        path: "/",
        // Lazy load the home page
        component: () => import("./pages/Home.js")
      },
      {
        path: "/dashboard",
        // Lazy load dashboard (admin only)
        component: () => import("./pages/Dashboard.js")
      },
      {
        path: "/settings",
        component: () => import("./pages/Settings.js")
      }
    ];
    
    // 2. Feature-based code splitting
    async function loadChartLibrary() {
      // Only load heavy libra
    ...

    Tree Shaking

    Tree shaking eliminates unused code from your final bundle. It works best with ES modules and side-effect-free code.

    Tree Shaking

    Dead code elimination techniques

    Try it Yourself ยป
    JavaScript
    // Tree Shaking - Dead Code Elimination
    
    // โŒ BAD: Imports entire library (no tree shaking)
    import _ from "lodash";
    const result = _.map([1, 2, 3], x => x * 2);
    
    // โœ… GOOD: Import only what you need (tree shakeable)
    import { map } from "lodash-es";
    const result = map([1, 2, 3], x => x * 2);
    
    
    // โŒ BAD: Side effects prevent tree shaking
    export function usefulFunction() {
      return "I am useful";
    }
    
    export function unusedFunction() {
      return "I am never used";
    }
    
    // Side effect - runs when module 
    ...

    Hot Module Replacement (HMR)

    HMR updates modules in the browser without a full page refresh, preserving application state. Vite provides instant HMR out of the box.

    Hot Module Replacement

    HMR implementation patterns

    Try it Yourself ยป
    JavaScript
    // Hot Module Replacement (HMR)
    
    // How HMR works internally:
    // 1. You edit a file
    // 2. Bundler compiles JUST that file
    // 3. Sends update via WebSocket
    // 4. Browser replaces the module
    // 5. State is preserved (no page refresh!)
    
    
    // Vite - HMR is automatic for most files
    // For custom HMR handling:
    if (import.meta.hot) {
      // Accept updates for this module
      import.meta.hot.accept((newModule) => {
        console.log("Module updated!", newModule);
      });
    
      // Clean up before module is replaced
    
    ...

    Environment Variables

    Bundlers inject environment-specific variables at build time, allowing different configurations for development, staging, and production.

    Environment Variables

    Managing environment-specific configurations

    Try it Yourself ยป
    JavaScript
    // Environment Variables in Bundlers
    
    // Vite - Uses import.meta.env
    // .env file:
    // VITE_API_URL=https://api.example.com
    // VITE_DEBUG=true
    
    // Access in code:
    console.log(import.meta.env.VITE_API_URL);
    console.log(import.meta.env.VITE_DEBUG);
    console.log(import.meta.env.MODE); // "development" or "production"
    console.log(import.meta.env.DEV);  // true in dev
    console.log(import.meta.env.PROD); // true in production
    
    
    // Webpack - Uses DefinePlugin
    // webpack.config.js
    const webpack = require("
    ...

    Module Federation (Microfrontends)

    Webpack Module Federation allows separate applications to share code at runtime โ€” the foundation of microfrontend architecture used by Amazon, Netflix, and Shopify.

    Module Federation

    Microfrontend architecture patterns

    Try it Yourself ยป
    JavaScript
    // Webpack Module Federation (Microfrontends)
    
    // Host Application - webpack.config.js
    const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
    
    module.exports = {
      plugins: [
        new ModuleFederationPlugin({
          name: "host",
          
          // Import modules from remote apps
          remotes: {
            // "internal name": "remote_name@URL"
            headerApp: "header@http://localhost:3001/remoteEntry.js",
            productApp: "products@http://localhost:3002/remoteEntr
    ...

    Server-Side Rendering (SSR)

    SSR requires bundling both client and server code. Vite has built-in SSR support with separate entry points for server rendering and client hydration.

    Server-Side Rendering

    SSR build configuration patterns

    Try it Yourself ยป
    JavaScript
    // Server-Side Rendering (SSR) Build Configuration
    
    // Vite SSR - vite.config.js
    import { defineConfig } from "vite";
    
    export default defineConfig({
      build: {
        // SSR entry point
        ssr: true,
        rollupOptions: {
          input: "./src/entry-server.js"
        }
      },
      
      ssr: {
        // Don't bundle these (use Node.js require)
        noExternal: ["some-package-to-bundle"]
      }
    });
    
    // entry-server.js - Server entry point
    import { renderToString } from "react-dom/server";
    import App from "./App";
    
    expo
    ...

    Parcel: Zero Configuration

    Parcel automatically detects and handles all file types without configuration. Perfect for prototypes, learning, and simple projects.

    Parcel Configuration

    Zero-configuration bundler setup

    Try it Yourself ยป
    JavaScript
    // Parcel - Zero Configuration Bundler
    
    // No config file needed! Just run:
    // npx parcel index.html
    
    // Parcel automatically detects and handles:
    // - JavaScript/TypeScript
    // - JSX/TSX
    // - CSS/SCSS/LESS
    // - Images and fonts
    // - HTML
    
    // Optional .parcelrc for customization
    {
      "extends": "@parcel/config-default",
      "transformers": {
        "*.svg": ["@parcel/transformer-svg-react"]
      },
      "optimizers": {
        "*.js": ["@parcel/optimizer-terser"]
      }
    }
    
    
    // package.json scripts
    {
      "scripts": {
    
    ...

    Choosing the Right Bundler

    Each bundler excels in different scenarios. Choose based on your project's needs, team experience, and long-term requirements.

    Bundler Comparison

    Comparing Webpack, Vite, and Parcel

    Try it Yourself ยป
    JavaScript
    // Bundler Feature Comparison
    
    /*
    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
    โ”‚ Feature         โ”‚ Webpack      โ”‚ Vite         โ”‚ Parcel       โ”‚
    โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
    โ”‚ Configuration   โ”‚ Complex      โ”‚ Minimal      โ”‚ Zero-config  โ”‚
    โ”‚ Dev Server      โ”‚ Slow         โ”‚ FASTEST      โ”‚ Fast         โ”‚
    โ”‚ Build Speed     โ”‚ Slow         โ”‚ Fast         โ”‚ Fast         โ”‚
    โ”‚ HMR             โ”‚ Config req.  โ”‚ Instant      โ”‚ Built-in     โ”‚
    โ”‚ Code Spli
    ...

    Key Takeaways

    Core Concepts

    • โœ“ Entry points, loaders, and plugins
    • โœ“ Code splitting with dynamic imports
    • โœ“ Tree shaking for dead code elimination
    • โœ“ Hot Module Replacement (HMR)
    • โœ“ Environment-specific builds

    When to Use Each

    • โœ“ Vite โ€” New projects, fastest dev
    • โœ“ Webpack โ€” Enterprise, microfrontends
    • โœ“ Parcel โ€” Prototypes, learning
    • โœ“ Production: minify, split, cache, CDN

    Sign up for free to track which lessons you've completed and get learning reminders.

    Previous