ViVite · Lesson 5 of 6

Build & Optimization

`npm run build` runs Rollup under the hood and produces optimized, code-split output. Vite handles CSS minification, asset hashing, tree-shaking, and chunk splitting automatically.

Bash
# Build for production
npm run build

# Output (dist/):
# dist/index.html
# dist/assets/index-a1b2c3d4.css     (hashed filename = cache-busting)
# dist/assets/index-e5f6a7b8.js      (main bundle)
# dist/assets/vendor-c9d0e1f2.js     (react + react-dom, cached separately)

# Analyze bundle size
npm install -D rollup-plugin-visualizer

# Add to vite.config.ts:
# import { visualizer } from 'rollup-plugin-visualizer'
# plugins: [react(), visualizer({ open: true })]
# Then: npm run build — opens interactive treemap in browser

# Preview production build locally
npm run preview   # serves dist/ at http://localhost:4173
TypeScript
// Build optimization in vite.config.ts
import { defineConfig, splitVendorChunkPlugin } from 'vite'

export default defineConfig({
  build: {
    // Target modern browsers — smaller output
    target: 'es2020',

    // Increase chunk size warning threshold (default 500kB)
    chunkSizeWarningLimit: 600,

    rollupOptions: {
      output: {
        // Manual chunk splitting — separate big libraries
        manualChunks(id) {
          if (id.includes('node_modules')) {
            // Put React in its own chunk
            if (id.includes('react')) return 'react-vendor'
            // Put charting library in its own chunk
            if (id.includes('recharts')) return 'charts'
            // Everything else in vendor
            return 'vendor'
          }
        },
      },
    },

    // Generate .gz and .br compressed versions
    // (needs vite-plugin-compression)
    reportCompressedSize: true,
  },

  // Pre-bundle dependencies for faster dev cold start
  optimizeDeps: {
    include: ['lodash-es', 'axios'],
    exclude: ['your-esm-package'],
  },
})

// Lazy loading routes (React Router example)
import { lazy, Suspense } from 'react'
import { Routes, Route } from 'react-router-dom'

const Home    = lazy(() => import('./pages/Home'))
const About   = lazy(() => import('./pages/About'))
const Dashboard = lazy(() => import('./pages/Dashboard'))

function App() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <Routes>
        <Route path="/"          element={<Home />} />
        <Route path="/about"     element={<About />} />
        <Route path="/dashboard" element={<Dashboard />} />
      </Routes>
    </Suspense>
  )
}
✦ Tip
After `npm run build`, check the output for chunks larger than 500KB — Vite warns you about them. Use `rollup-plugin-visualizer` to see exactly what's taking up space. The usual culprits: moment.js (use date-fns), lodash (use lodash-es or individual imports), and large icon libraries (import individually, not the whole set).