Vite Dynamic Import — Dynamic Imports with the Vite Bundler
In this tutorial, you will learn about Vite Dynamic Import. We cover key concepts, practical examples, and best practices to help you master this topic.
Vite handles dynamic imports natively with automatic code splitting and optimized chunk output, requiring minimal configuration for efficient Lazy Loading.
What You'll Learn
By the end of this tutorial, you'll understand how Vite handles dynamic imports, how to configure manual chunks, how to use Vite's built-in optimizations, and how Vite's approach differs from Webpack.
Why It Matters
Vite uses native ES modules for development and Rollup for production builds. Dynamic imports work out of the box with sensible defaults. Understanding Vite's approach helps you configure splitting without Webpack's complexity.
Real-World Use
A Vue 3 application uses Vite with dynamic imports for all routes. Development starts in under 2 seconds. Production builds produce automatic vendor and page chunks totaling 120KB gzipped for the initial page.
Vite Splitting Architecture
graph TD
A[Vite Build] --> B[Rollup bundler]
B --> C[Automatic
code splitting]
B --> D[Dynamic imports
→ separate chunks]
C --> E[Vendor chunk
node_modules]
C --> F[Entry chunk
main app code]
D --> G[Async chunks
per dynamic import]
E --> H[Output files
dist/]
F --> H
G --> H
H --> I[Browser loads
only needed chunks]
style B fill:#4a90d9,color:#fff
style C fill:#27ae60,color:#fff
style D fill:#e67e22,color:#fff
Vite Configuration
// vite.config.js — Code splitting configuration
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
build: {
// Output directory
outDir: 'dist',
// Generate source maps for debugging
sourcemap: false,
// Configure Rollup for custom splitting
rollupOptions: {
output: {
// Manual chunk configuration
manualChunks: {
// Vendor chunk
vendor: ['react', 'react-dom', 'react-router-dom'],
// UI library chunk
'vendor-ui': ['@mui/material', '@emotion/react'],
// Utility libraries
'vendor-utils': ['lodash-es', 'date-fns', 'axios'],
},
// Chunk file naming
entryFileNames: 'assets/[name].[hash].js',
chunkFileNames: 'assets/[name].[hash].js',
assetFileNames: 'assets/[name].[hash][extname]',
},
},
// Chunk size warning limit
chunkSizeWarningLimit: 500, // KB
// Reduce CSS duplication
cssCodeSplit: true,
// Minification
minify: 'esbuild', // or 'terser' for better output
},
});
Dynamic Imports in Vite
// Vue 3 with Vite — Dynamic imports
const routes = [
{
path: '/',
name: 'Home',
// Vite automatically splits these into separate chunks
component: () => import('@/views/Home.vue'),
},
{
path: '/dashboard',
name: 'Dashboard',
component: () => import('@/views/Dashboard.vue'),
},
{
path: '/analytics',
name: 'Analytics',
// Named chunks with Vite comments
component: () => import(/* @vite-ignore */ '@/views/Analytics.vue'),
},
];
// React with Vite — Same API
const routes = [
{
path: '/dashboard',
element: (
<Suspense fallback={<Loading />}>
{React.lazy(() => import('./pages/Dashboard'))}
</Suspense>
),
},
{
path: '/settings',
element: (
<Suspense fallback={<Loading />}>
{React.lazy(() => import('./pages/Settings'))}
</Suspense>
),
},
];
Manual Chunks Optimization
// vite.config.js — Advanced manual chunks
import { defineConfig } from 'vite';
export default defineConfig({
build: {
rollupOptions: {
output: {
manualChunks(id) {
// React ecosystem
if (id.includes('node_modules/react')) {
return 'vendor-react';
}
// UI libraries
if (id.includes('node_modules/@mui') ||
id.includes('node_modules/@emotion')) {
return 'vendor-ui';
}
// Chart libraries — Group together
if (id.includes('node_modules/chart.js') ||
id.includes('node_modules/d3') ||
id.includes('node_modules/recharts')) {
return 'vendor-charts';
}
// Lodash — Separate chunk (changes rarely)
if (id.includes('node_modules/lodash') ||
id.includes('node_modules/lodash-es')) {
return 'vendor-lodash';
}
// Date libraries
if (id.includes('node_modules/date-fns') ||
id.includes('node_modules/moment')) {
return 'vendor-dates';
}
// Everything else in node_modules
if (id.includes('node_modules')) {
return 'vendor';
}
},
},
},
},
});
Vite vs Webpack Comparison
// Comparison of Vite vs Webpack approaches
const comparison = {
development: {
vite: 'Native ESM — instant start, no bundling needed',
webpack: 'Full bundle on every change — slower for large apps'
},
codeSplitting: {
vite: 'Automatic via dynamic imports, manual chunks via rollupOptions',
webpack: 'Requires splitChunks configuration, more control'
},
chunkNaming: {
vite: 'Automatic with hash, or manual via manualChunks',
webpack: 'Magic comments, splitChunks.name, content hashes'
},
configuration: {
vite: 'Minimal config needed for common cases',
webpack: 'More config required for optimal splitting'
},
buildSpeed: {
vite: 'Faster for small-medium projects (Rollup)',
webpack: 'Better caching for large projects'
},
outputSize: {
vite: 'Comparable to Webpack, slightly smaller in many cases',
webpack: 'Comparable, better for complex tree-shaking'
}
};
Monitoring Vite Bundle
// vite.config.js — Bundle visualization
import { visualizer } from 'rollup-plugin-visualizer';
export default defineConfig({
plugins: [
visualizer({
filename: 'dist/bundle-visualization.html',
title: 'Vite Bundle Analysis',
template: 'treemap', // sunburst, treemap, network
gzipSize: true,
brotliSize: true,
}),
],
});
// package.json scripts
{
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"analyze": "vite build && open dist/bundle-visualization.html",
"build:stats": "vite build --output-stats stats.json"
}
}
Common Mistakes
- Not configuring manualChunks for large dependencies. Vite's auto-splitting is good but manual chunks give predictable names for CDN Caching. Configure manualChunks for your major dependencies.
- Importing from barrel files (index.js) in dynamic imports. Barrel files re-export many modules. Dynamic imports of barrel files include all re-exports. Import directly from the specific module file.
- Forgetting to handle chunk loading errors. Dynamic imports can fail on slow networks. Wrap in try-catch and show fallback UI.
- Not analyzing the bundle after adding dependencies. A single new npm package can add 100KB. Run bundle analysis after major additions.
- Using Webpack magic comments in Vite. Vite uses Rollup, not Webpack. Magic comments like webpackChunkName don't work. Use Vite's manualChunks configuration instead.
Practice Questions
- How does Vite handle dynamic imports differently from Webpack?
- How do you configure manual chunks in Vite?
- How do you analyze Vite's bundle output?
- What is the advantage of Vite's ESM-based development approach?
- How do manualChunks in Vite compare to splitChunks in Webpack?
Challenge: Migrate a Webpack-based project to Vite: configure rollupOptions for manual chunks, set up bundle visualization, verify chunk sizes match Webpack output, and benchmark development start time.
FAQ
Mini Project
Set up a Vite project with manual chunks: create a React app with 3 large libraries (chart, date utils, UI kit), configure manualChunks to separate them, add bundle visualization, limit vendor chunk to under 300KB, and compare build output with and without manual chunks.
What's Next
You've mastered Vite dynamic imports. Now learn about Preload & Prefetch for hinting the browser about critical and future resources.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro