Build Tools6 min read

Vite Advanced Configuration

Advanced Vite: custom plugins, library mode, SSR configuration, environment variables, chunk splitting, and optimizing production builds.

vitebundlerbuild-toolsperformance

Vite is the dominant build tool for modern web development, using native ES modules in development (instant server start) and Rollup for production builds. Advanced usage includes custom plugins, SSR configuration, library mode for publishing packages, and fine-grained chunk splitting.

Use Vite for all new web projects - its HMR speed and DX are unmatched. Write custom plugins for project-specific transforms. Use `rollupOptions` for chunk splitting control. Profile bundle size with `vite-bundle-visualizer` before optimizing.

Workflow

  1. Write a custom Vite pluginCustom plugins handle project-specific transformations - code generation, asset processing, custom file types.
  2. Configure library mode for publishingLibrary mode builds a package for npm publishing with proper ESM/CJS outputs.
  3. Configure SSR for server-side renderingSSR configuration controls which dependencies are bundled server-side vs externalized.
  4. Optimize chunk splittingPoor chunk splitting causes large initial bundles or over-splitting with too many parallel requests.
  5. Manage environment variablesEnvironment-specific config (API URLs, feature flags) must be accessible at build time or runtime.

Output Format

Custom plugin with appropriate hooks, library mode with ESM/CJS outputs and extern react, SSR middleware mode for dev, `manualChunks` for vendor splitting, typed env variables.

Examples

Virtual module plugin: `function iconPlugin() { return { name: "icons", resolveId(id) { return id.startsWith("~icons/") ? id : null }, load(id) { if (!id.startsWith("~icons/")) return; const [,set,name] = id.split("/"); return `export { default } from "@iconify-json/${set}/icons/${name}.svg?raw"` } } }`
Manual chunks: `manualChunks(id) { if (id.includes("/node_modules/")) { const parts = id.split("/node_modules/"); const pkg = parts[parts.length - 1].split("/")[0]; if (["react","react-dom","react-router-dom"].includes(pkg)) return "react-core"; if (pkg.startsWith("@tanstack")) return "tanstack"; return "vendor"; } }`
Library mode: `build: { lib: { entry: "src/index.ts", formats: ["es","cjs"] }, rollupOptions: { external: id => !id.startsWith(".") && !path.isAbsolute(id) } }`

Edge Cases & Gotchas

  • CommonJS interop: some npm packages are CJS-only; Vite auto-handles most cases but for complex deps, add to `optimizeDeps.include` to pre-bundle
  • Worker files: Vite bundles workers referenced with `new Worker(new URL("./worker.ts", import.meta.url), { type: "module" })` - they get their own bundle with correct dependencies
  • Path aliases: `resolve.alias: { "@": resolve(__dirname, "src") }` - add the same alias to `tsconfig.json` paths for TypeScript support

When to Break These Rules

  • For very large codebases (>500 modules) with complex build requirements (multiple entry points, custom loaders), webpack with its mature plugin ecosystem may offer more control despite worse DX.

Reference Files

  • Vite docs: https://vitejs.dev/guide/
  • Vite plugin API: https://vitejs.dev/guide/api-plugin
  • Vite library mode: https://vitejs.dev/guide/build#library-mode
  • vite-bundle-visualizer: https://github.com/KusStar/vite-bundle-visualizer

More skills in this library

Browse all technical skills - Mobile, AI/ML, Web, Backend, Design, and Product.