一键导入
web-performance
웹 성능 최적화 스킬. Core Web Vitals(LCP, FID, CLS, INP) 개선, 이미지/폰트 최적화, 코드 스플리팅, 캐싱 전략을 담당합니다.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
웹 성능 최적화 스킬. Core Web Vitals(LCP, FID, CLS, INP) 개선, 이미지/폰트 최적화, 코드 스플리팅, 캐싱 전략을 담당합니다.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
변경된 코드를 분석하여 관심사별로 그룹화하고, 각 그룹을 별도로 git add 하여 단계별 커밋을 수행합니다.
Git 커밋 내역을 분석하여 Obsidian 형식의 개발 기록 마크다운 자동 생성. "오늘 커밋 정리", "개발 기록 작성", "커밋 분석", "작업 로그" 요청 시 트리거. 커밋 메시지, 변경 파일, diff를 분석하여 frontmatter 메타데이터와 기술 개념 설명이 포함된 체계적인 문서 생성 후 Obsidian MCP로 저장.
AEO(Answer Engine Optimization) 및 GEO(Generative Engine Optimization) 최적화 스킬. AI 검색 엔진과 생성형 AI가 콘텐츠를 이해하고 인용할 수 있도록 최적화합니다.
블로그 SEO(검색 엔진 최적화) 전문 스킬. 메타데이터, sitemap, robots.txt, 구조화된 데이터, 캐노니컬 URL 등 기술적 SEO 구현을 담당합니다.
Schema.org 구조화된 데이터(JSON-LD) 구현 스킬. Article, FAQPage, BreadcrumbList, HowTo 등 다양한 스키마를 블로그에 적용합니다.
| name | web-performance |
| description | 웹 성능 최적화 스킬. Core Web Vitals(LCP, FID, CLS, INP) 개선, 이미지/폰트 최적화, 코드 스플리팅, 캐싱 전략을 담당합니다. |
| triggers | ["성능 최적화해줘","Core Web Vitals 개선","페이지 속도 개선","LCP 최적화"] |
이 스킬은 블로그의 웹 성능을 최적화합니다. Google의 Core Web Vitals는 SEO 랭킹 요소이므로 성능 최적화는 SEO와 직결됩니다.
| 지표 | 설명 | 목표값 |
|---|---|---|
| LCP | Largest Contentful Paint | < 2.5초 |
| INP | Interaction to Next Paint | < 200ms |
| CLS | Cumulative Layout Shift | < 0.1 |
// next.config.ts
const nextConfig = {
images: {
formats: ['image/avif', 'image/webp'],
deviceSizes: [640, 750, 828, 1080, 1200],
imageSizes: [16, 32, 48, 64, 96],
},
};
// Hero 이미지나 첫 번째 포스트 썸네일
<Image
src={heroImage}
alt="Hero"
priority // LCP 요소에 반드시 추가
sizes="(max-width: 768px) 100vw, 50vw"
/>
// app/layout.tsx
import localFont from 'next/font/local';
const mainFont = localFont({
src: './fonts/font.woff2',
display: 'swap', // FOIT 방지
preload: true,
fallback: ['system-ui', 'sans-serif'],
});
// app/layout.tsx
export const metadata: Metadata = {
other: {
'link': [
{ rel: 'preload', href: '/hero.webp', as: 'image' },
{ rel: 'preconnect', href: 'https://fonts.googleapis.com' },
],
},
};
// 나쁜 예 - 메인 스레드 블로킹
const handleClick = () => {
heavyComputation(); // 동기 실행
};
// 좋은 예 - 비동기 처리
const handleClick = async () => {
requestAnimationFrame(() => {
// UI 업데이트
});
await heavyComputation();
};
import { useTransition, useDeferredValue } from 'react';
function SearchComponent() {
const [isPending, startTransition] = useTransition();
const [query, setQuery] = useState('');
const deferredQuery = useDeferredValue(query);
const handleSearch = (value: string) => {
setQuery(value);
startTransition(() => {
// 낮은 우선순위 업데이트
performSearch(value);
});
};
}
// 동적 import로 번들 분리
import dynamic from 'next/dynamic';
const HeavyComponent = dynamic(
() => import('@/components/HeavyComponent'),
{
loading: () => <Skeleton />,
ssr: false, // 클라이언트 전용
}
);
// 항상 width, height 명시 또는 aspect-ratio 사용
<Image
src={thumbnail}
alt="Thumbnail"
width={800}
height={450}
className="aspect-video"
/>
// components/PostCardSkeleton.tsx
export function PostCardSkeleton() {
return (
<div className="animate-pulse">
<div className="aspect-video bg-gray-200 rounded-lg" />
<div className="h-6 bg-gray-200 rounded mt-4 w-3/4" />
<div className="h-4 bg-gray-200 rounded mt-2 w-1/2" />
</div>
);
}
/* font-display: swap과 함께 fallback 크기 조정 */
@font-face {
font-family: 'CustomFont';
src: url('/font.woff2') format('woff2');
font-display: swap;
size-adjust: 100%;
ascent-override: 90%;
descent-override: 20%;
}
// 외부 콘텐츠 공간 미리 확보
<div className="min-h-[250px]"> {/* 광고 높이 예약 */}
<AdComponent />
</div>
// app/api/posts/route.ts
export const revalidate = 3600; // 1시간마다 재검증
// 또는 동적 재검증
import { revalidatePath } from 'next/cache';
revalidatePath('/tech');
// app/[category]/[slug]/page.tsx
export const dynamicParams = true;
export const revalidate = 86400; // 24시간
export async function generateStaticParams() {
const posts = await getAllPosts();
return posts.map((post) => ({
category: post.category,
slug: post.slug,
}));
}
// next.config.ts
const nextConfig = {
async headers() {
return [
{
source: '/:all*(svg|jpg|png|webp|avif)',
headers: [
{
key: 'Cache-Control',
value: 'public, max-age=31536000, immutable',
},
],
},
];
},
};
// 나쁜 예 - 전체 라이브러리 import
import { format } from 'date-fns';
// 좋은 예 - 필요한 함수만 import
import format from 'date-fns/format';
# 번들 분석 실행
ANALYZE=true pnpm build
# 또는
npx @next/bundle-analyzer
// next.config.ts
const nextConfig = {
experimental: {
optimizePackageImports: ['lucide-react', 'date-fns'],
},
};
// lib/vitals.ts
import { onLCP, onINP, onCLS } from 'web-vitals';
export function reportWebVitals() {
onLCP(console.log);
onINP(console.log);
onCLS(console.log);
}
// app/layout.tsx (Client Component)
'use client';
import { reportWebVitals } from '@/lib/vitals';
import { useEffect } from 'react';
export function WebVitalsReporter() {
useEffect(() => {
reportWebVitals();
}, []);
return null;
}
# .github/workflows/lighthouse.yml
- name: Lighthouse CI
run: |
npm install -g @lhci/cli
lhci autorun
priority 속성display: swap