Tools
Tools: Vite Internals Deep Dive: How Modern Build Tools Actually Work
2026-02-09
0 views
admin
Table of Contents ## The Evolution: Why Webpack Dominated ## The Pre-Bundler Era (2010-2014) ## CommonJS and the Node.js Influence ## Enter Webpack (2012) ## Why Webpack Became Slow ## Webpack's Internal Architecture ## Phase 1: Entry and Dependency Resolution ## Phase 2: Loader Pipeline ## Phase 3: Chunk Generation ## Phase 4: Bundle Assembly ## The Dev Server: webpack-dev-server ## Vite's Paradigm Shift: No-Bundle Development ## The Enabling Technology: ES Modules (ESM) ## Vite's Architecture: Server-Side Transformation ## Vite Internals: Request-Time Transformation ## The Vite Dev Server ## Pre-Bundling Dependencies (esbuild) ## The Transform Pipeline ## Import Analysis and Rewriting ## CSS Handling ## Static Asset Handling ## HMR Protocol: Webpack vs Vite ## Webpack HMR Internals ## Vite HMR Internals ## React Fast Refresh Integration ## Production Builds: Why Vite Still Bundles ## Why Bundle for Production? ## Vite's Production Build: Rollup ## The Build Pipeline ## Why Not Bundle During Dev? ## npm Deep Dive: Dependency Resolution Algorithm ## The Dependency Resolution Problem ## npm Install Internals: Step-by-Step ## Step 1: Read package.json ## Step 2: Fetch Package Metadata ## Step 3: Version Range Resolution ## Step 4: Build Dependency Tree ## Step 5: Download Packages ## Step 6: Extract and Link ## Step 7: Run Lifecycle Scripts ## Step 8: Generate package-lock.json ## npm ci: Faster, Stricter Installs ## Peer Dependencies: Special Case ## The Complete Stack: How Everything Connects ## The Layers ## Workflow Timeline ## Relationship Matrix ## Performance Benchmarks and Real-World Impact ## Cold Start Time ## HMR Update Speed ## Production Build Size ## Real-World Impact ## Advanced Topics and Edge Cases ## Module Federation ## CSS-in-JS and Build Tools ## Server-Side Rendering (SSR) ## Migration Guide: Webpack → Vite ## Can You Migrate? ## Migration Steps ## Common Gotchas ## The Future: Where Are Build Tools Going? ## Trends ## Should You Learn Webpack Still? ## Conclusion: Mental Models Matter ## Further Reading ## About the Author Modern frontend development appears deceptively simple. You run npm install, execute npm run dev, and suddenly you have a blazing-fast development server. But what's actually happening beneath this abstraction? This article goes beyond surface-level comparisons. We'll dissect: This is not a beginner's guide. This is about understanding the mental models and implementation details that separate good developers from great ones. Before we criticize Webpack, we need to understand the problem it solved. Early web development had no module system: Problems with this approach: Node.js introduced require() and module.exports: The problem? Browsers didn't understand require(). Webpack solved the fundamental problem: "How do we use Node-style modules in the browser?" The solution was static analysis and bundling: This was revolutionary. Suddenly, you could write: And Webpack would handle everything — JS, CSS, images, fonts — through loaders. Webpack's strength became its weakness as applications grew: The Bundle-First Approach: Key bottleneck: Even if you change one file, Webpack has to: In large apps, this means 10-30 second cold starts and 1-5 second HMR updates. To understand why Vite is different, let's look at Webpack's core architecture. Webpack starts from entry points defined in webpack.config.js: What happens internally: This creates a Module Graph — a directed graph where: Each file type goes through its loader chain: Internal flow for a .jsx file: Critical insight: Loaders run synchronously during the build phase. Processing 1000 files means 1000 synchronous transformations. Webpack splits the bundle into chunks based on: Why this is expensive: Webpack analyzes all possible code paths to optimize chunk splitting. This requires: Finally, Webpack creates the actual bundle: During development, Webpack uses webpack-dev-server: What happens when you change a file: The problem: Even with caching and optimizations, Webpack still does significant work on every change. Vite asked a radical question: "What if we don't bundle during development at all?" Modern browsers natively support: Key insight: Browsers can load modules on demand via HTTP. Vite leverages this to flip the entire development model. Instead of bundling upfront, Vite: This is fundamentally different from Webpack's approach. Let's dive into Vite's actual implementation. When you run npm run dev, Vite starts a Koa-based HTTP server with custom middleware: Before serving files, Vite does one-time pre-bundling of dependencies: Result: Dependencies like react become single ESM files in .vite/deps/. Key difference from Webpack: This happens once on startup, not on every file change. When a file is requested, Vite applies transformations: Example transformation: After Vite transformation: Critical observations: Vite rewrites all import paths to be browser-compatible: Browsers need absolute or relative URLs. Module specifiers like 'react' don't work. CSS imports are transformed into JS: Result: CSS is injected as <style> tags by Vite's client-side code. Images and other assets get special URLs: Vite serves these files directly and handles them in production with content hashing. Hot Module Replacement is where Vite truly shines. Browser-side handling: Both tools integrate React Fast Refresh, but Vite's implementation is cleaner: Result: Component state is preserved across most changes. An important clarification: Vite only skips bundling during development. Even with HTTP/2 and HTTP/3, unbundled modules have issues: For production, Vite uses Rollup: Rollup optimizations: This is the key insight: Development priorities: Production priorities: Vite optimizes for each context separately — this is its core philosophy. npm is often taken for granted, but it's solving one of the hardest problems in software: dependency hell. Consider this scenario: Both package-a and package-b depend on package-c: The question: Which version of package-c should be installed? This is dependency resolution. When you run npm install, this happens: npm queries the registry (https://registry.npmjs.org/): npm uses semver to resolve version ranges: Common range specifiers: npm builds a tree structure: Deduplication algorithm: npm tries to hoist packages to the top level: If version ranges conflict, npm nests packages: npm downloads .tgz files from the registry: Files are cached in ~/.npm: Cache key: Based on package + version + integrity hash Future installs use the cache: npm extracts packages into node_modules: Packages with bin fields get linked to node_modules/.bin: npm creates symlinks: This is why npm run dev works without global installs. npm runs install scripts: Security note: This is why untrusted packages can be dangerous — install scripts run arbitrary code. npm creates a lockfile: Both get exactly the same versions. For CI/CD, use npm ci: Differences from npm install: Result: 2-3x faster in CI environments. Some packages declare peerDependencies: Meaning: "I need React 18.2.0, but don't install it for me — the user should install it." Prevents duplicate React instances: With peer dependencies: Now let's connect all the pieces. Adding a new dependency: Key insight: Each tool operates at a different abstraction layer. Let's look at actual numbers. Test: Start dev server for a 1000-component React app Breakdown of Vite's 1.2s: Test: Edit a component deep in the tree Test: Same 1000-component app, optimized build Both use tree shaking and minification. The real difference is dev experience, not production output. Developer productivity: When Webpack makes sense: When Vite makes sense: Webpack's killer feature: Allows runtime code sharing between separate apps. Vite has experimental module federation support via plugins, but it's not as mature. Vite handles CSS-in-JS differently: Both support SSR, but differently: Vite's SSR is simpler because it uses the same transformation pipeline for client and server. Move index.html to project root and add: Webpack allows importing CSS anywhere. Vite requires explicit imports or <link> tags. Vite doesn't polyfill Node.js modules. Use vite-plugin-node-polyfills if needed. Speed gains: Rust is 10-100x faster than JavaScript for parsing/transforming. 2. ESM-first development More tools adopting Vite's no-bundle approach: 3. Framework-specific bundlers Frameworks are integrating build tools more tightly. Build tools optimizing for edge runtimes: Requires different bundling strategies. Reality: Most developers will work with both throughout their careers. The tools you use shape how you think about problems. Whether you use Webpack, Vite, or the next hot tool, the principles remain: Because in the end, tools are just tools. The way you think is what makes you great. This article was written to help developers build better mental models of their tools. If you found it helpful, consider sharing it with others who might benefit. Got questions or corrections? Drop a comment below — I read and respond to all of them. Templates let you quickly answer FAQs or store snippets for re-use. Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment's permalink. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse CODE_BLOCK:
<!-- The old way -->
<script src="jquery.js"></script>
<script src="bootstrap.js"></script>
<script src="app.js"></script> Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
<!-- The old way -->
<script src="jquery.js"></script>
<script src="bootstrap.js"></script>
<script src="app.js"></script> CODE_BLOCK:
<!-- The old way -->
<script src="jquery.js"></script>
<script src="bootstrap.js"></script>
<script src="app.js"></script> COMMAND_BLOCK:
// math.js
module.exports.add = (a, b) => a + b; // app.js
const math = require('./math');
console.log(math.add(2, 3)); Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
// math.js
module.exports.add = (a, b) => a + b; // app.js
const math = require('./math');
console.log(math.add(2, 3)); COMMAND_BLOCK:
// math.js
module.exports.add = (a, b) => a + b; // app.js
const math = require('./math');
console.log(math.add(2, 3)); CODE_BLOCK:
import React from 'react';
import './styles.css';
import logo from './logo.png'; Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
import React from 'react';
import './styles.css';
import logo from './logo.png'; CODE_BLOCK:
import React from 'react';
import './styles.css';
import logo from './logo.png'; CODE_BLOCK:
Source Files (1000+) ↓ Webpack Reads All Files ↓ Applies Loaders (Babel, etc.) ↓ Generates Dependency Graph ↓ Creates Bundle ↓ Serves to Browser Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
Source Files (1000+) ↓ Webpack Reads All Files ↓ Applies Loaders (Babel, etc.) ↓ Generates Dependency Graph ↓ Creates Bundle ↓ Serves to Browser CODE_BLOCK:
Source Files (1000+) ↓ Webpack Reads All Files ↓ Applies Loaders (Babel, etc.) ↓ Generates Dependency Graph ↓ Creates Bundle ↓ Serves to Browser CODE_BLOCK:
module.exports = { entry: './src/index.js', // ...
}; Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
module.exports = { entry: './src/index.js', // ...
}; CODE_BLOCK:
module.exports = { entry: './src/index.js', // ...
}; CODE_BLOCK:
module: { rules: [ { test: /\.jsx?$/, use: ['babel-loader'] }, { test: /\.css$/, use: ['style-loader', 'css-loader'] } ]
} Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
module: { rules: [ { test: /\.jsx?$/, use: ['babel-loader'] }, { test: /\.css$/, use: ['style-loader', 'css-loader'] } ]
} CODE_BLOCK:
module: { rules: [ { test: /\.jsx?$/, use: ['babel-loader'] }, { test: /\.css$/, use: ['style-loader', 'css-loader'] } ]
} CODE_BLOCK:
button.jsx (source) ↓
babel-loader (JSX → JS) ↓
Transformed JS ↓
Added to compilation Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
button.jsx (source) ↓
babel-loader (JSX → JS) ↓
Transformed JS ↓
Added to compilation CODE_BLOCK:
button.jsx (source) ↓
babel-loader (JSX → JS) ↓
Transformed JS ↓
Added to compilation CODE_BLOCK:
optimization: { splitChunks: { chunks: 'all', }
} Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
optimization: { splitChunks: { chunks: 'all', }
} CODE_BLOCK:
optimization: { splitChunks: { chunks: 'all', }
} CODE_BLOCK:
// Simplified Webpack runtime
(function(modules) { function __webpack_require__(moduleId) { // Module loading logic var module = { exports: {} }; modules[moduleId](module, module.exports, __webpack_require__); return module.exports; } return __webpack_require__(0); // Entry point
})([ // Module 0 function(module, exports, __webpack_require__) { // Your transformed code }, // Module 1, 2, 3...
]); Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
// Simplified Webpack runtime
(function(modules) { function __webpack_require__(moduleId) { // Module loading logic var module = { exports: {} }; modules[moduleId](module, module.exports, __webpack_require__); return module.exports; } return __webpack_require__(0); // Entry point
})([ // Module 0 function(module, exports, __webpack_require__) { // Your transformed code }, // Module 1, 2, 3...
]); CODE_BLOCK:
// Simplified Webpack runtime
(function(modules) { function __webpack_require__(moduleId) { // Module loading logic var module = { exports: {} }; modules[moduleId](module, module.exports, __webpack_require__); return module.exports; } return __webpack_require__(0); // Entry point
})([ // Module 0 function(module, exports, __webpack_require__) { // Your transformed code }, // Module 1, 2, 3...
]); CODE_BLOCK:
const webpack = require('webpack');
const WebpackDevServer = require('webpack-dev-server'); const compiler = webpack(config);
const server = new WebpackDevServer(compiler, { hot: true, // Enable HMR
}); server.listen(3000); Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
const webpack = require('webpack');
const WebpackDevServer = require('webpack-dev-server'); const compiler = webpack(config);
const server = new WebpackDevServer(compiler, { hot: true, // Enable HMR
}); server.listen(3000); CODE_BLOCK:
const webpack = require('webpack');
const WebpackDevServer = require('webpack-dev-server'); const compiler = webpack(config);
const server = new WebpackDevServer(compiler, { hot: true, // Enable HMR
}); server.listen(3000); CODE_BLOCK:
// index.html
<script type="module"> import { add } from './math.js'; console.log(add(2, 3));
</script> Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
// index.html
<script type="module"> import { add } from './math.js'; console.log(add(2, 3));
</script> CODE_BLOCK:
// index.html
<script type="module"> import { add } from './math.js'; console.log(add(2, 3));
</script> CODE_BLOCK:
Browser requests /src/App.jsx ↓
Vite intercepts request ↓
Transforms JSX → JS (using esbuild) ↓
Returns transformed JS ↓
Browser executes and requests more imports Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
Browser requests /src/App.jsx ↓
Vite intercepts request ↓
Transforms JSX → JS (using esbuild) ↓
Returns transformed JS ↓
Browser executes and requests more imports CODE_BLOCK:
Browser requests /src/App.jsx ↓
Vite intercepts request ↓
Transforms JSX → JS (using esbuild) ↓
Returns transformed JS ↓
Browser executes and requests more imports CODE_BLOCK:
// Simplified Vite server structure
import { createServer } from 'vite'; const server = await createServer({ // config
}); await server.listen(5173); Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
// Simplified Vite server structure
import { createServer } from 'vite'; const server = await createServer({ // config
}); await server.listen(5173); CODE_BLOCK:
// Simplified Vite server structure
import { createServer } from 'vite'; const server = await createServer({ // config
}); await server.listen(5173); COMMAND_BLOCK:
# You'll see this in console
Pre-bundling dependencies: react react-dom lodash ... Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
# You'll see this in console
Pre-bundling dependencies: react react-dom lodash ... COMMAND_BLOCK:
# You'll see this in console
Pre-bundling dependencies: react react-dom lodash ... CODE_BLOCK:
// Vite uses esbuild to bundle dependencies
import { build } from 'esbuild'; await build({ entryPoints: ['react', 'react-dom'], bundle: true, format: 'esm', outdir: 'node_modules/.vite/deps',
}); Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
// Vite uses esbuild to bundle dependencies
import { build } from 'esbuild'; await build({ entryPoints: ['react', 'react-dom'], bundle: true, format: 'esm', outdir: 'node_modules/.vite/deps',
}); CODE_BLOCK:
// Vite uses esbuild to bundle dependencies
import { build } from 'esbuild'; await build({ entryPoints: ['react', 'react-dom'], bundle: true, format: 'esm', outdir: 'node_modules/.vite/deps',
}); CODE_BLOCK:
/src/App.jsx requested ↓
1. Load file from filesystem ↓
2. Apply plugins (transform hooks) ↓
3. esbuild transforms JSX → JS ↓
4. Inject HMR code ↓
5. Rewrite import paths ↓
Return transformed code Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
/src/App.jsx requested ↓
1. Load file from filesystem ↓
2. Apply plugins (transform hooks) ↓
3. esbuild transforms JSX → JS ↓
4. Inject HMR code ↓
5. Rewrite import paths ↓
Return transformed code CODE_BLOCK:
/src/App.jsx requested ↓
1. Load file from filesystem ↓
2. Apply plugins (transform hooks) ↓
3. esbuild transforms JSX → JS ↓
4. Inject HMR code ↓
5. Rewrite import paths ↓
Return transformed code CODE_BLOCK:
// Source: /src/App.jsx
import { useState } from 'react';
import './App.css'; export default function App() { return <div>Hello</div>;
} Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
// Source: /src/App.jsx
import { useState } from 'react';
import './App.css'; export default function App() { return <div>Hello</div>;
} CODE_BLOCK:
// Source: /src/App.jsx
import { useState } from 'react';
import './App.css'; export default function App() { return <div>Hello</div>;
} COMMAND_BLOCK:
import { useState } from '/@fs/Users/project/node_modules/.vite/deps/react.js';
import './App.css?import'; // CSS is handled specially export default function App() { return /*#__PURE__*/ React.createElement('div', null, 'Hello');
} // HMR code injected
import.meta.hot.accept((mod) => { // Fast Refresh logic
}); Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
import { useState } from '/@fs/Users/project/node_modules/.vite/deps/react.js';
import './App.css?import'; // CSS is handled specially export default function App() { return /*#__PURE__*/ React.createElement('div', null, 'Hello');
} // HMR code injected
import.meta.hot.accept((mod) => { // Fast Refresh logic
}); COMMAND_BLOCK:
import { useState } from '/@fs/Users/project/node_modules/.vite/deps/react.js';
import './App.css?import'; // CSS is handled specially export default function App() { return /*#__PURE__*/ React.createElement('div', null, 'Hello');
} // HMR code injected
import.meta.hot.accept((mod) => { // Fast Refresh logic
}); CODE_BLOCK:
// Original
import React from 'react'; // Rewritten by Vite
import React from '/@fs/Users/project/node_modules/.vite/deps/react.js'; Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
// Original
import React from 'react'; // Rewritten by Vite
import React from '/@fs/Users/project/node_modules/.vite/deps/react.js'; CODE_BLOCK:
// Original
import React from 'react'; // Rewritten by Vite
import React from '/@fs/Users/project/node_modules/.vite/deps/react.js'; CODE_BLOCK:
// Source
import './App.css'; // Vite transforms to
import { createStyle } from '/@vite/client';
createStyle( 'css-content-here', '/src/App.css'
); Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
// Source
import './App.css'; // Vite transforms to
import { createStyle } from '/@vite/client';
createStyle( 'css-content-here', '/src/App.css'
); CODE_BLOCK:
// Source
import './App.css'; // Vite transforms to
import { createStyle } from '/@vite/client';
createStyle( 'css-content-here', '/src/App.css'
); CODE_BLOCK:
import logo from './logo.png'; // Becomes
const logo = '/src/logo.png?import'; Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
import logo from './logo.png'; // Becomes
const logo = '/src/logo.png?import'; CODE_BLOCK:
import logo from './logo.png'; // Becomes
const logo = '/src/logo.png?import'; CODE_BLOCK:
{ "h": "abc123", // hash "c": { "main": true // chunks that changed }
} Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
{ "h": "abc123", // hash "c": { "main": true // chunks that changed }
} CODE_BLOCK:
{ "h": "abc123", // hash "c": { "main": true // chunks that changed }
} CODE_BLOCK:
// main.abc123.hot-update.js
webpackHotUpdate("main", { "./src/App.jsx": function(module, exports, __webpack_require__) { // New module code }
}); Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
// main.abc123.hot-update.js
webpackHotUpdate("main", { "./src/App.jsx": function(module, exports, __webpack_require__) { // New module code }
}); CODE_BLOCK:
// main.abc123.hot-update.js
webpackHotUpdate("main", { "./src/App.jsx": function(module, exports, __webpack_require__) { // New module code }
}); CODE_BLOCK:
{ "type": "update", "updates": [{ "type": "js-update", "path": "/src/App.jsx", "acceptedPath": "/src/App.jsx", "timestamp": 1704067200000 }]
} Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
{ "type": "update", "updates": [{ "type": "js-update", "path": "/src/App.jsx", "acceptedPath": "/src/App.jsx", "timestamp": 1704067200000 }]
} CODE_BLOCK:
{ "type": "update", "updates": [{ "type": "js-update", "path": "/src/App.jsx", "acceptedPath": "/src/App.jsx", "timestamp": 1704067200000 }]
} COMMAND_BLOCK:
// Vite's HMR client
socket.addEventListener('message', ({ data }) => { const payload = JSON.parse(data); if (payload.type === 'update') { payload.updates.forEach(update => { // Re-import the module import(`${update.path}?t=${update.timestamp}`) .then(mod => { // React Fast Refresh handles component updates }); }); }
}); Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
// Vite's HMR client
socket.addEventListener('message', ({ data }) => { const payload = JSON.parse(data); if (payload.type === 'update') { payload.updates.forEach(update => { // Re-import the module import(`${update.path}?t=${update.timestamp}`) .then(mod => { // React Fast Refresh handles component updates }); }); }
}); COMMAND_BLOCK:
// Vite's HMR client
socket.addEventListener('message', ({ data }) => { const payload = JSON.parse(data); if (payload.type === 'update') { payload.updates.forEach(update => { // Re-import the module import(`${update.path}?t=${update.timestamp}`) .then(mod => { // React Fast Refresh handles component updates }); }); }
}); COMMAND_BLOCK:
// Injected into every JSX file
import RefreshRuntime from '/@react-refresh'; RefreshRuntime.injectIntoGlobalHook(window);
window.$RefreshReg$ = () => {};
window.$RefreshSig$ = () => (type) => type; // After component definition
RefreshRuntime.register(App, 'App'); // HMR boundary
import.meta.hot.accept((mod) => { RefreshRuntime.performReactRefresh();
}); Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
// Injected into every JSX file
import RefreshRuntime from '/@react-refresh'; RefreshRuntime.injectIntoGlobalHook(window);
window.$RefreshReg$ = () => {};
window.$RefreshSig$ = () => (type) => type; // After component definition
RefreshRuntime.register(App, 'App'); // HMR boundary
import.meta.hot.accept((mod) => { RefreshRuntime.performReactRefresh();
}); COMMAND_BLOCK:
// Injected into every JSX file
import RefreshRuntime from '/@react-refresh'; RefreshRuntime.injectIntoGlobalHook(window);
window.$RefreshReg$ = () => {};
window.$RefreshSig$ = () => (type) => type; // After component definition
RefreshRuntime.register(App, 'App'); // HMR boundary
import.meta.hot.accept((mod) => { RefreshRuntime.performReactRefresh();
}); COMMAND_BLOCK:
npm run build Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
npm run build COMMAND_BLOCK:
npm run build CODE_BLOCK:
// Internally, Vite calls Rollup
import { build } from 'rollup'; await build({ input: 'src/main.jsx', plugins: [ vitePlugins(), ], output: { dir: 'dist', format: 'es', }
}); Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
// Internally, Vite calls Rollup
import { build } from 'rollup'; await build({ input: 'src/main.jsx', plugins: [ vitePlugins(), ], output: { dir: 'dist', format: 'es', }
}); CODE_BLOCK:
// Internally, Vite calls Rollup
import { build } from 'rollup'; await build({ input: 'src/main.jsx', plugins: [ vitePlugins(), ], output: { dir: 'dist', format: 'es', }
}); CODE_BLOCK:
Source Files ↓
Vite Plugins (transform) ↓
Rollup Bundling ↓
Code Splitting ↓
Tree Shaking ↓
Minification ↓
Asset Generation ↓
dist/ folder Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
Source Files ↓
Vite Plugins (transform) ↓
Rollup Bundling ↓
Code Splitting ↓
Tree Shaking ↓
Minification ↓
Asset Generation ↓
dist/ folder CODE_BLOCK:
Source Files ↓
Vite Plugins (transform) ↓
Rollup Bundling ↓
Code Splitting ↓
Tree Shaking ↓
Minification ↓
Asset Generation ↓
dist/ folder CODE_BLOCK:
dist/ assets/ index-abc123.js index-def456.css logo-ghi789.png index.html Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
dist/ assets/ index-abc123.js index-def456.css logo-ghi789.png index.html CODE_BLOCK:
dist/ assets/ index-abc123.js index-def456.css logo-ghi789.png index.html CODE_BLOCK:
// Your package.json
{ "dependencies": { "package-a": "^1.0.0", "package-b": "^2.0.0" }
} Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
// Your package.json
{ "dependencies": { "package-a": "^1.0.0", "package-b": "^2.0.0" }
} CODE_BLOCK:
// Your package.json
{ "dependencies": { "package-a": "^1.0.0", "package-b": "^2.0.0" }
} CODE_BLOCK:
// package-a's package.json
{ "dependencies": { "package-c": "^1.0.0" }
} // package-b's package.json
{ "dependencies": { "package-c": "^2.0.0" }
} Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
// package-a's package.json
{ "dependencies": { "package-c": "^1.0.0" }
} // package-b's package.json
{ "dependencies": { "package-c": "^2.0.0" }
} CODE_BLOCK:
// package-a's package.json
{ "dependencies": { "package-c": "^1.0.0" }
} // package-b's package.json
{ "dependencies": { "package-c": "^2.0.0" }
} CODE_BLOCK:
// Internally npm uses @npmcli/arborist
const Arborist = require('@npmcli/arborist');
const arb = new Arborist({ path: process.cwd() }); const tree = await arb.loadActual(); Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
// Internally npm uses @npmcli/arborist
const Arborist = require('@npmcli/arborist');
const arb = new Arborist({ path: process.cwd() }); const tree = await arb.loadActual(); CODE_BLOCK:
// Internally npm uses @npmcli/arborist
const Arborist = require('@npmcli/arborist');
const arb = new Arborist({ path: process.cwd() }); const tree = await arb.loadActual(); COMMAND_BLOCK:
GET https://registry.npmjs.org/react # Response (simplified)
{ "name": "react", "versions": { "18.0.0": { ... }, "18.1.0": { ... }, "18.2.0": { ... } }, "dist-tags": { "latest": "18.2.0" }
} Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
GET https://registry.npmjs.org/react # Response (simplified)
{ "name": "react", "versions": { "18.0.0": { ... }, "18.1.0": { ... }, "18.2.0": { ... } }, "dist-tags": { "latest": "18.2.0" }
} COMMAND_BLOCK:
GET https://registry.npmjs.org/react # Response (simplified)
{ "name": "react", "versions": { "18.0.0": { ... }, "18.1.0": { ... }, "18.2.0": { ... } }, "dist-tags": { "latest": "18.2.0" }
} CODE_BLOCK:
const semver = require('semver'); // ^1.2.3 means >=1.2.3 <2.0.0
semver.satisfies('1.3.0', '^1.2.3'); // true
semver.satisfies('2.0.0', '^1.2.3'); // false // ~1.2.3 means >=1.2.3 <1.3.0
semver.satisfies('1.2.5', '~1.2.3'); // true
semver.satisfies('1.3.0', '~1.2.3'); // false Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
const semver = require('semver'); // ^1.2.3 means >=1.2.3 <2.0.0
semver.satisfies('1.3.0', '^1.2.3'); // true
semver.satisfies('2.0.0', '^1.2.3'); // false // ~1.2.3 means >=1.2.3 <1.3.0
semver.satisfies('1.2.5', '~1.2.3'); // true
semver.satisfies('1.3.0', '~1.2.3'); // false CODE_BLOCK:
const semver = require('semver'); // ^1.2.3 means >=1.2.3 <2.0.0
semver.satisfies('1.3.0', '^1.2.3'); // true
semver.satisfies('2.0.0', '^1.2.3'); // false // ~1.2.3 means >=1.2.3 <1.3.0
semver.satisfies('1.2.5', '~1.2.3'); // true
semver.satisfies('1.3.0', '~1.2.3'); // false CODE_BLOCK:
project/
└─ node_modules/ ├─ [email protected] │ └─ dependencies: loose-envify@^1.1.0 ├─ [email protected] │ └─ dependencies: │ ├─ react@^18.2.0 │ └─ scheduler@^0.23.0 └─ [email protected] Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
project/
└─ node_modules/ ├─ [email protected] │ └─ dependencies: loose-envify@^1.1.0 ├─ [email protected] │ └─ dependencies: │ ├─ react@^18.2.0 │ └─ scheduler@^0.23.0 └─ [email protected] CODE_BLOCK:
project/
└─ node_modules/ ├─ [email protected] │ └─ dependencies: loose-envify@^1.1.0 ├─ [email protected] │ └─ dependencies: │ ├─ react@^18.2.0 │ └─ scheduler@^0.23.0 └─ [email protected] COMMAND_BLOCK:
# Ideal structure (deduplicated)
node_modules/ [email protected] [email protected] [email protected] # Shared by multiple packages Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
# Ideal structure (deduplicated)
node_modules/ [email protected] [email protected] [email protected] # Shared by multiple packages COMMAND_BLOCK:
# Ideal structure (deduplicated)
node_modules/ [email protected] [email protected] [email protected] # Shared by multiple packages COMMAND_BLOCK:
node_modules/ [email protected] node_modules/ [email protected] # Specific to package-a [email protected] node_modules/ [email protected] # Specific to package-b [email protected] # Hoisted version Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
node_modules/ [email protected] node_modules/ [email protected] # Specific to package-a [email protected] node_modules/ [email protected] # Specific to package-b [email protected] # Hoisted version COMMAND_BLOCK:
node_modules/ [email protected] node_modules/ [email protected] # Specific to package-a [email protected] node_modules/ [email protected] # Specific to package-b [email protected] # Hoisted version CODE_BLOCK:
GET https://registry.npmjs.org/react/-/react-18.2.0.tgz Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
GET https://registry.npmjs.org/react/-/react-18.2.0.tgz CODE_BLOCK:
GET https://registry.npmjs.org/react/-/react-18.2.0.tgz CODE_BLOCK:
~/.npm/_cacache/ content-v2/ index-v5/ tmp/ Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
~/.npm/_cacache/ content-v2/ index-v5/ tmp/ CODE_BLOCK:
~/.npm/_cacache/ content-v2/ index-v5/ tmp/ COMMAND_BLOCK:
# First install
npm install react # Downloads from registry # Second install
npm install react # Uses cache (instant) Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
# First install
npm install react # Downloads from registry # Second install
npm install react # Uses cache (instant) COMMAND_BLOCK:
# First install
npm install react # Downloads from registry # Second install
npm install react # Uses cache (instant) COMMAND_BLOCK:
# Simplified extraction
tar -xzf react-18.2.0.tgz -C node_modules/react Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
# Simplified extraction
tar -xzf react-18.2.0.tgz -C node_modules/react COMMAND_BLOCK:
# Simplified extraction
tar -xzf react-18.2.0.tgz -C node_modules/react CODE_BLOCK:
// vite's package.json
{ "bin": { "vite": "bin/vite.js" }
} Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
// vite's package.json
{ "bin": { "vite": "bin/vite.js" }
} CODE_BLOCK:
// vite's package.json
{ "bin": { "vite": "bin/vite.js" }
} COMMAND_BLOCK:
node_modules/.bin/vite -> ../vite/bin/vite.js Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
node_modules/.bin/vite -> ../vite/bin/vite.js COMMAND_BLOCK:
node_modules/.bin/vite -> ../vite/bin/vite.js CODE_BLOCK:
{ "scripts": { "preinstall": "node check.js", "install": "node build.js", "postinstall": "node setup.js" }
} Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
{ "scripts": { "preinstall": "node check.js", "install": "node build.js", "postinstall": "node setup.js" }
} CODE_BLOCK:
{ "scripts": { "preinstall": "node check.js", "install": "node build.js", "postinstall": "node setup.js" }
} CODE_BLOCK:
{ "name": "my-app", "version": "1.0.0", "lockfileVersion": 3, "packages": { "node_modules/react": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", "integrity": "sha512-...", "dependencies": { "loose-envify": "^1.1.0" } } }
} Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
{ "name": "my-app", "version": "1.0.0", "lockfileVersion": 3, "packages": { "node_modules/react": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", "integrity": "sha512-...", "dependencies": { "loose-envify": "^1.1.0" } } }
} CODE_BLOCK:
{ "name": "my-app", "version": "1.0.0", "lockfileVersion": 3, "packages": { "node_modules/react": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", "integrity": "sha512-...", "dependencies": { "loose-envify": "^1.1.0" } } }
} COMMAND_BLOCK:
# Developer A installs
npm install # Gets [email protected] # Developer B installs 6 months later
npm install # Gets [email protected] (different!) Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
# Developer A installs
npm install # Gets [email protected] # Developer B installs 6 months later
npm install # Gets [email protected] (different!) COMMAND_BLOCK:
# Developer A installs
npm install # Gets [email protected] # Developer B installs 6 months later
npm install # Gets [email protected] (different!) COMMAND_BLOCK:
npm ci Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
// react-dom's package.json
{ "peerDependencies": { "react": "^18.2.0" }
} Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
// react-dom's package.json
{ "peerDependencies": { "react": "^18.2.0" }
} CODE_BLOCK:
// react-dom's package.json
{ "peerDependencies": { "react": "^18.2.0" }
} COMMAND_BLOCK:
# Without peer dependencies
node_modules/ [email protected] # Your install react-dom/ node_modules/ [email protected] # Duplicate! 💥 Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
# Without peer dependencies
node_modules/ [email protected] # Your install react-dom/ node_modules/ [email protected] # Duplicate! 💥 COMMAND_BLOCK:
# Without peer dependencies
node_modules/ [email protected] # Your install react-dom/ node_modules/ [email protected] # Duplicate! 💥 COMMAND_BLOCK:
node_modules/ [email protected] # Single instance ✅ react-dom/ Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
node_modules/ [email protected] # Single instance ✅ react-dom/ COMMAND_BLOCK:
node_modules/ [email protected] # Single instance ✅ react-dom/ COMMAND_BLOCK:
npm WARN [email protected] requires a peer of react@^18.2.0 but none is installed Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
npm WARN [email protected] requires a peer of react@^18.2.0 but none is installed COMMAND_BLOCK:
npm WARN [email protected] requires a peer of react@^18.2.0 but none is installed CODE_BLOCK:
┌─────────────────────────────────────┐
│ Browser (Runtime) │
│ - Renders UI │
│ - Executes JavaScript │
│ - Handles ESM imports │
└─────────────────────────────────────┘ ↑ │ HTTP requests ↓
┌─────────────────────────────────────┐
│ Vite Dev Server (Build Time) │
│ - Transforms files on request │
│ - Handles HMR protocol │
│ - Serves static assets │
└─────────────────────────────────────┘ ↑ │ Reads from ↓
┌─────────────────────────────────────┐
│ node_modules (Dependencies) │
│ - Installed packages │
│ - Pre-bundled by Vite │
│ - Managed by npm │
└─────────────────────────────────────┘ ↑ │ Created by ↓
┌─────────────────────────────────────┐
│ npm (Install Time) │
│ - Resolves versions │
│ - Downloads packages │
│ - Builds dependency tree │
└─────────────────────────────────────┘ Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
┌─────────────────────────────────────┐
│ Browser (Runtime) │
│ - Renders UI │
│ - Executes JavaScript │
│ - Handles ESM imports │
└─────────────────────────────────────┘ ↑ │ HTTP requests ↓
┌─────────────────────────────────────┐
│ Vite Dev Server (Build Time) │
│ - Transforms files on request │
│ - Handles HMR protocol │
│ - Serves static assets │
└─────────────────────────────────────┘ ↑ │ Reads from ↓
┌─────────────────────────────────────┐
│ node_modules (Dependencies) │
│ - Installed packages │
│ - Pre-bundled by Vite │
│ - Managed by npm │
└─────────────────────────────────────┘ ↑ │ Created by ↓
┌─────────────────────────────────────┐
│ npm (Install Time) │
│ - Resolves versions │
│ - Downloads packages │
│ - Builds dependency tree │
└─────────────────────────────────────┘ CODE_BLOCK:
┌─────────────────────────────────────┐
│ Browser (Runtime) │
│ - Renders UI │
│ - Executes JavaScript │
│ - Handles ESM imports │
└─────────────────────────────────────┘ ↑ │ HTTP requests ↓
┌─────────────────────────────────────┐
│ Vite Dev Server (Build Time) │
│ - Transforms files on request │
│ - Handles HMR protocol │
│ - Serves static assets │
└─────────────────────────────────────┘ ↑ │ Reads from ↓
┌─────────────────────────────────────┐
│ node_modules (Dependencies) │
│ - Installed packages │
│ - Pre-bundled by Vite │
│ - Managed by npm │
└─────────────────────────────────────┘ ↑ │ Created by ↓
┌─────────────────────────────────────┐
│ npm (Install Time) │
│ - Resolves versions │
│ - Downloads packages │
│ - Builds dependency tree │
└─────────────────────────────────────┘ CODE_BLOCK:
1. npm install ├─ Reads package.json ├─ Resolves dependencies ├─ Downloads packages ├─ Builds node_modules/ └─ Generates package-lock.json 2. npm run dev ├─ npm looks up "dev" script in package.json ├─ Executes: vite (from node_modules/.bin/) └─ Vite starts dev server Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
1. npm install ├─ Reads package.json ├─ Resolves dependencies ├─ Downloads packages ├─ Builds node_modules/ └─ Generates package-lock.json 2. npm run dev ├─ npm looks up "dev" script in package.json ├─ Executes: vite (from node_modules/.bin/) └─ Vite starts dev server CODE_BLOCK:
1. npm install ├─ Reads package.json ├─ Resolves dependencies ├─ Downloads packages ├─ Builds node_modules/ └─ Generates package-lock.json 2. npm run dev ├─ npm looks up "dev" script in package.json ├─ Executes: vite (from node_modules/.bin/) └─ Vite starts dev server CODE_BLOCK:
1. Developer edits src/App.jsx 2. Vite's file watcher detects change 3. Vite: ├─ Invalidates module graph ├─ Sends HMR payload via WebSocket └─ Waits for browser request 4. Browser: ├─ Receives HMR update ├─ Requests updated module └─ Vite transforms on-demand 5. React Fast Refresh: ├─ Preserves component state └─ Re-renders changed component Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
1. Developer edits src/App.jsx 2. Vite's file watcher detects change 3. Vite: ├─ Invalidates module graph ├─ Sends HMR payload via WebSocket └─ Waits for browser request 4. Browser: ├─ Receives HMR update ├─ Requests updated module └─ Vite transforms on-demand 5. React Fast Refresh: ├─ Preserves component state └─ Re-renders changed component CODE_BLOCK:
1. Developer edits src/App.jsx 2. Vite's file watcher detects change 3. Vite: ├─ Invalidates module graph ├─ Sends HMR payload via WebSocket └─ Waits for browser request 4. Browser: ├─ Receives HMR update ├─ Requests updated module └─ Vite transforms on-demand 5. React Fast Refresh: ├─ Preserves component state └─ Re-renders changed component CODE_BLOCK:
1. npm install lodash ├─ Resolves version ├─ Downloads package ├─ Updates package.json ├─ Updates package-lock.json └─ Adds to node_modules/ 2. Vite detects new dependency └─ Pre-bundles lodash on next import 3. Import in code: import _ from 'lodash'; └─ Vite rewrites to: /@fs/.../lodash.js Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
1. npm install lodash ├─ Resolves version ├─ Downloads package ├─ Updates package.json ├─ Updates package-lock.json └─ Adds to node_modules/ 2. Vite detects new dependency └─ Pre-bundles lodash on next import 3. Import in code: import _ from 'lodash'; └─ Vite rewrites to: /@fs/.../lodash.js CODE_BLOCK:
1. npm install lodash ├─ Resolves version ├─ Downloads package ├─ Updates package.json ├─ Updates package-lock.json └─ Adds to node_modules/ 2. Vite detects new dependency └─ Pre-bundles lodash on next import 3. Import in code: import _ from 'lodash'; └─ Vite rewrites to: /@fs/.../lodash.js CODE_BLOCK:
// webpack.config.js
module.exports = { plugins: [ new ModuleFederationPlugin({ name: 'app1', remotes: { app2: 'app2@http://localhost:3002/remoteEntry.js', }, }), ],
}; Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
// webpack.config.js
module.exports = { plugins: [ new ModuleFederationPlugin({ name: 'app1', remotes: { app2: 'app2@http://localhost:3002/remoteEntry.js', }, }), ],
}; CODE_BLOCK:
// webpack.config.js
module.exports = { plugins: [ new ModuleFederationPlugin({ name: 'app1', remotes: { app2: 'app2@http://localhost:3002/remoteEntry.js', }, }), ],
}; CODE_BLOCK:
// Babel plugin extracts styles at build time
import styled from 'styled-components';
const Button = styled.button` color: blue;
`; Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
// Babel plugin extracts styles at build time
import styled from 'styled-components';
const Button = styled.button` color: blue;
`; CODE_BLOCK:
// Babel plugin extracts styles at build time
import styled from 'styled-components';
const Button = styled.button` color: blue;
`; CODE_BLOCK:
// Separate configs for client + server
module.exports = [ clientConfig, serverConfig,
]; Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
// Separate configs for client + server
module.exports = [ clientConfig, serverConfig,
]; CODE_BLOCK:
// Separate configs for client + server
module.exports = [ clientConfig, serverConfig,
]; CODE_BLOCK:
// Built-in SSR API
const { render } = await vite.ssrLoadModule('/src/entry-server.js');
const html = await render(); Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
// Built-in SSR API
const { render } = await vite.ssrLoadModule('/src/entry-server.js');
const html = await render(); CODE_BLOCK:
// Built-in SSR API
const { render } = await vite.ssrLoadModule('/src/entry-server.js');
const html = await render(); COMMAND_BLOCK:
npm install vite @vitejs/plugin-react --save-dev Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
npm install vite @vitejs/plugin-react --save-dev COMMAND_BLOCK:
npm install vite @vitejs/plugin-react --save-dev CODE_BLOCK:
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react'; export default defineConfig({ plugins: [react()], server: { port: 3000, },
}); Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react'; export default defineConfig({ plugins: [react()], server: { port: 3000, },
}); CODE_BLOCK:
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react'; export default defineConfig({ plugins: [react()], server: { port: 3000, },
}); CODE_BLOCK:
<!DOCTYPE html>
<html> <head> <title>My App</title> </head> <body> <div id="root"></div> <script type="module" src="/src/main.jsx"></script> </body>
</html> Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
<!DOCTYPE html>
<html> <head> <title>My App</title> </head> <body> <div id="root"></div> <script type="module" src="/src/main.jsx"></script> </body>
</html> CODE_BLOCK:
<!DOCTYPE html>
<html> <head> <title>My App</title> </head> <body> <div id="root"></div> <script type="module" src="/src/main.jsx"></script> </body>
</html> CODE_BLOCK:
{ "scripts": { "dev": "vite", "build": "vite build", "preview": "vite preview" }
} Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
{ "scripts": { "dev": "vite", "build": "vite build", "preview": "vite preview" }
} CODE_BLOCK:
{ "scripts": { "dev": "vite", "build": "vite build", "preview": "vite preview" }
} CODE_BLOCK:
// Webpack
process.env.REACT_APP_API_URL // Vite
import.meta.env.VITE_API_URL Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
// Webpack
process.env.REACT_APP_API_URL // Vite
import.meta.env.VITE_API_URL CODE_BLOCK:
// Webpack
process.env.REACT_APP_API_URL // Vite
import.meta.env.VITE_API_URL CODE_BLOCK:
// Webpack
require.context('./components', true, /\.jsx$/); // Vite
import.meta.glob('./components/**/*.jsx'); Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
// Webpack
require.context('./components', true, /\.jsx$/); // Vite
import.meta.glob('./components/**/*.jsx'); CODE_BLOCK:
// Webpack
require.context('./components', true, /\.jsx$/); // Vite
import.meta.glob('./components/**/*.jsx'); CODE_BLOCK:
// Doesn't work in Vite
const Component = require(`./${name}.jsx`); // Use dynamic import instead
const Component = await import(`./${name}.jsx`); Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
// Doesn't work in Vite
const Component = require(`./${name}.jsx`); // Use dynamic import instead
const Component = await import(`./${name}.jsx`); CODE_BLOCK:
// Doesn't work in Vite
const Component = require(`./${name}.jsx`); // Use dynamic import instead
const Component = await import(`./${name}.jsx`); - Vite's internal architecture — from ESM transformation to the HMR protocol
- Webpack's bundle-first approach — why it was necessary and why it became a bottleneck
- npm's dependency resolution algorithm — how it handles version conflicts and builds the node_modules tree
- The relationship between all three — how they form different layers of the modern frontend stack - The Evolution: Why Webpack Dominated
- Webpack's Internal Architecture
- Vite's Paradigm Shift: No-Bundle Development
- Vite Internals: Request-Time Transformation
- HMR Protocol: Webpack vs Vite
- Production Builds: Why Vite Still Bundles
- npm Deep Dive: Dependency Resolution Algorithm
- The Complete Stack: How Everything Connects
- Performance Benchmarks and Real-World Impact - Global scope pollution — everything lived in window
- Manual dependency ordering — script order mattered
- No code organization — monolithic files or hundreds of script tags
- HTTP/1.1 overhead — each file = separate request - Parse the entire dependency graph
- Transform all modules into browser-compatible code
- Bundle everything into one or more files
- Inject runtime code to handle module loading - Re-analyze dependencies
- Re-apply transformations
- Re-bundle (with optimizations) - Reads entry file
- Parses AST (Abstract Syntax Tree) using acorn parser
- Finds all import and require statements
- Recursively processes dependencies - Nodes = modules (files)
- Edges = dependencies (imports) - Entry points — creates separate chunks
- Code splitting — import() creates async chunks
- Optimization rules — shared dependencies extracted - Traversing the full dependency graph
- Analyzing import/export usage
- Calculating optimal chunk boundaries - Runtime code — module loader, chunk loading
- All transformed modules — wrapped in functions
- Module map — ID to function mapping - File watcher detects change
- Webpack re-compiles affected modules
- Generates patch (HMR update)
- WebSocket sends update to browser
- Browser applies patch - Serves files on request
- Transforms only requested files
- Lets the browser handle module loading - Plugin container — runs Rollup-compatible plugins
- Transform middleware — handles file transformations
- Module graph — tracks imports and dependencies
- HMR server — WebSocket for hot updates - Performance — node_modules have many files
- ESM compatibility — some packages use CommonJS
- HTTP overhead — reduce browser requests - Import paths are rewritten to absolute URLs
- JSX is compiled using esbuild (10-100x faster than Babel)
- HMR code is injected for hot updates
- CSS imports are handled with query params - Uses es-module-lexer to parse imports
- Resolves module specifiers using Rollup's resolution algorithm
- Rewrites paths to point to actual files - File changes detected by file watcher
- Webpack recompiles affected modules
- Generates HMR update manifest (.hot-update.json)
- Sends update ID via WebSocket
- Browser requests update via script tag
- Webpack runtime applies patch - Recompilation overhead — even with caching
- Bundle-level updates — not file-level
- Potential state loss — depends on HMR boundaries - File watcher detects change
- Vite invalidates module graph entry
- Sends HMR payload via WebSocket
- Browser requests updated module
- Vite transforms on-demand
- React Fast Refresh preserves state - No recompilation — file is transformed on-demand
- File-level granularity — exact module updated
- Timestamp-based cache busting — ?t= query param
- Instant updates — typically under 50ms - Too many requests — 1000s of files = 1000s of requests
- No tree shaking — dead code isn't eliminated
- No minification — larger file sizes
- No code splitting — can't optimize loading
- Network waterfall — sequential imports slow down parsing - Tree shaking — removes unused code
- Code splitting — dynamic imports become separate chunks
- Minification — uses Terser or esbuild
- Asset hashing — app.abc123.js for caching - Fast feedback loop
- Instant updates
- State preservation - Optimal loading
- Minimal file size
- Maximum compatibility - dependencies
- devDependencies
- peerDependencies
- optionalDependencies - Available versions
- Each version's dependencies
- Package metadata (license, maintainers, etc.) - ^1.2.3 — compatible with 1.2.3 (minor/patch updates)
- ~1.2.3 — approximately 1.2.3 (patch updates only)
- 1.2.3 — exact version
- * or latest — any version (usually latest) - postinstall
- prepare (for git dependencies) - Exact versions — no ambiguity
- Reproducibility — same tree on all machines
- Integrity hashes — detect tampering - Requires package-lock.json — fails if missing
- Deletes node_modules — starts fresh
- Installs exact versions — no resolution needed
- Skips package.json checks — trusts lockfile
- Faster — no deduplication calculations - 0.3s — Server startup
- 0.7s — Dependency pre-bundling (esbuild)
- 0.2s — First page load - No re-bundling — just re-transform one file
- esbuild transformation — 10-100x faster than Babel
- Precise module invalidation — only changed module - Faster iteration — 2-4s → 100ms HMR means 24-40x faster feedback
- Less context switching — instant updates keep you in flow
- Better DX — less waiting = less frustration - Legacy projects — migrating is costly
- Custom loaders — very specific transformation needs
- Advanced optimizations — fine-tuned control over chunking - New projects — better defaults
- Large apps — where Webpack slows down
- Modern browsers — when you can rely on ESM - Runtime CSS — styles injected at runtime
- Build-time extraction — via plugins like vite-plugin-styled-components - React, Vue, Svelte apps
- Modern browser targets
- ESM-compatible dependencies - Heavy Webpack-specific loaders
- Module Federation
- IE11 support required - Install Vite: - Create vite.config.js: - Update index.html: - Update package.json: - Handle environment variables: - Replace Webpack-specific code: - Turbopack (Vercel) — Webpack successor in Rust
- Farm — Vite-like tool in Rust
- Rspack (ByteDance) — Webpack-compatible Rust bundler - WMR (Preact)
- Snowpack (predecessor to Vite)
- esbuild (as a standalone tool) - Next.js + Turbopack
- SvelteKit + Vite
- Astro + Vite - Cloudflare Workers
- Vercel Edge Functions
- Deno Deploy - Working with legacy codebases
- Need deep customization
- Using Module Federation - Starting new projects
- Prioritizing DX
- Building modern apps - Everything can be bundled
- Loaders are powerful
- Configuration is complex but flexible - Bundling isn't always necessary
- Browser capabilities can be leveraged
- Simplicity scales better than complexity - Dependency management is hard
- Determinism matters
- Abstraction has costs - Understand the layers
- Know when to use each tool
- Don't cargo-cult solutions - Understand the problem before choosing the solution
- Know the trade-offs — every tool optimizes for something
- Learn the internals — mental models beat tutorials - Vite Documentation
- Vite source code
- Evan You's talk on Vite - Webpack Documentation
- Webpack source code
- Sean Larkin's talks - npm Documentation
- npm source code
- Understanding npm algorithm - MDN: JavaScript modules
- ES modules deep dive
how-totutorialguidedev.toaimlservernetworkswitchnodejavascriptgit