Performance Optimization
PikaCSS is designed for optimal performance by default, but there are strategies to further optimize your setup for production.
Build-Time Performance
1. Optimize File Scanning
Limit the files PikaCSS needs to scan:
// vite.config.ts
export default defineConfig({
plugins: [
pikacss({
scan: {
// ✅ Only scan necessary directories
include: ['src/**/*.{ts,tsx,vue}'],
// ✅ Explicitly exclude large directories
exclude: [
'node_modules/**',
'dist/**',
'coverage/**',
'**/*.test.{ts,tsx}',
'**/*.spec.{ts,tsx}'
]
}
})
]
})Impact: Faster builds and HMR (Hot Module Replacement)
2. Use Shortcuts Wisely
❌ Bad - Duplicate styles everywhere:
// Repeated in many components
<button className={pika({
padding: '0.5rem 1rem',
backgroundColor: '#3b82f6',
color: 'white',
borderRadius: '0.25rem',
cursor: 'pointer'
})} />✅ Good - Define once, reuse everywhere:
// pika.config.ts
shortcuts: [
['btn', {
padding: '0.5rem 1rem',
backgroundColor: '#3b82f6',
color: 'white',
borderRadius: '0.25rem',
cursor: 'pointer'
}]
]// Usage
<button className={pika('btn')} />Benefits:
- Faster build time (less code to analyze)
- Smaller source code
- Better maintainability
3. Minimize Dynamic Shortcuts
❌ Slower - Complex regex patterns:
shortcuts: [
// This runs on every potential match
[/^m-(\d+)$/, m => ({
margin: `${m[1]}px`,
padding: `${m[1]}px`,
// ... complex logic
}), ['m-4', 'm-8', 'm-16', /* ... hundreds of options */]]
]✅ Faster - Static shortcuts when possible:
shortcuts: [
['m-4', { margin: '4px' }],
['m-8', { margin: '8px' }],
['m-16', { margin: '16px' }],
// Only create what you actually use
]Runtime Performance
1. CSS Bundle Size
PikaCSS automatically generates atomic CSS, which is highly optimized:
/* Each property-value pair becomes a unique class */
.a { color: red; }
.b { font-size: 16px; }
.c { padding: 1rem; }
/* Reused across your entire application */
<div class="a b c">...</div>
<span class="a">...</span> <!-- "a" reused -->Automatic optimizations:
- ✅ Deduplication (same styles share classes)
- ✅ Short class names (
.a,.b,.c) - ✅ Minimal specificity (single class selectors)
2. Analyzing Bundle Size
Check your generated CSS file:
# View generated CSS size
ls -lh src/pika.gen.css
# Or use a bundler analyzer
pnpm add -D vite-bundle-visualizer// vite.config.ts
import { visualizer } from 'rollup-plugin-visualizer'
export default defineConfig({
plugins: [
pikacss(),
visualizer({ open: true })
]
})3. Minimize Unused Styles
PikaCSS only generates CSS for styles you actually use:
// pika.config.ts with unused shortcuts
shortcuts: [
['btn-primary', { /* used */ }],
['btn-secondary', { /* used */ }],
['btn-tertiary', { /* NEVER USED - still in config */ }], // ❌
]Solution: Regularly audit and remove unused shortcuts
# Search for shortcut usage
grep -r "btn-tertiary" src/
# If no results, remove from configLoading Performance
1. Critical CSS Inline
For optimal First Contentful Paint (FCP):
<!-- Inline critical CSS in HTML head -->
<head>
<style>
/* Inline pika.gen.css content */
.a{color:red}.b{font-size:16px}...
</style>
</head>Next.js example:
// app/layout.tsx
import fs from 'fs'
import path from 'path'
// Read generated CSS at build time
const pikaCSS = fs.readFileSync(
path.join(process.cwd(), 'src/pika.gen.css'),
'utf-8'
)
export default function RootLayout({ children }) {
return (
<html>
<head>
<style dangerouslySetInnerHTML={{ __html: pikaCSS }} />
</head>
<body>{children}</body>
</html>
)
}Benefits:
- ⚡ Eliminates CSS request
- ⚡ Faster FCP
- ⚡ No render-blocking CSS
Trade-off: Slightly larger HTML (usually worth it for critical styles)
2. Preload CSS
If not inlining, preload for faster loading:
<head>
<link rel="preload" href="/pika.gen.css" as="style">
<link rel="stylesheet" href="/pika.gen.css">
</head>3. CSS Minification
Enable CSS minification in production:
// vite.config.ts
export default defineConfig({
build: {
cssMinify: true // Default in production
}
})PikaCSS output is already minimal, but minification removes whitespace:
/* Before minification */
.a { color: red; }
.b { font-size: 16px; }
/* After minification */
.a{color:red}.b{font-size:16px}Code Splitting Strategies
1. Route-Based Splitting (Automatic)
Most bundlers automatically split CSS by route:
// pages/index.tsx
<div className={pika({ color: 'red' })} />
// pages/about.tsx
<div className={pika({ color: 'blue' })} />Each route gets only the CSS it needs (automatic with PikaCSS's atomic approach).
2. Component-Based Splitting
Use dynamic imports for large components:
// Heavy component loaded on-demand
const HeavyFeature = lazy(() => import('./HeavyFeature'))
function App() {
return (
<Suspense fallback={<div className={pika({ padding: '2rem' })}>Loading...</div>}>
<HeavyFeature />
</Suspense>
)
}3. Preflight Optimization
Move global styles to preflights:
// pika.config.ts
export default defineEngineConfig({
preflights: [
// ✅ Good - Global CSS in preflights
`* { box-sizing: border-box; margin: 0; padding: 0; }`,
`:root {
--color-primary: #3b82f6;
--color-secondary: #6b7280;
}`
]
})Don't use pika() for truly global styles:
// ❌ Bad - Global styles via pika()
const globalStyles = pika({
'*': {
boxSizing: 'border-box',
margin: '0',
padding: '0'
}
})Developer Experience Optimization
1. Hot Module Replacement (HMR)
PikaCSS supports HMR out of the box. Optimize by:
// vite.config.ts
export default defineConfig({
server: {
hmr: true // Enabled by default
},
plugins: [
pikacss({
// Faster HMR with focused scanning
scan: {
include: ['src/**/*.{ts,tsx}']
}
})
]
})2. TypeScript Performance
Generated pika.gen.ts provides autocomplete. Keep it fast:
// pika.config.ts
export default defineEngineConfig({
// ✅ Limit shortcuts to what you need
shortcuts: {
shortcuts: [
// 50 shortcuts: Fast
// 500 shortcuts: Slower TypeScript
// 5000 shortcuts: Very slow
]
}
})Rule of thumb: Keep shortcuts under 200 for optimal TypeScript performance.
3. Build Tool Caching
Enable persistent caching:
// vite.config.ts
export default defineConfig({
cacheDir: '.vite-cache', // Cache build artifacts
optimizeDeps: {
force: false // Use cache when possible
}
})Production Optimization Checklist
- [ ] Scan Optimization: Limit
includepatterns to necessary files - [ ] Exclude Tests: Don't scan test files (
**/*.test.ts) - [ ] Use Shortcuts: Extract repeated styles into shortcuts
- [ ] Remove Unused Shortcuts: Audit and clean config regularly
- [ ] CSS Minification: Enable in production build
- [ ] Consider Inlining: Inline CSS for critical pages
- [ ] Preload CSS: If not inlining, add preload hint
- [ ] Lazy Load: Use dynamic imports for heavy components
- [ ] Limit Complexity: Keep shortcuts under 200
- [ ] Use Preflights: Move global styles to preflights
- [ ] Enable Caching: Use build tool caching
- [ ] Monitor Bundle: Use bundle analyzers
Measuring Performance
1. Build Time
# Measure build time
time pnpm build2. Bundle Size
# Check generated CSS size
ls -lh dist/assets/*.css
# Check total bundle size
du -sh dist/3. Lighthouse Audit
# Run Lighthouse on production build
pnpm build
pnpm preview
# Open Chrome DevTools > Lighthouse > Run auditKey metrics to watch:
- First Contentful Paint (FCP)
- Largest Contentful Paint (LCP)
- Total Blocking Time (TBT)
- Cumulative Layout Shift (CLS)
4. Runtime Performance
// Measure style application time
console.time('pika-styles')
const classes = pika({ /* ... */ })
console.timeEnd('pika-styles') // Should be instant (build-time)PikaCSS has zero runtime cost - all processing happens at build time.
Comparison: Before and After Optimization
Before Optimization
// ❌ Scanning everything
scan: { include: ['**/*'] }
// ❌ No shortcuts, repeated styles
<Button className={pika({
padding: '0.5rem 1rem',
backgroundColor: '#3b82f6',
color: 'white',
borderRadius: '0.25rem'
})} />
// Repeated 50+ times across codebase
// ❌ Complex dynamic shortcuts
[/^m-(\d{1,3})$/, m => ({ margin: `${m[1]}px` }),
Array.from({length: 1000}, (_, i) => `m-${i}`)] // 1000 suggestions!
// Result:
// - Build time: 8s
// - CSS size: 150KB
// - TypeScript slowAfter Optimization
// ✅ Focused scanning
scan: {
include: ['src/**/*.{ts,tsx}'],
exclude: ['**/*.test.ts']
}
// ✅ Shortcuts for common patterns
shortcuts: [
['btn-primary', {
padding: '0.5rem 1rem',
backgroundColor: '#3b82f6',
color: 'white',
borderRadius: '0.25rem'
}]
]
<Button className={pika('btn-primary')} />
// ✅ Limited dynamic shortcuts
[/^m-(\d+)$/, m => ({ margin: `${m[1]}px` }),
['m-4', 'm-8', 'm-16', 'm-24']] // Only common values
// Result:
// - Build time: 3s (62% faster)
// - CSS size: 45KB (70% smaller)
// - TypeScript fastAdvanced Optimization Techniques
1. Conditional Plugin Loading
// vite.config.ts
export default defineConfig({
plugins: [
// Only run PikaCSS in development and production builds
process.env.NODE_ENV !== 'test' && pikacss()
].filter(Boolean)
})2. Parallel Build Processing
// vite.config.ts
export default defineConfig({
build: {
rollupOptions: {
output: {
manualChunks: {
// Split vendor and app CSS
'pika-styles': ['pika.css']
}
}
}
}
})3. CSS Purging (Advanced)
For extremely large applications, consider additional purging:
pnpm add -D purgecss// postcss.config.js
module.exports = {
plugins: [
process.env.NODE_ENV === 'production' && require('@fullhuman/postcss-purgecss')({
content: ['./src/**/*.{ts,tsx}'],
defaultExtractor: content => content.match(/[\w-/:]+(?<!:)/g) || []
})
].filter(Boolean)
}Note: Usually not needed due to PikaCSS's atomic nature.
Troubleshooting Performance Issues
Issue: Slow Build Times
Diagnose:
# Enable verbose logging
VITE_DEBUG=pikacss pnpm buildSolutions:
- Narrow
scan.includepatterns - Add more to
scan.exclude - Reduce number of shortcuts
- Simplify dynamic shortcut patterns
Issue: Large CSS Bundle
Diagnose:
ls -lh src/pika.gen.cssSolutions:
- Remove unused shortcuts
- Avoid overly specific selectors
- Use CSS variables instead of many color variations
- Enable production minification
Issue: Slow TypeScript
Diagnose: Check pika.gen.ts file size:
wc -l src/pika.gen.tsSolutions:
- Reduce number of shortcuts (< 200)
- Limit dynamic shortcut autocomplete arrays
- Restart TypeScript server
Best Practices Summary
- ✅ Scan only what's needed - Focused include/exclude patterns
- ✅ Use shortcuts for repetition - DRY principle
- ✅ Keep shortcuts manageable - Under 200 for best TypeScript perf
- ✅ Inline critical CSS - For optimal FCP
- ✅ Enable minification - Always in production
- ✅ Monitor bundle size - Regular audits
- ✅ Leverage atomic CSS - Natural deduplication
- ✅ Use preflights for globals - Cleaner separation
- ✅ Measure regularly - Build time, bundle size, Lighthouse
- ✅ Profile and iterate - Continuous optimization
Next Steps
- Review Troubleshooting Guide for common issues
- Explore SSR/SSG Guide for server-side optimization
- Check Examples for optimized patterns