Vue.js: Vite Configuration
Last updated: 2026-10-20
Vite is the next-generation build tool from the Vue 3 team, with a cold start 30x faster than Webpack. Vite 5/6 brings major improvements to TypeScript, SSR, and build optimization, and is the standard choice for modern Vue projects.
This lesson walks you through a complete Vite 5/6 engineering setup: vite.config.ts, path aliases, env variables, SCSS, auto-imports, and build optimization. These are essential skills for enterprise Vue projects.
1. What You'll Learn
- The complete vite.config.ts (alias / server / build / css / plugins)
- 3 kinds of environment variables (the VITE_ prefix)
- SCSS / Less preprocessor integration
- unplugin-auto-import for ref / computed
- path.resolve path aliases
- 5 build optimizations (chunk splitting, tree-shaking, minification, CDN, Source Maps)
- Key differences between Vite 5/6 and Vite 4
2. A "5-Minute Cold Start" Developer Experience Comparison
(1) Pain Point: Webpack Takes 30 Seconds to Cold Start, Developers Give Up Waiting
Alice's team used Webpack:
# Webpack project cold start
$ npm run dev
> Project is running at http://localhost:8080
> Compiled successfully in 28.5s ← 30 seconds of waiting
Team lead Charlie:
"Alice, the dev server takes 30 seconds to start. Every file save costs 3 seconds of hot reload. We need to switch to Vite."
(2) The Vite Fix: 5-Second Cold Start, Millisecond HMR
# Vite project cold start
$ npm run dev
> VITE v5.4.0 ready in 487 ms ← only 0.5 seconds
> Local: http://localhost:5173/
Developer experience comparison:
| Operation | Webpack 5 | Vite 5 |
|---|---|---|
| Cold start | 28s | 0.5s |
| HMR | 1-3s | < 50ms |
| Build (large project) | 30-60s | 5-15s |
A 56x faster cold start. After switching to Vite, development speed improves dramatically.
(3) Benefits
After moving to Vite:
- Cold start: 28s → 0.5s (-98%)
- HMR: 3s → 50ms (-98%)
- Build: 30s → 10s (-67%)
- Developer satisfaction: noticeably higher
3. Vite 5/6 Core Concepts
(1) Vite's Two Modes
Development mode (dev):
- Uses native ESM; the browser imports modules directly
- Compiles on demand (a module is compiled on first access)
- Extremely fast HMR (only the changed module is updated)
Production mode (build):
- Bundles with Rollup
- Automatic tree-shaking / code splitting / minification
- Outputs to the dist/ directory
(2) 5 Core Advantages
| Advantage | Description |
|---|---|
| Instant cold start | esbuild pre-bundles dependencies (written in Go, 100x faster than JS-based babel) |
| Compile on demand | Only compiles the modules currently accessed, not the whole project |
| Native ESM | The browser loads modules directly via <script type="module"> |
| Blazing-fast HMR | Changing 1 file updates only that 1 module |
| SSR / SSG | First-class support (officially recommended by Nuxt 3) |
(3) Vite 5/6 vs Vite 4
| Dimension | Vite 4 | Vite 5/6 |
|---|---|---|
| Startup speed | Fast | Faster (better dependency pre-bundling) |
| Build speed | 5-15s | 3-8s |
| Node requirement | 14+ | 18+ |
| Rollup | 3.x | 4.x |
| ESM by default | ✅ | ✅ |
| Recommendation | Legacy | ⭐⭐⭐⭐⭐ |
4. The Complete vite.config.ts
(1) Basic Structure
// vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'
export default defineConfig({
// Project root (defaults to process.cwd())
root: '.',
// Base public path
base: '/',
// Plugins
plugins: [vue()],
// Dev server
server: {
port: 5173,
open: true, // open the browser automatically
host: '0.0.0.0' // reachable on the LAN
},
// Build
build: {
outDir: 'dist',
sourcemap: false,
minify: 'esbuild'
},
// CSS
css: {
preprocessorOptions: {
scss: {
additionalData: `@import "@/styles/variables.scss";`
}
}
},
// Path aliases
resolve: {
alias: {
'@': path.resolve(__dirname, 'src')
}
}
})
(2) 5 Core Config Sections
export default defineConfig({
// 1. Path aliases (the most used)
resolve: {
alias: {
'@': path.resolve(__dirname, 'src'),
'@components': path.resolve(__dirname, 'src/components'),
'@stores': path.resolve(__dirname, 'src/stores')
}
},
// 2. Dev server
server: {
port: 5173,
open: true,
host: '0.0.0.0',
proxy: {
'/api': {
target: 'http://localhost:3000',
changeOrigin: true
}
}
},
// 3. CSS preprocessors
css: {
preprocessorOptions: {
scss: { /* ... */ },
less: { /* ... */ }
}
},
// 4. Build optimization
build: {
rollupOptions: {
output: {
manualChunks: {
'vue-vendor': ['vue', 'vue-router', 'pinia']
}
}
},
chunkSizeWarningLimit: 1500
},
// 5. Dependency optimization
optimizeDeps: {
include: ['vue', 'vue-router', 'pinia']
}
})
5. 3 Kinds of Environment Variables
(1) The VITE_ Prefix Rule
# .env.development
VITE_API_BASE_URL=http://localhost:3000
VITE_APP_TITLE=My App (Dev)
# .env.production
VITE_API_BASE_URL=https://api.example.com
VITE_APP_TITLE=My App
# .env.local (git-ignored, one per developer)
VITE_API_KEY=secret-key
(2) TypeScript Declarations
// src/env.d.ts
/// <reference types="vite/client" />
interface ImportMetaEnv {
readonly VITE_API_BASE_URL: string
readonly VITE_APP_TITLE: string
readonly VITE_API_KEY?: string
}
interface ImportMeta {
readonly env: ImportMetaEnv
}
(3) Using Them in Components
const apiUrl = import.meta.env.VITE_API_BASE_URL
const title = import.meta.env.VITE_APP_TITLE
(4) Priority of the 4 .env Files
| File | Purpose | Git |
|---|---|---|
.env |
Shared by all environments | Commit |
.env.development |
Development only | Commit |
.env.production |
Production only | Commit |
.env.local |
Local overrides (not committed) | Ignore |
▶ Example: Environment Variable Injection + Conditional Rendering (browser-runnable)
import.meta.env with literals at build time, so a plain constant object simulates that injection and a mode switch flips between the dev and prod values.
Output:
First render: title is My App (Dev), API base is http://localhost:3000, and "🛠 Dev build: debug panel visible (HMR connected)" is shown.
After clicking "Switch build mode": the title becomes My App, the API base becomes https://api.example.com, the debug panel disappears and the prod message appears.
Same as real Vite: values are replaced by literals at build time, and the dev branch of the v-if is dropped entirely from the production bundle.
▶ Example: 3 Environment Variable Configurations
# .env.development (development)
VITE_API_BASE_URL=http://localhost:3000
# .env.production (production)
VITE_API_BASE_URL=https://api.example.com
# .env.local (local, not committed to Git)
VITE_API_KEY=secret
// src/env.d.ts (TypeScript declarations)
interface ImportMetaEnv {
readonly VITE_API_BASE_URL: string
readonly VITE_API_KEY?: string
}
// Use it in .vue / .ts files
const apiUrl = import.meta.env.VITE_API_BASE_URL
Output:
With npm run dev the value of apiUrl is http://localhost:3000;
with npm run build it is https://api.example.com.
Variables without the VITE_ prefix (and values from .env.local when it exists) are replaced during the build, and Volar offers autocompletion for both keys through src/env.d.ts.
dev → import.meta.env.VITE_API_BASE_URL === 'http://localhost:3000'
build → import.meta.env.VITE_API_BASE_URL === 'https://api.example.com'
.env.local overrides both when present (regardless of mode)
6. SCSS Integration
(1) Installation
npm install -D sass
(2) Global Variables
// src/styles/variables.scss
$primary: #42b883;
$danger: #ef4444;
$font-size-base: 14px;
$border-radius: 4px;
// vite.config.ts
css: {
preprocessorOptions: {
scss: {
// Injected into every .scss file automatically
additionalData: `@import "@/styles/variables.scss";`
}
}
}
// Usable directly in any .scss file
.button {
background: $primary; /* no @import needed */
color: white;
border-radius: $border-radius;
}
(3) 5 SCSS Advantages
- Variables: $primary, $danger
- Nesting: parent/child selectors
- mixins: reusable style blocks
- Functions: lighten($primary, 10%)
- Modularity: @use / @forward
7. Auto-Imports with unplugin-auto-import
(1) Installation
npm install -D unplugin-auto-import
(2) Configuration
// vite.config.ts
import AutoImport from 'unplugin-auto-import'
export default defineConfig({
plugins: [
vue(),
AutoImport({
imports: ['vue', 'vue-router', 'pinia'],
dts: 'src/auto-imports.d.ts', // type declarations
eslintrc: {
enabled: true // generates .eslintrc-auto-import.json
}
})
]
})
(3) Usage
<script setup>
// ✅ No more import of ref / computed / watch
const count = ref(0)
const double = computed(() => count.value * 2)
watch(count, (val) => console.log(val))
// ✅ No more useRouter import
const router = useRouter()
</script>
(4) 5 Advantages
| Advantage | Description |
|---|---|
| Fewer imports | No need to write import ref / computed every time |
| Type safety | The dts file generates types automatically |
| Configurable | Choose exactly which APIs are auto-imported |
| ESLint friendly | Generates the .eslintrc file to suppress import warnings |
| Fast builds | Does not slow down bundling |
8. 5 Build Optimizations
(1) Code Splitting (manualChunks)
// vite.config.ts
build: {
rollupOptions: {
output: {
manualChunks: {
'vue-vendor': ['vue', 'vue-router', 'pinia'],
'echarts-vendor': ['echarts', 'vue-echarts'],
'utils': ['axios', 'dayjs']
}
}
}
}
(2) Tree-shaking (on by default)
build: {
rollupOptions: {
treeshake: {
moduleSideEffects: 'no-external', // treat all modules as side-effect free
propertyReadSideEffects: false // treat property reads as side-effect free
}
}
}
(3) CSS Minification
build: {
cssMinify: 'lightningcss', // 10x faster than esbuild
// or 'esbuild' (the default)
}
(4) Asset Handling
build: {
assetsInlineLimit: 4096, // assets < 4KB are inlined (base64)
rollupOptions: {
output: {
assetFileNames: 'assets/[name]-[hash][extname]',
chunkFileNames: 'js/[name]-[hash].js',
entryFileNames: 'js/[name]-[hash].js'
}
}
}
(5) Source Maps (debugging in production)
build: {
sourcemap: true, // generate them in production too (for Sentry)
rollupOptions: {
output: {
sourcemapExcludeSources: true // do not inline the source into the map
}
}
}
9. Putting It Together: One Config for Dev and Build
▶ Example: A Complete vite.config.ts (⚠️ requires a Vite project)
vite.config.ts; the CDN global build does not apply. It demonstrates the core options:
// vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import AutoImport from 'unplugin-auto-import'
import path from 'path'
export default defineConfig({
plugins: [
vue(),
AutoImport({
imports: ['vue', 'vue-router', 'pinia'],
dts: 'src/auto-imports.d.ts'
})
],
resolve: {
alias: {
'@': path.resolve(__dirname, 'src') // @ → src/
}
},
server: {
port: 5173, open: true, // open the browser on start
proxy: {
'/api': {
target: 'http://localhost:3000', // proxy forwarding
changeOrigin: true
}
}
},
css: {
preprocessorOptions: {
scss: {
additionalData: '@import "@/styles/variables.scss";'
}
}
},
build: {
outDir: 'dist', sourcemap: true,
rollupOptions: {
output: {
manualChunks: { 'vue-vendor': ['vue', 'vue-router', 'pinia'] }
}
}
}
})
Output:
No page is rendered; this is a build-time config file.
When you run npm run dev, Vite prints VITE v5.x.x ready in ...
ms plus Local: http://localhost:5173/, the browser opens automatically, @/...
imports resolve to src/..., requests to /api/* are forwarded to http://localhost:3000, and npm run build writes hashed bundles plus source maps into dist/.
$ npm run dev
VITE v5.4.0 ready in 487 ms
➜ Local: http://localhost:5173/
➜ Network: http://192.168.1.10:5173/
[proxy] /api/products → http://localhost:3000/api/products
$ npm run build
dist/index.html
dist/assets/index-8f3a1c.css
dist/js/vue-vendor-2b7d9e.js
dist/js/index-4c1a06.js
dist/js/index-4c1a06.js.map
(1) 📊 5 Build Optimizations
| Optimization | Config |
|---|---|
| Code splitting | rollupOptions.output.manualChunks |
| Tree-shaking | build.treeshake settings |
| CSS minification | build.cssMinify: 'lightningcss' |
| Asset handling | build.assetsInlineLimit + file name patterns |
| Source Maps | build.sourcemap: true |
(2) 📊 Quick Reference for 5 Common Mistakes
| Mistake | Symptom | Fix |
|---|---|---|
| Path alias not working | Imports fail | Use path.resolve with __dirname |
| SCSS variable undefined | Compile error | Auto-import it via additionalData |
| Env variable is undefined | undefined at runtime |
Use the VITE_ prefix + .env files |
| auto-import not working | ref cannot be found |
Check that the dts file was generated |
| White screen in production | Wrong paths | Set base: '/yourpath/' |
(3) 📊 5 Vite Performance Comparisons
| Configuration | Cold start | HMR | Production build |
|---|---|---|---|
| Default | 0.5s | 50ms | 10s |
| + alias | 0.5s | 50ms | 10s |
| + SCSS | 0.6s | 60ms | 11s |
| + auto-import | 0.6s | 60ms | 11s |
| + manualChunks | 0.6s | 60ms | 12s (but 50% faster first paint) |
❓ FAQ
import.meta.url: fileURLToPath(new URL('./src', import.meta.url)). Vite 5 recommends combining resolve.alias with path.resolve.unplugin-auto-import removes the auto-import code during build (turning it into explicit imports), so it does not affect the bundle.vite build --ssr or the Nuxt 3 integration. SSR configuration is a bit involved (you have to handle hydration), but Vite's official support is solid.npx auto-imports.📖 Summary
- Vite 5/6 cold start is 0.5s with 50ms HMR (vs Webpack's 28s/3s)
- The 5 core parts of vite.config.ts: plugins / server / build / css / resolve.alias
- 3 kinds of env variables: the VITE_ prefix + 4 .env files
- SCSS auto-import:
additionalData+ variables.scss - unplugin-auto-import: no more imports for ref / computed / useRouter
- 5 build optimizations: code splitting / tree-shaking / CSS minification / asset handling / Source Maps
- Vite is the officially recommended build tool for Vue 3
📝 Exercises
-
Basic (difficulty ⭐) Create a Vite + Vue 3 project and configure:
- The path alias
@→ src - Global SCSS variables
- A
.env.developmentcontaining VITE_API_BASE_URL
- The path alias
-
Intermediate (difficulty ⭐⭐) A complete Vite configuration:
- Path aliases (@ / @components / @stores)
- SCSS + auto-imported variables
- unplugin-auto-import (vue + vue-router + pinia)
- Proxy /api to the backend
- manualChunks for the production build (vue-vendor)
-
Challenge (difficulty ⭐⭐⭐) Build a complete "enterprise-grade Vite configuration":
- 5 path aliases (@ / @components / @stores / @utils / @composables)
- Global SCSS variables + 5 mixins (flex / card / button / form / responsive)
- unplugin-auto-import + Volar type generation
- 3 environments (dev / staging / prod)
- 5 build optimizations (manualChunks / tree-shaking / lightningcss / assets / sourcemap)
- Proxy /api to the backend
- A complete TypeScript setup (env.d.ts + auto-imports.d.ts)