Build Optimization Patterns
Vite Configuration
// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { visualizer } from 'rollup-plugin-visualizer';
import { compression } from 'vite-plugin-compression2';
export default defineConfig({
plugins: [
react(),
compression({ algorithm: 'gzip' }),
compression({ algorithm: 'brotliCompress', ext: '.br' }),
visualizer({ open: false, gzipSize: true, filename: 'dist/stats.html' }),
],
build: {
target: 'es2020',
minify: 'esbuild',
sourcemap: true,
rollupOptions: {
output: {
manualChunks: {
'react-vendor': ['react', 'react-dom', 'react-router-dom'],
'ui-vendor': ['@radix-ui/react-dialog', '@radix-ui/react-dropdown-menu'],
'query': ['@tanstack/react-query'],
'charts': ['recharts'],
},
chunkFileNames: 'assets/[name]-[hash].js',
assetFileNames: 'assets/[name]-[hash].[ext]',
}
}
},
resolve: {
alias: { '@': '/src' }
}
});
Tree Shaking
// WRONG: imports entire library
import _ from 'lodash';
const result = _.groupBy(items, 'category');
// RIGHT: named import (tree-shakeable)
import { groupBy } from 'lodash-es';
const result = groupBy(items, 'category');
// Or use native
const result = Object.groupBy(items, i => i.category);
// Check if library is ESM (package.json "module" field)
// Use bundlephobia.com to check package size
Code Splitting Strategies
// Route-level splitting
import { lazy, Suspense } from 'react';
const Dashboard = lazy(() => import('./pages/Dashboard'));
const Settings = lazy(() => import('./pages/Settings'));
// Component-level (heavy components)
const RichEditor = lazy(() => import('./components/RichEditor'));
const VideoPlayer = lazy(() => import('./components/VideoPlayer'));
// With loading boundary
<Suspense fallback={<PageSkeleton />}>
<Dashboard />
</Suspense>
// Prefetch on hover/focus
function NavLink({ to, children }) {
const prefetch = () => import(`./pages/${to}`);
return <Link to={to}
}
Bundle Analysis
# Vite: open stats.html after build
npx vite build && open dist/stats.html
# Webpack Bundle Analyzer
npx webpack-bundle-analyzer dist/stats.json
# Check what's in a package
npx bundlephobia lodash
Module Federation (Vite)
// host/vite.config.ts
import federation from '@originjs/vite-plugin-federation';
export default defineConfig({
plugins: [federation({
name: 'host',
remotes: {
mfe_auth: 'http://localhost:3001/assets/remoteEntry.js',
mfe_dashboard: 'http://localhost:3002/assets/remoteEntry.js',
},
shared: ['react', 'react-dom'],
})]
});
// remote/vite.config.ts
export default defineConfig({
plugins: [federation({
name: 'mfe_auth',
filename: 'remoteEntry.js',
exposes: { './LoginForm': './src/components/LoginForm' },
shared: ['react', 'react-dom'],
})],
build: { target: 'esnext' }
});
CDN & Cache Headers
# Long-term cache for hashed assets
location /assets/ {
add_header Cache-Control "public, max-age=31536000, immutable";
}
# Short cache for HTML
location / {
add_header Cache-Control "public, max-age=0, must-revalidate";
try_files $uri /index.html;
}
Environment-Based Optimization
// vite.config.ts
export default defineConfig(({ mode }) => ({
define: {
__DEV__: mode === 'development',
},
build: {
minify: mode === 'production',
sourcemap: mode !== 'production',
}
}));