---
name: build-pipelines-bundling
description: Explains JavaScript bundling, code splitting, chunking strategies, tree shaking, and build pipelines. Use when optimizing bundle size, understanding how modern build tools work, configuring Webpack/Vite/esbuild, or debugging build output.
---
# Build Pipelines and Bundling
## Overview
Build pipelines transform your source code into optimized assets for browsers. Understanding this process is essential for performance optimization and debugging.
## Why Bundling Exists
Browsers historically couldn't handle modern JavaScript development patterns:
```javascript
// YOUR CODE: Many small files with imports
// src/
// ├── index.js (imports App)
// ├── App.js (imports Header, Main, Footer)
// ├── Header.js (imports Logo, Nav)
// ├── Nav.js (imports NavLink)
// └── ... 100+ files
// PROBLEM 1: HTTP/1.1 could only load 6 files in parallel
// 100 files = 17 round trips = SLOW
// PROBLEM 2: Browsers didn't support import/export (until ES modules)
import { Component } from './Component.js'; // Didn't work!
// PROBLEM 3: npm packages live in node_modules
import React from 'react'; // Browser can't resolve this path!
// SOLUTION: Bundle everything into fewer files
// dist/
// ├── index.html
// ├── main.js (all your code + dependencies)
// └── main.css
```
## The Build Pipeline
```
SOURCE CODE BUILD PIPELINE OUTPUT
─────────────────────────────────────────────────────────────────────────────
src/ dist/
├── index.tsx ───┐ ┌─► index.html
├── App.tsx │ ┌──────────────────────────────┐ │
├── components/ ├───►│ 1. Resolve imports │ ├─► main.[hash].js
│ ├── Header.tsx │ │ 2. Transform (TS, JSX, etc) │ │
│ └── Button.tsx │ │ 3. Bundle modules │───►├─► vendor.[hash].js
├── styles/ │ │ 4. Optimize (minify, etc) │ │
│ └── main.css │ │ 5. Output files │ ├─► main.[hash].css
└── assets/ │ └──────────────────────────────┘ │
└── logo.png ────┘ └─► assets/logo.[hash].png
```
## Bundler Comparison
| Bundler | Speed | Configuration | Best For |
|---------|-------|---------------|----------|
| **Webpack** | Slower | Complex, powerful | Large apps, legacy |
| **Vite** | Fast (dev) | Minimal | Modern apps, DX |
| **esbuild** | Fastest | Limited | Build step, library |
| **Rollup** | Medium | Plugin-focused | Libraries |
| **Parcel** | Fast | Zero-config | Quick prototypes |
| **Turbopack** | Fast | Webpack-compatible | Next.js |
## Core Bundling Concepts
### Module Resolution
How bundlers find your imports:
```javascript
// Relative imports - resolved from current file
import { Button } from './components/Button';
// → src/components/Button.js
// Bare imports - resolved from node_modules
import React from 'react';
// → node_modules/react/index.js
// Alias imports - resolved via config
import { api } from '@/lib/api';
// → src/lib/api.js (@ mapped to src/)
// RESOLUTION ORDER (Node-style):
// 1. Exact path: ./Button.js
// 2. Add extensions: ./Button → ./Button.js, ./Button.ts, ./Button.tsx
// 3. Index files: ./Button → ./Button/index.js
// 4. Package.json "main" or "exports" field
```
### Dependency Graph
Bundlers build a graph of all dependencies:
```
Entry: src/index.tsx
│
▼
┌─────────┐
│ index │
└────┬────┘
│ imports
▼
┌─────────┐ ┌─────────┐
│ App │────►│ React │
└────┬────┘ └─────────┘
│ imports
┌────┴────┐
▼ ▼
┌────────┐ ┌────────┐
│ Header │ │ Footer │
└───┬────┘ └────────┘
│ imports
▼
┌─────────┐
│ Logo │
└─────────┘
// Bundler walks this graph:
// 1. Start at entry point
// 2. Parse file, find imports
// 3. Recursively process each import
// 4. Build complete dependency graph
// 5. Output bundle in correct order
```
## Code Splitting
Breaking your bundle into smaller pieces loaded on demand.
### Why Code Split?
```
WITHOUT CODE SPLITTING:
┌─────────────────────────────────────────┐
│ main.js (2MB) │
│ ┌─────┐ ┌─────┐ ┌─────┐ ┌───────────┐ │
│ │Home │ │About│ │Blog │ │ Dashboard │ │
│ └─────┘ └─────┘ └─────┘ └───────────┘ │
└─────────────────────────────────────────┘
User visits /home → Downloads 2MB (includes unused Dashboard code)
WITH CODE SPLITTING:
┌──────────────┐
│ main.js (50KB)│ ← Core app, router
└──────────────┘
│
├─► home.js (30KB) ← Loaded on /home
├─► about.js (20KB) ← Loaded on /about
├─► blog.js (40KB) ← Loaded on /blog
└─► dashboard.js (500KB) ← Loaded only on /dashboard
User visits /home → Downloads 80KB (main + home)
```
### Split Strategies
**1. Route-Based Splitting**
```javascript
// React with lazy loading
import { lazy, Suspense } from 'react';
// Each route becomes a separate chunk
const Home = lazy(() => import('./pages/Home'));
const About = lazy(() => import('./pages/About'));
const Dashboard = lazy(() => import('./pages/Dashboard'));
function App() {
return (
}>
} />
} />
} />
);
}
// Build output:
// main.js - core app
// pages-Home-[hash].js - home chunk
// pages-About-[hash].js - about chunk
// pages-Dashboard-[hash].js - dashboard chunk
```
**2. Component-Based Splitting**
```javascript
// Heavy components loaded on demand
const HeavyChart = lazy(() => import('./components/HeavyChart'));
const MarkdownEditor = lazy(() => import('./components/MarkdownEditor'));
function Dashboard() {
const [showChart, setShowChart] = useState(false);
return (
{showChart && (
}>
{/* Loaded only when needed */}
)}
);
}
```
**3. Vendor Splitting**
```javascript
// Webpack config
optimization: {
splitChunks: {
cacheGroups: {
// Separate node_modules into vendor chunk
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all',
},
// Separate large libraries
react: {
test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/,
name: 'react',
chunks: 'all',
},
},
},
}
// Output:
// main.js - your code
// vendors.js - all node_modules
// react.js - react + react-dom (cached separately)
```
## Chunking Strategies
### Chunk Types
```
ENTRY CHUNKS:
- Starting points of your application
- Usually one per "page" or entry point
ASYNC CHUNKS:
- Created by dynamic imports: import('./module')
- Loaded on demand
COMMON/SHARED CHUNKS:
- Code used by multiple chunks
- Extracted to avoid duplication
VENDOR CHUNKS:
- Third-party code from node_modules
- Changes less frequently = better caching
```
### Optimal Chunking
```javascript
// Webpack splitChunks configuration
optimization: {
splitChunks: {
chunks: 'all',
minSize: 20000, // Minimum chunk size (20KB)
maxSize: 244000, // Try to keep under 244KB
minChunks: 1, // Minimum times a module is shared
maxAsyncRequests: 30, // Max parallel requests for async chunks
cacheGroups: {
defaultVendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10,
reuseExistingChunk: true,
},
default: {
minChunks: 2, // Split if used 2+ times
priority: -20,
reuseExistingChunk: true,
},
},
},
}
```
## Tree Shaking
Removing unused code from the bundle.
### How It Works
```javascript
// utils.js - exports multiple functions
export function usedFunction() {
return 'I am used';
}
export function unusedFunction() {
return 'I am never imported anywhere';
}
export const USED_CONSTANT = 42;
export const UNUSED_CONSTANT = 999;
// app.js - only imports some exports
import { usedFunction, USED_CONSTANT } from './utils';
console.log(usedFunction(), USED_CONSTANT);
// AFTER TREE SHAKING:
// Bundle only contains usedFunction and USED_CONSTANT
// unusedFunction and UNUSED_CONSTANT are removed
```
### Requirements for Tree Shaking
```javascript
// ✓ WORKS: ES modules (static structure)
import { specific } from 'library';
export function myFunction() {}
// ✗ DOESN'T WORK: CommonJS (dynamic structure)
const library = require('library');
module.exports = myFunction;
// ✗ DOESN'T WORK: Dynamic imports of specific exports
const { specific } = await import('library'); // Can tree shake the import
// But the library must use ES modules internally
// SIDE EFFECTS: Code that runs on import
// package.json
{
"sideEffects": false // All files are pure, safe to tree shake
}
// Or specify which files have side effects:
{
"sideEffects": [
"*.css", // CSS imports have side effects
"./src/polyfills.js" // This file runs code on import
]
}
```
## Minification
Reducing code size without changing behavior.
### Techniques
```javascript
// ORIGINAL CODE:
function calculateTotalPrice(items) {
let totalPrice = 0;
for (let i = 0; i < items.length; i++) {
totalPrice += items[i].price * items[i].quantity;
}
return totalPrice;
}
// AFTER MINIFICATION:
function calculateTotalPrice(e){let t=0;for(let l=0;lClick;
}
// Output:
// .button → .Button_button_x7h3j (scoped)
```
## Content Hashing
Cache busting with content-based filenames.
```javascript
// WITHOUT HASHING:
// main.js - browser caches indefinitely
// Update code → browser still uses old cached version!
// WITH CONTENT HASHING:
// main.a1b2c3d4.js - hash based on content
// Update code → new hash → new filename → browser fetches new version
// Webpack configuration:
output: {
filename: '[name].[contenthash].js',
chunkFilename: '[name].[contenthash].chunk.js',
}
// Benefits:
// - Unchanged files keep same hash = cached
// - Changed files get new hash = fresh download
// - Long cache headers possible (immutable)
```
## Build Performance Optimization
### Caching
```javascript
// Webpack persistent caching
cache: {
type: 'filesystem',
buildDependencies: {
config: [__filename], // Invalidate on config change
},
}
// First build: 30 seconds
// Subsequent builds: 5 seconds (cache hit)
```
### Parallelization
```javascript
// Webpack thread-loader for expensive loaders
{
test: /\.tsx?$/,
use: [
'thread-loader', // Run in worker pool
'babel-loader',
],
}
// esbuild/SWC are parallel by default (Rust/Go)
```
### Excluding node_modules
```javascript
// Don't transform node_modules (already compiled)
{
test: /\.js$/,
exclude: /node_modules/,
use: 'babel-loader',
}
```
## Build Analysis
Understanding your bundle contents.
```bash
# Webpack Bundle Analyzer
npm install --save-dev webpack-bundle-analyzer
# Add to webpack config:
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
plugins: [
new BundleAnalyzerPlugin()
]
# Generates interactive treemap of bundle contents
```
```
# source-map-explorer
npx source-map-explorer dist/main.js
# Vite
npx vite-bundle-visualizer
```
---
## Deep Dive: Understanding Bundling From First Principles
### What Bundlers Actually Do: Step by Step
Let's trace through exactly what happens when you run `npm run build`:
```javascript
// YOUR SOURCE FILES:
// src/index.js
import { greet } from './utils.js';
import React from 'react';
console.log(greet('World'));
// src/utils.js
export function greet(name) {
return `Hello, ${name}!`;
}
export function unused() {
return 'Never called';
}
```
**Step 1: Parse Entry Point**
```javascript
// Bundler parses index.js into AST (Abstract Syntax Tree)
{
type: 'Program',
body: [
{
type: 'ImportDeclaration',
source: { value: './utils.js' },
specifiers: [{ imported: { name: 'greet' } }]
},
{
type: 'ImportDeclaration',
source: { value: 'react' },
specifiers: [{ imported: { name: 'default' }, local: { name: 'React' } }]
},
// ... rest of AST
]
}
```
**Step 2: Resolve Dependencies**
```javascript
// For each import, resolve to actual file path
// './utils.js'
// → Current dir: /project/src/
// → Resolved: /project/src/utils.js ✓
// 'react'
// → Not relative, check node_modules
// → /project/node_modules/react/package.json
// → "main": "index.js"
// → Resolved: /project/node_modules/react/index.js ✓
```
**Step 3: Build Dependency Graph**
```javascript
// Graph structure (simplified)
const graph = {
'/project/src/index.js': {
dependencies: [
'/project/src/utils.js',
'/project/node_modules/react/index.js'
],
code: '...',
exports: [],
imports: ['greet', 'React']
},
'/project/src/utils.js': {
dependencies: [],
code: '...',
exports: ['greet', 'unused'],
imports: []
},
// ... react and its dependencies
};
```
**Step 4: Transform Code**
```javascript
// Each file goes through loaders/plugins
// TypeScript → JavaScript
// TSX/JSX → React.createElement calls
// Modern JS → Compatible JS (Babel)
// Input (TSX):
const Button: React.FC = () => ;
// Output (JS):
const Button = () => React.createElement("button", null, "Click");
```
**Step 5: Tree Shake**
```javascript
// Analyze what's actually used
// utils.js exports: ['greet', 'unused']
// index.js imports from utils: ['greet']
//
// 'unused' is never imported anywhere
// Mark for removal
// After tree shaking, only 'greet' is included
```
**Step 6: Concatenate Modules**
```javascript
// Combine all modules into bundle format
// IIFE wrapper (Immediately Invoked Function Expression)
(function(modules) {
// Module cache
var installedModules = {};
// Module loader
function __webpack_require__(moduleId) {
if (installedModules[moduleId]) {
return installedModules[moduleId].exports;
}
var module = installedModules[moduleId] = { exports: {} };
modules[moduleId](module, module.exports, __webpack_require__);
return module.exports;
}
// Start at entry point
return __webpack_require__('./src/index.js');
})({
'./src/index.js': function(module, exports, __webpack_require__) {
var utils = __webpack_require__('./src/utils.js');
var React = __webpack_require__('react');
console.log(utils.greet('World'));
},
'./src/utils.js': function(module, exports) {
exports.greet = function(name) {
return 'Hello, ' + name + '!';
};
// Note: unused() is gone!
},
// ... react modules
});
```
**Step 7: Minify**
```javascript
// Terser/esbuild minification
// Before:
function greet(name) {
return 'Hello, ' + name + '!';
}
// After:
function greet(n){return"Hello, "+n+"!"}
// Or with further optimization:
const greet=n=>"Hello, "+n+"!";
```
**Step 8: Output with Hashing**
```
dist/
├── index.html
├── main.7f8a2b3c.js ← Hash based on content
├── main.7f8a2b3c.js.map ← Source map
└── index.html ← References hashed files
```
### Module Formats: A History Lesson
Understanding why we have multiple module systems:
```javascript
// 1. NO MODULES (Pre-2009)
// Everything in global scope
// script.js
var myApp = {};
myApp.utils = {
greet: function(name) { return 'Hello, ' + name; }
};
// Problem: Global namespace pollution, dependency order matters
// 2. COMMONJS (2009, Node.js)
// Synchronous, designed for servers
// utils.js
module.exports.greet = function(name) { return 'Hello, ' + name; };
// index.js
const { greet } = require('./utils');
// Problem: Synchronous require() doesn't work in browsers
// 3. AMD - Asynchronous Module Definition (2011, RequireJS)
// Async loading for browsers
define(['./utils'], function(utils) {
console.log(utils.greet('World'));
});
// Problem: Verbose, non-standard
// 4. UMD - Universal Module Definition (2014)
// Works everywhere (browser global, CommonJS, AMD)
(function(root, factory) {
if (typeof define === 'function' && define.amd) {
define(['dep'], factory); // AMD
} else if (typeof module === 'object') {
module.exports = factory(require('dep')); // CommonJS
} else {
root.myLib = factory(root.dep); // Browser global
}
}(this, function(dep) {
return { greet: function(name) { return 'Hello, ' + name; } };
}));
// Problem: Complex wrapper for every file
// 5. ES MODULES (2015, ES6)
// Official JavaScript standard
// Static structure enables tree shaking
export function greet(name) { return 'Hello, ' + name; }
import { greet } from './utils.js';
// Now supported natively in browsers and Node.js!
```
### Why Vite is Fast: Native ES Modules
Traditional bundlers (Webpack) vs Vite approach:
```
WEBPACK DEVELOPMENT:
Your Code Webpack Browser
────────────────────────────────────────────────────────────────
src/
├── index.js ─┐
├── App.js ├─► Bundle ALL ─► bundle.js ─────► Load bundle
├── Header.js │ files
└── 100+ more ─┘ together
Time: Parse + transform + bundle ALL files = 10-30 seconds
Change 1 file → Rebundle everything = 2-5 seconds
VITE DEVELOPMENT:
Your Code Vite Browser
────────────────────────────────────────────────────────────────
src/
├── index.js ──────────────────────────────────► Request each
├── App.js ─► Transform ─► Serve directly ──► file when needed
├── Header.js on demand via native ES
└── 100+ more ─► (only if requested) module imports
Time: Transform only requested files = 300-500ms
Change 1 file → Transform only that file = <100ms
WHY THIS WORKS:
// index.js (served directly, not bundled)
import { App } from './App.js'; // Browser makes another request
// Browser's network tab:
// GET /src/index.js
// GET /src/App.js (from import in index.js)
// GET /src/Header.js (from import in App.js)
// ...
```
### Dynamic Imports: How Code Splitting Works
The magic behind `import()`:
```javascript
// STATIC IMPORT (resolved at build time)
import { heavy } from './heavy.js';
// Always included in main bundle
// DYNAMIC IMPORT (resolved at runtime)
const heavy = await import('./heavy.js');
// Creates a separate chunk, loaded on demand
```
**What the bundler does:**
```javascript
// Your code:
button.onclick = async () => {
const { HeavyComponent } = await import('./HeavyComponent.js');
render(HeavyComponent);
};
// Bundler output:
// main.js
button.onclick = async () => {
const { HeavyComponent } = await __webpack_require__.e("HeavyComponent")
.then(__webpack_require__.bind(__webpack_require__, "./HeavyComponent.js"));
render(HeavyComponent);
};
// HeavyComponent.a1b2c3.chunk.js (separate file)
(self["webpackChunk"] = self["webpackChunk"] || []).push([
["HeavyComponent"],
{
"./HeavyComponent.js": (module, exports) => {
exports.HeavyComponent = function() { /* ... */ };
}
}
]);
// At runtime:
// 1. User clicks button
// 2. __webpack_require__.e creates `
);
},
};
}
```
### Implementing Code Splitting Logic
```javascript
// CUSTOM CODE SPLITTING STRATEGY
class ChunkSplitter {
constructor(options = {}) {
this.options = {
minChunkSize: options.minChunkSize || 20000,
maxChunkSize: options.maxChunkSize || 250000,
vendorPattern: options.vendorPattern || /node_modules/,
};
this.chunks = new Map();
}
// Analyze module graph
analyzeGraph(modules) {
const graph = {
nodes: new Map(),
edges: new Map(),
};
for (const mod of modules) {
graph.nodes.set(mod.id, {
id: mod.id,
size: mod.code.length,
isVendor: this.options.vendorPattern.test(mod.id),
imports: mod.imports,
importedBy: [],
});
}
// Build reverse edges
for (const [id, node] of graph.nodes) {
for (const imp of node.imports) {
const target = graph.nodes.get(imp);
if (target) {
target.importedBy.push(id);
}
}
}
return graph;
}
// Determine chunks
splitChunks(graph, entries) {
const chunks = [];
// Create vendor chunk
const vendorModules = [...graph.nodes.values()]
.filter(n => n.isVendor);
if (vendorModules.length > 0) {
chunks.push({
name: 'vendor',
modules: vendorModules.map(n => n.id),
});
}
// Create chunks per entry
for (const entry of entries) {
const reachable = this.getReachableModules(graph, entry);
const nonVendor = reachable.filter(id => !graph.nodes.get(id)?.isVendor);
// Split large chunks
const subChunks = this.splitBySize(nonVendor, graph);
chunks.push(...subChunks.map((mods, i) => ({
name: `${entry}-${i}`,
modules: mods,
})));
}
// Find shared chunks
const sharedChunks = this.findSharedChunks(chunks, graph);
chunks.push(...sharedChunks);
return chunks;
}
getReachableModules(graph, entry) {
const visited = new Set();
const queue = [entry];
while (queue.length > 0) {
const id = queue.shift();
if (visited.has(id)) continue;
visited.add(id);
const node = graph.nodes.get(id);
if (node) {
queue.push(...node.imports);
}
}
return [...visited];
}
findSharedChunks(chunks, graph) {
// Find modules used by multiple chunks
const moduleUsage = new Map();
for (const chunk of chunks) {
for (const modId of chunk.modules) {
if (!moduleUsage.has(modId)) {
moduleUsage.set(modId, []);
}
moduleUsage.get(modId).push(chunk.name);
}
}
// Extract frequently shared modules
const shared = [];
for (const [modId, usedBy] of moduleUsage) {
if (usedBy.length >= 2) {
shared.push(modId);
}
}
if (shared.length > 0) {
return [{ name: 'shared', modules: shared }];
}
return [];
}
}
```
### Building a Module Transformer
```javascript
// AST-BASED MODULE TRANSFORMER
import * as acorn from 'acorn';
import * as walk from 'acorn-walk';
import MagicString from 'magic-string';
class ModuleTransformer {
transform(code, options = {}) {
const ast = acorn.parse(code, {
ecmaVersion: 'latest',
sourceType: 'module',
});
const s = new MagicString(code);
// Transform imports
walk.simple(ast, {
ImportDeclaration(node) {
const source = node.source.value;
// Resolve bare imports
if (!source.startsWith('.') && !source.startsWith('/')) {
const resolved = resolveNodeModule(source);
s.overwrite(
node.source.start,
node.source.end,
`"${resolved}"`
);
}
},
// Transform dynamic imports
ImportExpression(node) {
const source = node.source;
if (source.type === 'Literal') {
const resolved = resolvePath(source.value);
s.overwrite(source.start, source.end, `"${resolved}"`);
}
},
// Transform exports for HMR
ExportDefaultDeclaration(node) {
if (options.hmr) {
const decl = node.declaration;
s.appendLeft(decl.start, '__hmr_wrap(');
s.appendRight(decl.end, ')');
}
},
});
return {
code: s.toString(),
map: s.generateMap({ hires: true }),
};
}
}
// Import analysis
function analyzeImports(code) {
const ast = acorn.parse(code, { ecmaVersion: 'latest', sourceType: 'module' });
const imports = [];
const exports = [];
walk.simple(ast, {
ImportDeclaration(node) {
imports.push({
source: node.source.value,
specifiers: node.specifiers.map(s => ({
type: s.type,
imported: s.imported?.name || 'default',
local: s.local.name,
})),
});
},
ExportNamedDeclaration(node) {
if (node.declaration) {
if (node.declaration.type === 'VariableDeclaration') {
for (const decl of node.declaration.declarations) {
exports.push({ name: decl.id.name, type: 'named' });
}
} else if (node.declaration.id) {
exports.push({ name: node.declaration.id.name, type: 'named' });
}
}
},
ExportDefaultDeclaration() {
exports.push({ name: 'default', type: 'default' });
},
});
return { imports, exports };
}
```
### Implementing Source Maps
```javascript
// SOURCE MAP GENERATION
class SourceMapGenerator {
constructor() {
this.mappings = [];
this.sources = [];
this.sourcesContent = [];
this.names = [];
}
addSource(filename, content) {
const index = this.sources.indexOf(filename);
if (index !== -1) return index;
this.sources.push(filename);
this.sourcesContent.push(content);
return this.sources.length - 1;
}
addMapping(generated, original, sourceIndex, name) {
this.mappings.push({
generatedLine: generated.line,
generatedColumn: generated.column,
originalLine: original.line,
originalColumn: original.column,
sourceIndex,
nameIndex: name ? this.addName(name) : undefined,
});
}
addName(name) {
const index = this.names.indexOf(name);
if (index !== -1) return index;
this.names.push(name);
return this.names.length - 1;
}
generate() {
// Sort mappings
this.mappings.sort((a, b) =>
a.generatedLine - b.generatedLine ||
a.generatedColumn - b.generatedColumn
);
// Encode mappings to VLQ
const encodedMappings = this.encodeMappings();
return {
version: 3,
sources: this.sources,
sourcesContent: this.sourcesContent,
names: this.names,
mappings: encodedMappings,
};
}
encodeMappings() {
let result = '';
let previousGeneratedLine = 1;
let previousGeneratedColumn = 0;
let previousOriginalLine = 0;
let previousOriginalColumn = 0;
let previousSourceIndex = 0;
let previousNameIndex = 0;
for (let i = 0; i < this.mappings.length; i++) {
const mapping = this.mappings[i];
// New lines
while (previousGeneratedLine < mapping.generatedLine) {
result += ';';
previousGeneratedLine++;
previousGeneratedColumn = 0;
}
if (i > 0 && this.mappings[i - 1].generatedLine === mapping.generatedLine) {
result += ',';
}
// Encode segment
let segment = this.encodeVLQ(mapping.generatedColumn - previousGeneratedColumn);
previousGeneratedColumn = mapping.generatedColumn;
segment += this.encodeVLQ(mapping.sourceIndex - previousSourceIndex);
previousSourceIndex = mapping.sourceIndex;
segment += this.encodeVLQ(mapping.originalLine - previousOriginalLine);
previousOriginalLine = mapping.originalLine;
segment += this.encodeVLQ(mapping.originalColumn - previousOriginalColumn);
previousOriginalColumn = mapping.originalColumn;
if (mapping.nameIndex !== undefined) {
segment += this.encodeVLQ(mapping.nameIndex - previousNameIndex);
previousNameIndex = mapping.nameIndex;
}
result += segment;
}
return result;
}
encodeVLQ(value) {
const VLQ_BASE64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
let encoded = '';
let vlq = value < 0 ? ((-value) << 1) + 1 : value << 1;
do {
let digit = vlq & 0x1f;
vlq >>>= 5;
if (vlq > 0) digit |= 0x20;
encoded += VLQ_BASE64[digit];
} while (vlq > 0);
return encoded;
}
}
```
## Related Skills
- See [meta-frameworks-overview](../meta-frameworks-overview/SKILL.md) for framework build setups
- See [rendering-patterns](../rendering-patterns/SKILL.md) for how bundles affect rendering
- See [hydration-patterns](../hydration-patterns/SKILL.md) for code splitting and hydration