You’re probably thinking Vite’s lightning speed means its output bundles are automatically lean and mean. That’s usually true, but sometimes you’ll find your production build is larger than you expect, and you need to figure out why. This is where bundle analysis comes in.

Let’s see Vite’s bundle analysis in action. First, make sure you have the @vite-plugin-inspect plugin installed:

npm install -D vite-plugin-inspect
# or
yarn add -D vite-plugin-inspect
# or
pnpm add -D vite-plugin-inspect

Then, add it to your vite.config.js:

// vite.config.js
import { defineConfig } from 'vite';
import inspect from 'vite-plugin-inspect';

export default defineConfig({
  plugins: [
    inspect(),
    // ... other plugins
  ],
});

Now, when you run your Vite build (npm run build), you’ll see a new entry in your terminal output, something like this:

vite v5.0.0 building for production...
✓ 10 modules transformed.
✓ Built in 1.23s
Rendered 10.3 MiB (compressed 3.1 MiB)
Inspect build at http://localhost:5173/__inspect/

Visit that http://localhost:5173/__inspect/ URL in your browser. You’ll see a list of all your modules and, crucially, a "Build" tab. Clicking on "Build" will show you a visual representation of your bundled output, broken down by chunks. You can click on individual chunks to see exactly which modules are contributing to their size.

The Problem Vite Solves

Vite’s development server is famously fast because it uses native ES modules and only transforms files on demand. However, for production, it still needs to bundle your code for better performance and smaller download sizes. The challenge is that as your project grows, it becomes harder to keep track of what’s ending up in your final bundles. Large dependencies, duplicated code across chunks, or even just unintentionally imported libraries can bloat your application. Bundle analysis helps you pinpoint these offenders.

How it Works Internally

Vite uses Rollup under the hood for its production builds. The @vite-plugin-inspect plugin leverages Rollup’s rollup-plugin-visualizer under the hood. When you run vite build, Rollup processes your entire application, resolving imports, transforming code, and then organizing it into optimized output chunks. The rollup-plugin-visualizer hooks into this process, collecting information about the size of each module and how they are grouped into chunks. It then generates an HTML file (or provides an inspect URL) that visualizes this data, typically as a treemap or a sunburst chart, allowing you to interactively explore the composition of your bundles.

Controlling Your Bundles

The primary levers you have for controlling bundle size are:

  1. Code Splitting: Vite (via Rollup) automatically splits your code into chunks based on dynamic imports and entry points. You can influence this by strategically placing import() statements.

  2. Dependency Management: Be mindful of the libraries you add. Large, un-tree-shakable dependencies can significantly increase bundle size. Look for smaller alternatives or use techniques to import only the specific parts of a library you need.

  3. Tree Shaking: Vite performs tree shaking, which removes unused code. Ensure your dependencies are compatible with tree shaking (e.g., using ES modules) and that you’re not accidentally keeping code alive through side effects.

  4. Externalizing: For very large, infrequently changing libraries (like a charting library or a UI framework), you might consider externalizing them. This means they won’t be bundled with your app but will be loaded separately (e.g., via a CDN). You configure this in vite.config.js:

    // vite.config.js
    export default defineConfig({
      build: {
        rollupOptions: {
          external: ['react', 'react-dom'], // Example: externalize React
          output: {
            // Example: map externalized modules to specific global variables
            globals: {
              react: 'React',
              'react-dom': 'ReactDOM',
            },
          },
        },
      },
    });
    

    This tells Rollup not to include react and react-dom in your bundle, assuming they will be available globally (e.g., via a <script> tag).

The One Thing Most People Don’t Realize

You can actually see the unminified and uncompressed size of each chunk in the inspect tool, which is incredibly useful for understanding the raw impact of your code before optimizations. This raw size is often a better indicator of how much code your application is actually shipping, as minification and compression can vary in effectiveness. To see this, in the __inspect/ URL, go to the "Build" tab, and when you click on a chunk, you’ll see both "size" (compressed) and "raw size" (uncompressed). Focus on the "raw size" to understand the fundamental code volume.

Once you’ve optimized your bundles based on the analysis, you’ll likely want to ensure these optimizations are persistent and that you’re not introducing regressions. This often leads to thinking about how to automate performance checks within your CI/CD pipeline.

Want structured learning?

Take the full Vite course →