Vite

Build ToolJavaScriptFastFrontendNext GenerationES modules

Build Tool

Vite

Overview

Vite is a fast build tool for frontend development. Created by Evan You, the creator of Vue.js, with the concept of being "lightning fast". By leveraging ES modules and Rollup, it achieves extremely fast cold starts and Hot Module Replacement (HMR) during development, while providing Rollup-based optimization for production builds. It supports a wide range of technology stacks including Vue, React, Svelte, and TypeScript, rapidly gaining popularity as a next-generation frontend development tool.

Details

Key Features

  • Fast Development Server: Instant startup leveraging native ES modules
  • Hot Module Replacement: Fast updates while preserving state
  • TypeScript Integration: Zero-config TypeScript support
  • CSS Processing: Automatic support for PostCSS, Sass, Less, and more
  • Optimized Builds: Rollup-based production builds
  • Plugin Ecosystem: Rich plugins compatible with Rollup
  • Multi-Framework Support: Vue, React, Svelte, Vanilla, and more

Architecture

Serves native ES modules directly to the browser during development, optimizes with Rollup for production. Achieves speed through dependency pre-bundling using esbuild.

Performance Characteristics

  • Dev Server Startup: Starts in hundreds of milliseconds
  • HMR: Updates in under 50ms
  • Pre-bundling: 10-100x faster dependency processing with esbuild
  • Incremental Builds: Only processes changed modules

Pros and Cons

Pros

  • Exceptional Speed: Extremely fast dev server startup and HMR
  • Zero Configuration: Works out of the box in most cases
  • Modern Architecture: Leverages ES modules and esbuild
  • Lightweight: Few dependencies, fast installation
  • Excellent DX: Fast feedback loops
  • Full TypeScript Support: Zero-config TypeScript support
  • Rich Framework Support: Official support for Vue, React, Svelte
  • Plugin Ecosystem: Compatible with Rollup plugins

Cons

  • Newer Tool: Less track record and community compared to Webpack
  • Plugin Gaps: Some specialized plugins not yet available
  • Legacy Browsers: Complex configuration for older browsers
  • Learning Curve: Conceptual differences when migrating from Webpack
  • Large Projects: Some limitations in very large/complex projects
  • Debug Information: Sometimes fewer error messages than Webpack

Reference Links

Usage Examples

Project Creation and Setup

# Create new project (with framework selection)
npm create vite@latest my-app
cd my-app
npm install

# Create with specific framework
npm create vite@latest my-vue-app -- --template vue
npm create vite@latest my-react-app -- --template react
npm create vite@latest my-svelte-app -- --template svelte
npm create vite@latest my-ts-app -- --template vanilla-ts

# Add Vite to existing project
npm install --save-dev vite

# Start development server
npm run dev

# Production build
npm run build

# Preview server (check build results)
npm run preview

Basic vite.config.js Configuration

import { defineConfig } from 'vite'

export default defineConfig({
  // Root directory setting
  root: '.',
  
  // Development server settings
  server: {
    port: 3000,
    open: true,  // Auto open browser
    host: true,  // Allow external access
    cors: true   // Enable CORS
  },
  
  // Build settings
  build: {
    outDir: 'dist',
    assetsDir: 'assets',
    sourcemap: true,  // Generate source maps
    minify: 'terser', // Minification method
    target: 'es2015'  // Target browsers
  },
  
  // Base path setting
  base: './',
  
  // Preview server settings
  preview: {
    port: 4173,
    open: true
  }
})

React + TypeScript Configuration

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import path from 'path'

export default defineConfig({
  plugins: [react()],
  
  // Path alias configuration
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src'),
      '@components': path.resolve(__dirname, './src/components'),
      '@utils': path.resolve(__dirname, './src/utils')
    }
  },
  
  // Development server settings
  server: {
    port: 3000,
    hot: true,
    
    // Proxy settings (API server)
    proxy: {
      '/api': {
        target: 'http://localhost:8080',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/api/, '')
      }
    }
  },
  
  // CSS settings
  css: {
    preprocessorOptions: {
      scss: {
        additionalData: `@import "@/styles/variables.scss";`
      }
    },
    modules: {
      localsConvention: 'camelCaseOnly'
    }
  },
  
  // Optimization settings
  optimizeDeps: {
    include: ['react', 'react-dom'],
    exclude: ['some-large-library']
  },
  
  // Build settings
  build: {
    target: 'es2015',
    outDir: 'dist',
    sourcemap: true,
    
    // Rollup options
    rollupOptions: {
      output: {
        manualChunks: {
          vendor: ['react', 'react-dom'],
          router: ['react-router-dom']
        }
      }
    }
  }
})

Vue 3 + TypeScript Configuration

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path'

export default defineConfig({
  plugins: [
    vue({
      // Vue SFC custom blocks
      include: [/\.vue$/],
      // TypeScript JSX support
      script: {
        defineModel: true,
        propsDestructure: true
      }
    })
  ],
  
  resolve: {
    alias: {
      '@': resolve(__dirname, './src'),
      '~': resolve(__dirname, './src')
    }
  },
  
  server: {
    port: 5173,
    open: true,
    proxy: {
      '/api': {
        target: 'http://localhost:3000',
        changeOrigin: true
      }
    }
  },
  
  css: {
    preprocessorOptions: {
      scss: {
        additionalData: `
          @import "@/styles/variables.scss";
          @import "@/styles/mixins.scss";
        `
      }
    }
  },
  
  build: {
    target: 'esnext',
    minify: 'esbuild',
    cssCodeSplit: true
  }
})

Advanced Configuration with Plugins

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { resolve } from 'path'
import legacy from '@vitejs/plugin-legacy'
import { visualizer } from 'rollup-plugin-visualizer'
import eslint from 'vite-plugin-eslint'

export default defineConfig({
  plugins: [
    react(),
    
    // ESLint integration
    eslint({
      cache: false,
      include: ['./src/**/*.js', './src/**/*.jsx', './src/**/*.ts', './src/**/*.tsx'],
      exclude: []
    }),
    
    // Legacy browser support
    legacy({
      targets: ['defaults', 'not IE 11']
    }),
    
    // Bundle analysis
    visualizer({
      filename: 'dist/stats.html',
      open: false,
      gzipSize: true
    })
  ],
  
  resolve: {
    alias: {
      '@': resolve(__dirname, './src'),
      '@assets': resolve(__dirname, './src/assets'),
      '@components': resolve(__dirname, './src/components'),
      '@hooks': resolve(__dirname, './src/hooks'),
      '@services': resolve(__dirname, './src/services'),
      '@utils': resolve(__dirname, './src/utils')
    },
    
    // Extension omission
    extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue']
  },
  
  // Environment variable settings
  define: {
    __APP_VERSION__: JSON.stringify(process.env.npm_package_version),
    __BUILD_TIME__: JSON.stringify(new Date().toISOString())
  },
  
  server: {
    port: 3000,
    host: '0.0.0.0',
    
    // HTTPS settings
    https: false,
    
    // Proxy settings (multiple APIs)
    proxy: {
      '/api/v1': {
        target: 'http://localhost:8080',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/api\/v1/, '/api/v1')
      },
      '/api/v2': {
        target: 'http://localhost:8081',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/api\/v2/, '/api/v2')
      }
    }
  },
  
  css: {
    devSourcemap: true,
    preprocessorOptions: {
      scss: {
        additionalData: `
          @import "@/styles/variables.scss";
          @import "@/styles/mixins.scss";
          @import "@/styles/functions.scss";
        `
      }
    },
    postcss: {
      plugins: [
        require('autoprefixer'),
        require('cssnano')({
          preset: 'default'
        })
      ]
    }
  },
  
  // Pre-bundling settings
  optimizeDeps: {
    include: [
      'react',
      'react-dom',
      'react-router-dom',
      'axios',
      'lodash-es'
    ],
    exclude: ['some-es-module-library'],
    
    // esbuild options
    esbuildOptions: {
      define: {
        global: 'globalThis'
      }
    }
  },
  
  build: {
    target: ['es2015', 'chrome79', 'safari13'],
    outDir: 'dist',
    assetsDir: 'assets',
    sourcemap: 'hidden',
    minify: 'terser',
    
    // Terser options
    terserOptions: {
      compress: {
        drop_console: true,
        drop_debugger: true
      }
    },
    
    // Chunk splitting
    rollupOptions: {
      input: {
        main: resolve(__dirname, 'index.html'),
        admin: resolve(__dirname, 'admin.html')
      },
      
      output: {
        manualChunks: {
          react: ['react', 'react-dom'],
          router: ['react-router-dom'],
          ui: ['@mui/material', '@mui/icons-material'],
          utils: ['lodash-es', 'date-fns'],
          chart: ['chart.js', 'react-chartjs-2']
        },
        
        // Asset naming rules
        chunkFileNames: 'js/[name]-[hash].js',
        entryFileNames: 'js/[name]-[hash].js',
        assetFileNames: ({ name }) => {
          if (/\.(gif|jpe?g|png|svg)$/.test(name ?? '')) {
            return 'images/[name]-[hash][extname]'
          }
          if (/\.css$/.test(name ?? '')) {
            return 'css/[name]-[hash][extname]'
          }
          return 'assets/[name]-[hash][extname]'
        }
      }
    },
    
    // File size warning threshold
    chunkSizeWarningLimit: 1000
  }
})

Environment-based Configuration

import { defineConfig, loadEnv } from 'vite'
import react from '@vitejs/plugin-react'

export default defineConfig(({ command, mode }) => {
  // Load environment variables
  const env = loadEnv(mode, process.cwd(), '')
  
  return {
    plugins: [react()],
    
    // Switch settings between development and production
    server: {
      port: command === 'serve' ? 3000 : undefined,
      open: command === 'serve' ? true : false
    },
    
    build: {
      // Generate source maps only in production
      sourcemap: mode === 'production' ? 'hidden' : true,
      
      // Minify only in production
      minify: mode === 'production' ? 'terser' : false
    },
    
    // Expose environment variables to client
    define: {
      __API_URL__: JSON.stringify(env.VITE_API_URL),
      __APP_VERSION__: JSON.stringify(env.npm_package_version)
    }
  }
})

Library Build Configuration

import { defineConfig } from 'vite'
import { resolve } from 'path'
import dts from 'vite-plugin-dts'

export default defineConfig({
  plugins: [
    dts({
      insertTypesEntry: true  // Auto-generate type definition files
    })
  ],
  
  build: {
    lib: {
      entry: resolve(__dirname, 'src/index.ts'),
      name: 'MyLibrary',
      formats: ['es', 'umd'],  // Output in ES and UMD formats
      fileName: (format) => `my-library.${format}.js`
    },
    
    rollupOptions: {
      // External dependencies (not bundled)
      external: ['react', 'react-dom'],
      output: {
        globals: {
          react: 'React',
          'react-dom': 'ReactDOM'
        }
      }
    },
    
    // Generate source maps
    sourcemap: true,
    
    // Output directory
    outDir: 'dist'
  }
})

Test Integration (Vitest)

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { resolve } from 'path'

export default defineConfig({
  plugins: [react()],
  
  resolve: {
    alias: {
      '@': resolve(__dirname, './src'),
      '@test': resolve(__dirname, './test')
    }
  },
  
  // Vitest configuration
  test: {
    globals: true,
    environment: 'jsdom',
    setupFiles: ['./src/test/setup.ts'],
    css: true,
    
    // Coverage settings
    coverage: {
      provider: 'c8',
      reporter: ['text', 'html', 'lcov'],
      exclude: [
        'node_modules/',
        'src/test/',
        '**/*.d.ts'
      ]
    }
  }
})