Loading...
Loading...
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.
npx skill4agent add supercent-io/skills-template performance-optimization# CLI
npm install -g lighthouse
lighthouse https://example.com --view
# CI에서 자동화
lighthouse https://example.com --output=json --output-path=./report.jsonimport { getCLS, getFID, getFCP, getLCP, getTTFB } from 'web-vitals';
function sendToAnalytics(metric: any) {
// Google Analytics, Datadog 등으로 전송
console.log(metric);
}
getCLS(sendToAnalytics);
getFID(sendToAnalytics);
getFCP(sendToAnalytics);
getLCP(sendToAnalytics);
getTTFB(sendToAnalytics);// ❌ 나쁜 예: 부모가 리렌더링될 때마다 자식도 리렌더링
function ExpensiveComponent({ data }: { data: Data }) {
return <div>{/* 복잡한 렌더링 */}</div>;
}
// ✅ 좋은 예: props 변경 시에만 리렌더링
const ExpensiveComponent = React.memo(({ data }: { data: Data }) => {
return <div>{/* 복잡한 렌더링 */}</div>;
});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>
);
}import { lazy, Suspense } from 'react';
// ✅ Route-based code splitting
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>
);
}
// ✅ Component-based lazy loading
const HeavyChart = lazy(() => import('./components/HeavyChart'));
function Dashboard() {
return (
<div>
<h1>Dashboard</h1>
<Suspense fallback={<Skeleton />}>
<HeavyChart data={data} />
</Suspense>
</div>
);
}npm install --save-dev webpack-bundle-analyzer
# package.json
{
"scripts": {
"analyze": "webpack-bundle-analyzer build/stats.json"
}
}// ❌ 나쁜 예: 전체 라이브러리 임포트
import _ from 'lodash';
// ✅ 좋은 예: 필요한 것만 임포트
import debounce from 'lodash/debounce';// ✅ 필요할 때만 로드
button.addEventListener('click', async () => {
const { default: Chart } = await import('chart.js');
new Chart(ctx, config);
});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"
/>
);
}<picture>
<source srcset="image.webp" type="image/webp">
<source srcset="image.jpg" type="image/jpeg">
<img src="image.jpg" alt="Fallback">
</picture>// ❌ 나쁜 예: N+1 queries
const posts = await db.post.findMany();
for (const post of posts) {
const author = await db.user.findUnique({ where: { id: post.authorId } });
// 101번 쿼리 (1 + 100)
}
// ✅ 좋은 예: JOIN 또는 include
const posts = await db.post.findMany({
include: {
author: true
}
});
// 1번 쿼리-- 느린 쿼리 식별
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);async function getUserProfile(userId: string) {
// 1. 캐시 확인
const cached = await redis.get(`user:${userId}`);
if (cached) {
return JSON.parse(cached);
}
// 2. DB 조회
const user = await db.user.findUnique({ where: { id: userId } });
// 3. 캐시 저장 (1시간)
await redis.setex(`user:${userId}`, 3600, JSON.stringify(user));
return user;
}## 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#performance#optimization#React#caching#lazy-loading#web-vitals#code-quality