Vite & Webpack
The model
- A bundler starts at an entry file and follows every
importto build a dependency graph. It writes that graph out as bundles, the files the browser loads. - Webpack bundles the whole app before it serves a page, in dev and in production. Loaders transform one file at a time, and plugins hook into the whole build.
- Vite skips the bundle in dev. It serves your code as native ES modules, compiles each file when the browser asks for it, and pre-bundles
node_modulesonce. - For production, Vite bundles anyway, because each unbundled import costs a network round trip. Vite 8 uses Rolldown, a Rust bundler. Earlier versions built with Rollup.
- Hot Module Replacement (HMR) swaps an edited module into the running page, so its state survives. If no module accepts the update, the page reloads.
How bundlers work
the ideas behind every Vite and webpack questionPick a bundler
Webpack's core concepts
entryoutput.pathmodule.rulespluginsWhy Vite's dev server starts fast
Webpack is ready only after it bundles the app. Vite is ready once dependencies are pre-bundled, then compiles each file when the browser asks.
Pre-bundling and production bundles
optimizeDeps.include vite --forceStart a Vite project
create, run and build an app, and know where files goCreate, run and build
npm create vite@latestnpm create vite@latest app -- --template react-tsnpm run devnpm run buildnpm run previewTrapvite preview is for a local check. It is not a production server.
Where files go
<script type="module" src="/src/main.js"> public/robots.txt Link to it as /robots.txt.Trapindex.html goes in the root, not in public/. Vite treats it as source, part of the module graph.
Configure Vite
the config file, modes, env variables, TypeScript and testsvite.config.js and modes
defineConfig({}) ({ command, mode }) => ({})vite build --mode stagingmergeConfig(base, app)TrapA mode isn't NODE_ENV. vite build --mode staging still makes a production build.
Env variables in Vite
VITE_API_URL=/api import.meta.env.VITE_API_URL .env.[mode] beats .env. Shell variables beat both.TrapOnly VITE_ names reach the browser, and anyone can read them in the bundle. Never put a secret in one.
Asked in interviews
AskedHow do you handle environment variables in Vite?TypeScript and path aliases
tsc --noEmit && vite build"isolatedModules": trueresolve.aliasresolve.tsconfigPaths: trueTrapVite's alias doesn't reach TypeScript. Add matching paths to tsconfig.json, or tsc reports missing imports.
Test with Vitest
vite.config.js. Add a test key.environment: 'jsdom'Asked in interviews
AskedHow do you handle testing in a Vite project?Configure webpack
dev and production configs, env values and transpilingDev, production and env values
merge(common, prod)From webpack-merge.new webpack.DefinePlugin({}) new webpack.EnvironmentPlugin(['API_URL']) TrapDefinePlugin pastes each value in as code. Wrap a string in JSON.stringify, or it arrives without its quotes.
TypeScript and Babel in webpack
ts-loadertranspileOnly: trueThen check types in ForkTsCheckerWebpackPlugin .@babel/preset-env Externals, workers and top-level await
externals: { react: 'React' }new Worker(new URL('./w.js', import.meta.url)) TrapKeep the worker path a literal string in new URL. Webpack can't follow a variable.
CSS, images & fonts
load styles and files in each toolCSS in Vite
npm install -D sassNo plugin needed.css.preprocessorOptions Button.module.css TrapPut @use, not @import, in scss.. Sass deprecated @import.
Asked in interviews
AskedHow does Vite handle CSS preprocessing (Sass, Less, Stylus)?Assets in Vite
import url from './img.png'?raw?worker?inlinebuild.assetsInlineLimit Asked in interviews
AskedHow does Vite handle asset imports and processing?CSS in webpack
use: ['style-loader', 'css-loader']MiniCssExtractPlugin.loader TrapLoaders run right to left. css-loader reads the file first, then style-loader injects it.
Asset modules in webpack 5
type: 'asset/resource' type: 'asset'output.publicPath Dev server & HMR
swap modules live, proxy API calls, keep the server safeHot Module Replacement
import.meta.hot.accept() module.hot.accept() import.meta.webpackHot Use the second in ES modules.hot: trueIt's on by default since v4.TrapAn update no module accepts climbs to the entry, and the page fully reloads.
Dev servers, proxies and safety
server.proxyThe browser sees one origin, so no CORS check runs.npx webpack serveproxy an array of objects, each with a context list.historyApiFallback: trueserver.host: trueserver.fs.allowTrapA dev proxy does nothing in production. Route /api on your web server, or send CORS headers.
Split & lazy-load code
send less JavaScript on the first loadDynamic import()
await import('./chart.js') import.meta.glob('./pages/*.js') /* webpackChunkName: "chart" *//* webpackPrefetch: true */TrapIn webpack, a fully dynamic import(foo) bundles nothing and fails at runtime. Keep part of the path static.
Code splitting in Vite
import(). Shared code gets its own chunk.codeSplitting.groups manualChunksIts object form is gone in Vite 8. Its function form is deprecated.build.cssCodeSplit: falseTipVite loads a lazy chunk's CSS before it runs the chunk. That prevents a flash of unstyled content.
SplitChunksPlugin and entries
splitChunks: { chunks: 'all' }The default splits async chunks only.cacheGroupsentry an object, one key per page.Tree shaking
import into require.mode: 'production'It marks unused exports. The minifier deletes them."sideEffects": falseTrapList polyfills and CSS in sideEffects. Otherwise webpack may drop them.
Asked in interviews
AskedWhat is tree shaking and how does it work in Webpack?Caching, speed & debugging
browser caching, faster builds and build errorsContent hashes and cache headers
[name].[contenthash].js Production mode hashes each file's final bytes.max-age=31536000, immutable . index.html gets no-cache.Asked in interviews
AskedWhat is the real content hash feature in Webpack 5?Speed up a Vite build
minify: 'terser'drop_console: truereportCompressedSize: falseindex.js.TrapoptimizeDeps can't speed up vite build. Pre-bundling only runs in dev.
Asked in interviews
AskedHow do you optimize Vite for production builds?Speed up webpack
cache: { type: 'filesystem' }thread-loaderminimizer: ['...', new CssMinimizerPlugin()] Analyze and debug builds
webpack --profile --json > stats.jsonwebpack-bundle-analyzer stats.jsonstats: { errorDetails: true }Can't resolve 'crypto'resolve.fallback Webpack 5 stopped adding Node.js polyfills.vite build --profileSource maps
devtool: 'eval-source-map'build: { minify: false, sourcemap: true }TrapPublic .map files expose your source. Keep them from normal users.
Asked in interviews
AskedWhat are source maps and how do you configure them in webpack?Plugins & loaders
use them, order them and write your ownVite plugins
plugins: [react()]Most Rollup plugins work too.apply: 'build'enforce: 'pre'resolveIdloadtransform(code, id)configureServer(server) handleHotUpdateAsked in interviews
AskedWhat are Vite plugins and how do they work?Webpack loaders and plugins
new HtmlWebpackPlugin() output.clean: truethis.getOptions() Export a function that takes the source and returns new source.apply(compiler)Tap the hooks you need.compilation.hooks.processAssets TrapWebpack caches loader results, so a loader must give the same output for the same input.
Deploy, scale & migrate
deploys, libraries, SSR, micro-frontends and upgradesDeploy an app, a library or a PWA
base: '/repo/'index.html for unknown paths.build.librolldownOptions.external vite-plugin-pwaSSR and the Environment API
middlewareMode: truevite.ssrLoadModule('/src/server-entry.js') vite build --ssr src/server-entry.js environmentsModule Federation
ModuleFederationPlugin A remote exposes modules. A host loads them.singleton: trueimport('./bootstrap') .@module-federation/vite TrapA remote that is down or changes its API breaks the host at runtime. Plan a fallback.
Asked in interviews
AskedWhat is module federation in Webpack 5?Migrate and upgrade
require.context becomes import.meta.glob . process.env.X becomes import.meta.env.VITE_X .compiler.close(callback) Asked in interviews
AskedHow would you migrate a large Webpack project to Vite?Nothing matches. Try a shorter word, or clear the search.
This sheet stays free. With Pro, you can:
- Every answer on this sheet. Read the full answer to all 89 questions it links, not just the 15 free ones.
- My sheet. The cards you star and the ones you miss in Quiz me, from every sheet, on one page to quiz and print.
- PDFs. Download this sheet and My sheet, laid out for A4, with every question a link to its answer.
- The rest of Pro. Every answer in the question library, and 1,000 AI credits a month.