| name | performance-optimization |
| description | Optimize application performance for speed, efficiency, and scalability. Use when improving page load times, reducing bundle size, optimizing database queries, or fixing performance bottlenecks. Handles React optimization, lazy loading, caching, code splitting, and profiling. |
| tags | ["performance","optimization","React","lazy-loading","caching","profiling","web-vitals"] |
| platforms | ["Claude","ChatGPT","Gemini"] |
Performance Optimization
When to use this skill
- ๋๋ฆฐ ํ์ด์ง ๋ก๋: Lighthouse ์ ์ ๋ฎ์
- ๋๋ฆฐ ๋ ๋๋ง: ์ฌ์ฉ์ ์ธํฐ๋์
์ง์ฐ
- ํฐ ๋ฒ๋ค ํฌ๊ธฐ: ๋ค์ด๋ก๋ ์๊ฐ ์ฆ๊ฐ
- ๋๋ฆฐ ์ฟผ๋ฆฌ: ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ณ๋ชฉ
Instructions
Step 1: ์ฑ๋ฅ ์ธก์
Lighthouse (Chrome DevTools):
npm install -g lighthouse
lighthouse https://example.com --view
lighthouse https://example.com --output=json --output-path=./report.json
Web Vitals ์ธก์ (React):
import { getCLS, getFID, getFCP, getLCP, getTTFB } from 'web-vitals';
function sendToAnalytics(metric: any) {
console.log(metric);
}
getCLS(sendToAnalytics);
getFID(sendToAnalytics);
getFCP(sendToAnalytics);
getLCP(sendToAnalytics);
getTTFB(sendToAnalytics);
Step 2: React ์ต์ ํ
React.memo (๋ถํ์ํ ๋ฆฌ๋ ๋๋ง ๋ฐฉ์ง):
function ExpensiveComponent({ data }: { data: Data }) {
return <div>{/* ๋ณต์กํ ๋ ๋๋ง */}</div>;
}
const ExpensiveComponent = React.memo(({ data }: { data: Data }) => {
return <div>{/* ๋ณต์กํ ๋ ๋๋ง */}</div>;
});
useMemo & useCallback:
function ProductList({ products, category }: Props) {
const filteredProducts = useMemo(() => {
return products.filter(p => p.category === category);
}, [products, category]);
const handleAddToCart = useCallback((id: string) => {
addToCart(id);
}, []);
return (
<div>
{filteredProducts.map(product => (
<ProductCard key={product.id} product={product} onAdd={handleAddToCart} />
))}
</div>
);
}
Lazy Loading & Code Splitting:
import { lazy, Suspense } from 'react';
const Dashboard = lazy(() => import('./pages/Dashboard'));
const Profile = lazy(() => import('./pages/Profile'));
const Settings = lazy(() => import('./pages/Settings'));
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<Routes>
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/profile" element={<Profile />} />
<Route path="/settings" element={<Settings />} />
</Routes>
</Suspense>
);
}
const HeavyChart = lazy(() => import('./components/HeavyChart'));
function Dashboard() {
return (
<div>
<h1>Dashboard</h1>
<Suspense fallback={<Skeleton />}>
<HeavyChart data={data} />
</Suspense>
</div>
);
}
Step 3: ๋ฒ๋ค ํฌ๊ธฐ ์ต์ ํ
Webpack Bundle Analyzer:
npm install --save-dev webpack-bundle-analyzer
{
"scripts": {
"analyze": "webpack-bundle-analyzer build/stats.json"
}
}
Tree Shaking (์ฌ์ฉํ์ง ์๋ ์ฝ๋ ์ ๊ฑฐ):
import _ from 'lodash';
import debounce from 'lodash/debounce';
Dynamic Imports:
button.addEventListener('click', async () => {
const { default: Chart } = await import('chart.js');
new Chart(ctx, config);
});
Step 4: ์ด๋ฏธ์ง ์ต์ ํ
Next.js Image ์ปดํฌ๋ํธ:
import Image from 'next/image';
function ProductImage() {
return (
<Image
src="/product.jpg"
alt="Product"
width={500}
height={500}
priority // LCP ์ด๋ฏธ์ง์ธ ๊ฒฝ์ฐ
placeholder="blur" // ๋ธ๋ฌ ํ๋ ์ด์คํ๋
sizes="(max-width: 768px) 100vw, 50vw"
/>
);
}
WebP ํฌ๋งท ์ฌ์ฉ:
<picture>
<source srcset="image.webp" type="image/webp">
<source srcset="image.jpg" type="image/jpeg">
<img src="image.jpg" alt="Fallback">
</picture>
Step 5: ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฟผ๋ฆฌ ์ต์ ํ
N+1 ์ฟผ๋ฆฌ ๋ฌธ์ ํด๊ฒฐ:
const posts = await db.post.findMany();
for (const post of posts) {
const author = await db.user.findUnique({ where: { id: post.authorId } });
}
const posts = await db.post.findMany({
include: {
author: true
}
});
์ธ๋ฑ์ค ์ถ๊ฐ:
EXPLAIN ANALYZE SELECT * FROM users WHERE email = 'test@example.com';
CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_orders_user_date ON orders(user_id, created_at);
์บ์ฑ (Redis):
async function getUserProfile(userId: string) {
const cached = await redis.get(`user:${userId}`);
if (cached) {
return JSON.parse(cached);
}
const user = await db.user.findUnique({ where: { id: userId } });
await redis.setex(`user:${userId}`, 3600, JSON.stringify(user));
return user;
}
Output format
์ฑ๋ฅ ์ต์ ํ ์ฒดํฌ๋ฆฌ์คํธ
## Frontend
- [ ] React.memo๋ก ๋ถํ์ํ ๋ฆฌ๋ ๋๋ง ๋ฐฉ์ง
- [ ] useMemo/useCallback ์ ์ ํ ์ฌ์ฉ
- [ ] Lazy loading & Code splitting
- [ ] ์ด๋ฏธ์ง ์ต์ ํ (WebP, lazy loading)
- [ ] ๋ฒ๋ค ํฌ๊ธฐ ๋ถ์ ๋ฐ ๊ฐ์
## Backend
- [ ] N+1 ์ฟผ๋ฆฌ ์ ๊ฑฐ
- [ ] ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ธ๋ฑ์ค ์ถ๊ฐ
- [ ] Redis ์บ์ฑ
- [ ] API Response ์์ถ (gzip)
- [ ] CDN ์ฌ์ฉ
## ์ธก์
- [ ] Lighthouse ์ ์ 90+
- [ ] LCP < 2.5s
- [ ] FID < 100ms
- [ ] CLS < 0.1
Constraints
ํ์ ๊ท์น (MUST)
- ์ธก์ ๋จผ์ : ์ถ์ธกํ์ง ๋ง๊ณ ํ๋กํ์ผ๋ง
- ์ ์ง์ ๊ฐ์ : ํ ๋ฒ์ ํ๋์ฉ ์ต์ ํ
- ์ฑ๋ฅ ๋ชจ๋ํฐ๋ง: ์ง์์ ์ผ๋ก ์ถ์
๊ธ์ง ์ฌํญ (MUST NOT)
- ์กฐ๊ธฐ ์ต์ ํ: ๋ณ๋ชฉ์ด ์๋๋ฐ ์ต์ ํํ์ง ์์
- ๊ฐ๋
์ฑ ํฌ์: ์ฑ๋ฅ์ ์ํด ์ฝ๋๋ฅผ ๋ณต์กํ๊ฒ ๋ง๋ค์ง ์์
Best practices
- 80/20 ๋ฒ์น: 20% ๋
ธ๋ ฅ์ผ๋ก 80% ๊ฐ์
- ์ฌ์ฉ์ ์ค์ฌ: ์ค์ ์ฌ์ฉ์ ๊ฒฝํ ๊ฐ์ ์ ์ง์ค
- ์๋ํ: CI์์ ์ฑ๋ฅ ํ๊ท ํ
์คํธ
References
Metadata
๋ฒ์
- ํ์ฌ ๋ฒ์ : 1.0.0
- ์ต์ข
์
๋ฐ์ดํธ: 2025-01-01
- ํธํ ํ๋ซํผ: Claude, ChatGPT, Gemini
๊ด๋ จ ์คํฌ
ํ๊ทธ
#performance #optimization #React #caching #lazy-loading #web-vitals #code-quality
Examples
Example 1: Basic usage
Example 2: Advanced usage