--- 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