MindForge
MindForge
DashboardHelp & Support
Dashboard
MindForge

Interview Preparation Bootcamp

Course progress

0%
0 of 177 modules complete
Start Here0/1
  • How to Use This Course
Data Structures & Algorithms0/27
  • Arrays and Hashing
  • Two Pointers
  • Sliding Window
  • Sliding Window: Harder Problems
  • Binary Search
  • Stacks
  • Practice Test: Arrays, Pointers, Windows, Search and Stacks
  • Trees: Traversals and Core Patterns
  • Binary Search Trees and Rebuilding a Tree
  • Tries (Prefix Trees)
  • Heaps and Priority Queues
  • Graphs: BFS and DFS
  • Topological Sort and Cycle Detection
  • Union-Find (Disjoint Set Union)
  • Practice Test: Trees, Heaps and Graphs
  • Dynamic Programming Basics
  • Dynamic Programming: Two Dimensions
  • Dynamic Programming: Hard String Matching
  • Backtracking
  • Backtracking: Constraint Satisfaction
  • Greedy Algorithms
  • Interval Problems
  • Bit Manipulation
  • Math and Geometry
  • String Manipulation
  • Pattern Recall and Mock Coding Rounds
  • Practice Test: DP, Backtracking, Greedy and More

System Design

Foundations0/16
  • The System Design Interview Framework
  • Back-of-the-Envelope Estimation
  • Networking and Protocols for Design
  • API Design and Idempotency
  • Load Balancing, Proxies, and Scaling Out
  • Caching and CDNs
  • Choosing a Database: Storage, Indexes and Transactions
  • Replication, Partitioning, and Sharding
  • CAP, PACELC, and Levels of Consistency
  • Messaging, Queues, and Event-Driven Architecture
  • Distributed Transactions and Data Integrity
  • Coordination, Consensus, and Distributed Locks
  • Reliability, Resilience, and Rate Limiting
  • Observability, Security, and Cost
  • System Design Cheat Sheet
  • Practice Test: System Design Foundations
Case Studies0/23
  • Design a URL Shortener
  • Design a Rate Limiter
  • Design a Notification Service
  • Design a Job Queue System
  • Design a Chat App (WhatsApp)
  • Design an Analytics Pipeline
  • Design a Multi-tenant SaaS Architecture
  • Design a Social Media Feed (Twitter/X)
  • Design a Search Autocomplete System
  • Design a File Storage Service (Dropbox)
  • Design Google Docs
  • Design a Code Review System
  • Design Netflix
  • Design YouTube
  • Design Spotify
  • Design Uber/Lyft
  • Design Airbnb
  • Design Ticketmaster (Eventbrite)
  • Design an E-commerce Cart, Checkout, and Catalog
  • Design a Payment System
  • Design a Logging and Monitoring System
  • Mock Design Rounds
  • Practice Test: System Design Case Studies
Low-Level Design0/19
  • The LLD Interview Framework and UML
  • OOP Foundations for Design
  • SOLID Principles
  • Creational Patterns
  • Structural Patterns
  • Behavioral Patterns I — Strategy, Observer, Command, State, Template Method
  • Behavioral Patterns II and Anti-Patterns
  • Concurrency in Low-Level Design
  • Design a Parking Lot
  • Design an Elevator System
  • Design a Movie Ticket Booking System
  • Design an Expense-Sharing App (Splitwise)
  • Design a Vending Machine and an ATM
  • Design a Rate Limiter and a Logging Framework
  • Design a Notification Service and an In-Memory Cache
  • Design Games — Tic-Tac-Toe, Snake and Ladder, Chess
  • Database Design for LLD
  • LLD Cheat Sheet and Recall Drill
  • Practice Test: Low-Level Design

Backend

Python0/5
  • How Python Runs Your Code
  • Functions Deep Dive: Closures, Generators, Context Managers, Scope
  • Classes Deep Dive: Method Types, MRO, Metaclasses
  • Standard Library and Serialization
  • Practice Test: Python
Django0/6
  • Django Request Lifecycle
  • Lab: Django Middleware — Request ID & Response Time
  • Django ORM and Querysets
  • Django's Cache Framework
  • Practice Test: Django
  • Django in Production: Debugging Labs
FastAPI0/5
  • FastAPI, ASGI, and Async
  • FastAPI Dependency Injection
  • FastAPI Background Tasks
  • Lab: FastAPI Async — Concurrent Aggregation
  • Practice Test: FastAPI
Databases (PostgreSQL)0/6
  • Indexing
  • Query Optimization
  • Transactions and Isolation
  • Migrations and Schema Changes
  • Hierarchical Data and Safe Concurrent Updates
  • Practice Test: Databases
Caching, Queues & Distributed Systems0/8
  • Redis Caching
  • Redis Advanced Patterns
  • Celery and Background Workers
  • Kafka and Message Queues
  • Async Pipelines
  • Distributed Systems Basics
  • Distributed Locks
  • Practice Test: Caching, Queues and Distributed Systems
APIs, Security & Deployment0/9
  • REST API Design
  • API Versioning and Error Handling
  • API Security and Authentication
  • WebSockets and Real-Time Systems
  • Docker and Containers
  • File Storage with S3
  • Testing Strategies
  • Mock Backend Round
  • Practice Test: APIs, Security and Deployment
Frontend0/38
  • HTML Document Structure and Semantics
  • CSS Box Model, Flexbox and Grid
  • CSS Architecture and Theming
  • CSS and Rendering Performance
  • Variables, Scope, Hoisting, and Truthiness
  • Functions, this, and Binding
  • Objects and Prototypal Inheritance
  • JavaScript Utility Patterns: Cloning, Caching, and Memory
  • Promises From Scratch
  • The Event Loop and Browser Rendering Pipeline
  • The DOM: Nodes, Events, and Traversal
  • Practice Test: HTML, CSS and JavaScript
  • React Rendering Fundamentals
  • React Hooks Internals
  • React Performance
  • Lab: React — Stateful Counter Component
  • State Management
  • State Machines in React
  • React Custom Hooks and Composition Patterns
  • TypeScript for React
  • React Testing
  • Practice Test: React
  • HTTP and Caching
  • Network Performance and Web Vitals
  • Code Splitting and Bundles
  • Virtualization
  • GraphQL and Data Fetching
  • Web Security
  • WebSockets and Real-time
  • SSR and Next.js
  • Micro-frontends
  • Build Tools and Bundling
  • Accessibility
  • Error Handling
  • Internationalization
  • Animation
  • Rapid Recall and Mock Frontend Rounds
  • Practice Test: Performance, Architecture and Production
Behavioral & Interview Day0/14
  • Resume and Project Walkthroughs
  • The STAR Method and Refining Your Stories
  • Conflict and Difficult Coworkers
  • Failures, Incidents, and Obstacles
  • Leadership, Mentorship, and Ownership
  • Teamwork, Communication, and Feedback
  • Growth and Handling Ambiguity
  • Career Goals, Why This Company, and Negotiation
  • Situational Questions
  • Company Research
  • Mock Behavioral Rounds
  • Interview Day
  • After the Interview
  • Practice Test: Behavioral and Interview Day
Build Tools and Bundling
Course contents

Interview Preparation Bootcamp

Course progress

0%
0 of 177 modules complete
Start Here0/1
  • How to Use This Course
Data Structures & Algorithms0/27
  • Arrays and Hashing
  • Two Pointers
  • Sliding Window
  • Sliding Window: Harder Problems
  • Binary Search
  • Stacks
  • Practice Test: Arrays, Pointers, Windows, Search and Stacks
  • Trees: Traversals and Core Patterns
  • Binary Search Trees and Rebuilding a Tree
  • Tries (Prefix Trees)
  • Heaps and Priority Queues
  • Graphs: BFS and DFS
  • Topological Sort and Cycle Detection
  • Union-Find (Disjoint Set Union)
  • Practice Test: Trees, Heaps and Graphs
  • Dynamic Programming Basics
  • Dynamic Programming: Two Dimensions
  • Dynamic Programming: Hard String Matching
  • Backtracking
  • Backtracking: Constraint Satisfaction
  • Greedy Algorithms
  • Interval Problems
  • Bit Manipulation
  • Math and Geometry
  • String Manipulation
  • Pattern Recall and Mock Coding Rounds
  • Practice Test: DP, Backtracking, Greedy and More

System Design

Foundations0/16
  • The System Design Interview Framework
  • Back-of-the-Envelope Estimation
  • Networking and Protocols for Design
  • API Design and Idempotency
  • Load Balancing, Proxies, and Scaling Out
  • Caching and CDNs
  • Choosing a Database: Storage, Indexes and Transactions
  • Replication, Partitioning, and Sharding
  • CAP, PACELC, and Levels of Consistency
  • Messaging, Queues, and Event-Driven Architecture
  • Distributed Transactions and Data Integrity
  • Coordination, Consensus, and Distributed Locks
  • Reliability, Resilience, and Rate Limiting
  • Observability, Security, and Cost
  • System Design Cheat Sheet
  • Practice Test: System Design Foundations
Case Studies0/23
  • Design a URL Shortener
  • Design a Rate Limiter
  • Design a Notification Service
  • Design a Job Queue System
  • Design a Chat App (WhatsApp)
  • Design an Analytics Pipeline
  • Design a Multi-tenant SaaS Architecture
  • Design a Social Media Feed (Twitter/X)
  • Design a Search Autocomplete System
  • Design a File Storage Service (Dropbox)
  • Design Google Docs
  • Design a Code Review System
  • Design Netflix
  • Design YouTube
  • Design Spotify
  • Design Uber/Lyft
  • Design Airbnb
  • Design Ticketmaster (Eventbrite)
  • Design an E-commerce Cart, Checkout, and Catalog
  • Design a Payment System
  • Design a Logging and Monitoring System
  • Mock Design Rounds
  • Practice Test: System Design Case Studies
Low-Level Design0/19
  • The LLD Interview Framework and UML
  • OOP Foundations for Design
  • SOLID Principles
  • Creational Patterns
  • Structural Patterns
  • Behavioral Patterns I — Strategy, Observer, Command, State, Template Method
  • Behavioral Patterns II and Anti-Patterns
  • Concurrency in Low-Level Design
  • Design a Parking Lot
  • Design an Elevator System
  • Design a Movie Ticket Booking System
  • Design an Expense-Sharing App (Splitwise)
  • Design a Vending Machine and an ATM
  • Design a Rate Limiter and a Logging Framework
  • Design a Notification Service and an In-Memory Cache
  • Design Games — Tic-Tac-Toe, Snake and Ladder, Chess
  • Database Design for LLD
  • LLD Cheat Sheet and Recall Drill
  • Practice Test: Low-Level Design

Backend

Python0/5
  • How Python Runs Your Code
  • Functions Deep Dive: Closures, Generators, Context Managers, Scope
  • Classes Deep Dive: Method Types, MRO, Metaclasses
  • Standard Library and Serialization
  • Practice Test: Python
Django0/6
  • Django Request Lifecycle
  • Lab: Django Middleware — Request ID & Response Time
  • Django ORM and Querysets
  • Django's Cache Framework
  • Practice Test: Django
  • Django in Production: Debugging Labs
FastAPI0/5
  • FastAPI, ASGI, and Async
  • FastAPI Dependency Injection
  • FastAPI Background Tasks
  • Lab: FastAPI Async — Concurrent Aggregation
  • Practice Test: FastAPI
Databases (PostgreSQL)0/6
  • Indexing
  • Query Optimization
  • Transactions and Isolation
  • Migrations and Schema Changes
  • Hierarchical Data and Safe Concurrent Updates
  • Practice Test: Databases
Caching, Queues & Distributed Systems0/8
  • Redis Caching
  • Redis Advanced Patterns
  • Celery and Background Workers
  • Kafka and Message Queues
  • Async Pipelines
  • Distributed Systems Basics
  • Distributed Locks
  • Practice Test: Caching, Queues and Distributed Systems
APIs, Security & Deployment0/9
  • REST API Design
  • API Versioning and Error Handling
  • API Security and Authentication
  • WebSockets and Real-Time Systems
  • Docker and Containers
  • File Storage with S3
  • Testing Strategies
  • Mock Backend Round
  • Practice Test: APIs, Security and Deployment
Frontend0/38
  • HTML Document Structure and Semantics
  • CSS Box Model, Flexbox and Grid
  • CSS Architecture and Theming
  • CSS and Rendering Performance
  • Variables, Scope, Hoisting, and Truthiness
  • Functions, this, and Binding
  • Objects and Prototypal Inheritance
  • JavaScript Utility Patterns: Cloning, Caching, and Memory
  • Promises From Scratch
  • The Event Loop and Browser Rendering Pipeline
  • The DOM: Nodes, Events, and Traversal
  • Practice Test: HTML, CSS and JavaScript
  • React Rendering Fundamentals
  • React Hooks Internals
  • React Performance
  • Lab: React — Stateful Counter Component
  • State Management
  • State Machines in React
  • React Custom Hooks and Composition Patterns
  • TypeScript for React
  • React Testing
  • Practice Test: React
  • HTTP and Caching
  • Network Performance and Web Vitals
  • Code Splitting and Bundles
  • Virtualization
  • GraphQL and Data Fetching
  • Web Security
  • WebSockets and Real-time
  • SSR and Next.js
  • Micro-frontends
  • Build Tools and Bundling
  • Accessibility
  • Error Handling
  • Internationalization
  • Animation
  • Rapid Recall and Mock Frontend Rounds
  • Practice Test: Performance, Architecture and Production
Behavioral & Interview Day0/14
  • Resume and Project Walkthroughs
  • The STAR Method and Refining Your Stories
  • Conflict and Difficult Coworkers
  • Failures, Incidents, and Obstacles
  • Leadership, Mentorship, and Ownership
  • Teamwork, Communication, and Feedback
  • Growth and Handling Ambiguity
  • Career Goals, Why This Company, and Negotiation
  • Situational Questions
  • Company Research
  • Mock Behavioral Rounds
  • Interview Day
  • After the Interview
  • Practice Test: Behavioral and Interview Day
Browsing without an account — progress is saved in this browser only.Sign in to save it

Build Tools and Bundling

Reading30 min

"How does a bundler actually work" is a favorite senior question, because most engineers run Webpack or Vite every day without ever looking inside. Explaining module resolution, tree shaking, and hot reload from first principles is a real signal of depth. This lesson builds a tiny bundler and a tiny code-transform by hand, then covers what production tools do differently.

What a bundler is actually for

A bundler solves one problem: browsers used to be slow at loading hundreds of separately imported files over the network, too many round trips, though HTTP/2 and native ES modules have since eaten into that. So a bundler walks a dependency graph of modules and combines it into one file, or a handful of them.

The pipeline is the same shape no matter the tool. Resolve: starting from an entry file, follow every import/require to an actual file on disk. Parse: turn each file's source into a tree structure (an AST). Build a graph: walk each file's imports and exports, recursively resolving and parsing until every reachable module is found. Transform: run each file through its loaders and plugins, TypeScript to plain JS, JSX to React.createElement. Generate: combine the modules into one or more output files, wiring up each module's imports as a lookup into a shared runtime registry.

Webpack, Vite, and esbuild differ mainly in when this happens and what language does it. Webpack runs the full pipeline upfront, in both dev and production, highly configurable, written in JavaScript, flexible but the slowest of the three. esbuild runs the same pipeline written in Go, parsing and generating far faster than JS-based tools, and it's what Vite uses under the hood for transforms. Vite doesn't bundle at all in development: it serves native ES modules straight to the browser, transforming each file on demand as it's requested, and only bundles for production, through Rollup. That's why Vite's dev server starts almost instantly no matter how big the app is, it never builds a full dependency graph upfront.

Remember: Webpack builds the whole graph before serving anything, even in dev. Vite serves files on demand in dev and only bundles for production.

Sign in to try this knowledge check.

Building a minimal bundler

Enough code to make "dependency graph" a concrete thing, resolving and combining CommonJS-style modules:

ts
function extractDependencies(code: string): string[] {
  // Illustrative only — a real bundler uses an AST parser (acorn, babel), not regex
  const requireRegex = /require\(["'](.+?)["']\)/g;
  const deps: string[] = [];
  let match: RegExpExecArray | null;
  while ((match = requireRegex.exec(code))) deps.push(match[1]);
  return deps;
}

function buildGraph(entryFile: string) {
  let nextId = 0;
  const graph: { id: number; filename: string; code: string; dependencyMap: Record<string, number> }[] = [];
  const visited = new Map<string, number>();

  function visit(filename: string): number {
    if (visited.has(filename)) return visited.get(filename)!;
    const code = readFileSync(filename, "utf-8");
    const id = nextId++;
    visited.set(filename, id);
    const dependencyMap: Record<string, number> = {};
    for (const relativePath of extractDependencies(code)) {
      dependencyMap[relativePath] = visit(resolve(dirname(filename), relativePath + ".js")); // recurse — this IS the graph traversal
    }
    graph.push({ id, filename, code, dependencyMap });
    return id;
  }
  visit(entryFile);
  return graph;
}

Generating output wraps each module in a function, keyed by its id, with a require that looks up dependencies by numeric id instead of by string path:

ts
function bundle(graph: ReturnType<typeof buildGraph>): string {
  const modules = graph.map((m) => `${m.id}: [function(require, module, exports) { ${m.code} }, ${JSON.stringify(m.dependencyMap)}]`).join(",\n");
  return `
(function(modules) {
  const cache = {};
  function require(id) {
    if (cache[id]) return cache[id].exports;
    const [fn, mapping] = modules[id];
    const module = { exports: {} };
    cache[id] = module;
    fn((relativePath) => require(mapping[relativePath]), module, module.exports);
    return module.exports;
  }
  require(0); // entry point is always module 0
})({ ${modules} });`;
}

This is the same core idea every real bundler uses: replace require/import with a lookup into an in-memory registry keyed by module id, so the runtime never touches the filesystem again after resolution happens once, at build time.

Remember: a bundler's runtime registry is what lets require/import become a fast numeric lookup instead of a filesystem read on every call.

Building a code transform, the way Babel does

Transforms work on the AST, not the raw source string, because a plain string replacement breaks the moment syntax gets nested or shows up somewhere unexpected, a require sitting inside a comment or a template literal, for example.

ts
interface ASTNode { type: string; [key: string]: unknown; }

// A real implementation uses @babel/parser + @babel/traverse + @babel/generator.
// This shows the *shape* of the visitor pattern every AST tool follows.
function transform(ast: ASTNode): ASTNode {
  function visit(node: ASTNode): ASTNode {
    if (node.type === "VariableDeclaration" && (node.kind === "const" || node.kind === "let")) {
      node.kind = "var"; // the actual transformation — mutate the node in place
    }
    for (const key of Object.keys(node)) {
      const value = node[key];
      if (Array.isArray(value)) value.forEach((child) => { if (child?.type) visit(child as ASTNode); });
      else if (value && typeof value === "object" && "type" in value) visit(value as ASTNode);
    }
    return node;
  }
  return visit(ast);
}

JSX compiling into React.createElement, and TypeScript compiling into plain JS, both work through this exact same visitor pattern: parse the source into an AST once, run one or more passes that mutate specific node types, then regenerate source from the transformed tree. A Babel plugin is, structurally, just a visit function scoped to specific node types through a visitor object.

Remember: regex-based rewriting breaks the moment syntax nests or hides inside a string or comment. An AST-based transform doesn't, because it only sees real syntax nodes.

Sign in to try this knowledge check.

Module resolution

Resolution turns import x from "./utils" or import y from "lodash" into an actual file path. Node's algorithm, which most bundlers extend rather than replace, works in three steps. A relative or absolute path (./, ../, /) resolves directly against the current file's directory, trying the exact path, then path.js, then path/index.js, in that order. A bare name ("lodash") triggers a walk up the directory tree, checking node_modules/lodash in each parent directory until it's found or the filesystem root is reached. Package resolution then reads that package's package.json, its exports field (modern, can restrict what's importable) or main/module (older), to find the actual entry file.

Bundlers add path aliases on top of this, @/components mapping to src/components, as a resolution-time rewrite (tsconfig.json's paths, Webpack's resolve.alias, Vite's resolve.alias), applied before falling through to Node's own algorithm.

Tree shaking, from the bundler's own point of view

Tree shaking removes exported code that's never imported anywhere in the graph, and it depends specifically on ES module syntax, since import/export are statically readable without running any code.

ts
// math.ts
export function add(a: number, b: number) { return a + b; }
export function subtract(a: number, b: number) { return a - b; } // never imported anywhere

// app.ts
import { add } from "./math";
// A production build contains `add` but not `subtract` —
// static analysis proves `subtract` is unreachable from any entry point.

CommonJS largely defeats this, since require calls can be conditional or dynamic, so a bundler can't statically prove what's actually used without running the code. That's the real, mechanical reason "use ES modules, not CommonJS" is standard advice, not just a style preference.

Hot module replacement

HMR swaps a changed module's code inside the running app without a full page reload, keeping in-memory state, form inputs, component state, that a full refresh would otherwise wipe out. The dev server watches the filesystem, re-transforms just the changed file on a save, sends the new code to the browser over a WebSocket, which is why a dev server opens one at all, and the browser's own HMR runtime swaps the old module's exports for the new ones in its registry, then re-runs anything that "accepted" the update.

ts
// Vite/Webpack HMR API — a module opts into accepting its own updates
if (import.meta.hot) {
  import.meta.hot.accept((newModule) => { /* re-render with the new exports instead of reloading */ });
}

React's Fast Refresh builds on this: it detects that only a component's render function changed, not its state-holding hooks' call order, swaps the function, and re-renders, keeping useState values intact across the edit. If the edit changes hook order or a non-component export, Fast Refresh falls back to a full remount, state lost, because it can no longer guarantee that's safe.

Remember: Fast Refresh only preserves state when it can prove the same hooks still run in the same order. Change that order and it has to fall back to a full remount.

Sign in to try this knowledge check.

Why this is worth knowing beyond trivia

None of resolve, parse, transform, tree-shake, or HMR are things you'll hand-implement at your actual job. They're worth knowing because the mini-bundler and mini-transform above are the same shape of code running inside Webpack, Vite, and Babel today, just with a real parser and years of edge cases layered on top instead of a regex. When an interviewer asks why tree shaking isn't working, or why HMR just did a full reload, they're checking whether you can reason from the actual mechanism, not whether you've memorized a remembered answer.

PreviousMicro-frontendsNextAccessibility

Course progress

0%
0 of 177 modules complete

On this page

  • What a bundler is actually for
  • Building a minimal bundler
  • Building a code transform, the way Babel does
  • Module resolution
  • Tree shaking, from the bundler's own point of view
  • Hot module replacement
  • Why this is worth knowing beyond trivia