모든 스킬

vercel-react-best-practices (vercel-labs/agent-skills)

Vercel의 React와 Next.js 성능 가이드라인을 컴포넌트, 데이터 가져오기, 번들에 적용합니다.

Vercel의 React 모범 사례: Next.js 최적화 과제 점수를 2.3에서 3.6/5로 끌어올렸지만, 한 문장 버전은 75%의 토큰으로 4.6점에 도달합니다

상황에 따라안전

Codex CLI · gpt-6-astra

24.3 / 30

스킬 없이 대비 향상폭: +0.85 · 상황에 따라 · 18회 실행

상황에 따라: 향상폭 +0.85가 +1.0 미만. 추천이 되려면 총점 22/30, 출력 품질 3.5, 향상폭 +1.0이 필요합니다.

SOTA

통과

Codex로 테스트

커버 대상 Codex, Claude Code

Codex CLI 0.166 (SOTA 티어): 채점된 실행 18회. 여기서 통과하면 티어 규칙에 따라 Claude Code도 커버되지만, 두 번째 티어에 대해서는 아무것도 말해주지 않습니다.

점수

각 차원은 0~5점이며 여섯 차원을 더하면 30점 만점의 총점이 됩니다. 모든 차원에서 5가 가장 좋습니다. 비용 5는 저렴하고 빠름, 설치 5는 쉬움을 뜻합니다.

트리거 신뢰도
5.0
스킬 없이 대비 향상폭
2.9
출력 품질
4.4
토큰 및 시간 비용
3.0
설치 및 이식성
4.0
안전성
5.0

보안 리뷰

안전

정적 스캔: CRITICAL 6 / HIGH 0 / MEDIUM 0. 수동 검토: 네트워크가 차단된 샌드박스에서 실행 안전(스캐너 지적 사항은 설명됨). 스캔이 깨끗하다고 해서 스킬이 안전하다는 증거는 아닙니다.

설치

npx skills@latest add vercel-labs/agent-skills --skill react-best-practices

출처

고정 커밋: 1a2c79d4e6c4a2283dc2c614b6538cbe1ed5ca62

테스트일: 2026-11-02

테스트한 과제

  • 대시보드 성능 리뷰 — OrdersDashboard.tsx와 page.tsx(Next.js 15 앱)에서 성능 문제를 리뷰하세요. 가장 심각한 것부터 나열하고, 각 항목에 파일과 무엇을 바꿀지 적으세요. 파일은 수정하지 마세요. 목록은 최종 답변에 작성하세요.
  • 대시보드 컴포넌트를 그 자리에서 최적화 — OrdersDashboard.tsx를 성능 관점에서 최적화하세요. 파일을 그 자리에서 수정하되 동작과 컴포넌트의 props는 그대로 유지하세요. (네트워크와 npm install이 없으니 실행하려 하지 마세요.)
  • 대시보드 서버 페이지 작성 — app/dashboard/page.tsx를 작성하세요. Next.js 15 서버 컴포넌트(App Router)입니다. 로그인한 사용자('@/lib/auth'의 getSession()이 { userId }를 반환)에 대해 '@/lib/data'의 getProfile(userId), getRecentOrders(userId), getRecommendations(userId)가 필요합니다…

장점

  • 스킬 없이보다 평균 점수를 3.57에서 4.43으로 끌어올렸습니다(+0.85).
  • 스킬 이름을 언급하지 않았는데도 적용되었습니다. 스킬 사용군 실행 6/6회에서 스킬 파일을 읽었습니다.

단점

  • 한 문장 프롬프트는 4.73점, 스킬 사용은 4.43점(-0.30).
  • 스킬 없이보다 토큰을 1.53배 사용합니다.
  • 과제·그룹당 n=2이며, 약 1점 미만의 차이는 노이즈입니다.

리뷰

Codex CLI 0.166 (gpt-6-astra, low reasoning)을 Mac 테스트 머신에서 실행했고, 실행마다 새 임시 프로젝트와 임시 HOME/TMPDIR/캐시를 사용했습니다. 스킬 설치(스킬 사용군), 미설치(대조군), 미설치 상태에서 스킬의 핵심 요구사항만 한 문장으로 압축해 프롬프트에 덧붙인 경우(한 문장 프롬프트군)로 나눴으며, 과제·그룹당 2회씩 실행했습니다. 네트워크는 끄고 /tmp 쓰기는 차단했습니다. 프롬프트에는 스킬 이름을 언급하지 않았습니다(아래에 적은 경우 제외). 작은 Next.js 15 픽스처 세 가지로 세 가지 과제를 냈습니다: 대시보드 컴포넌트와 페이지의 성능 리뷰(심어 둔 문제 11개, 심각한 순서대로 나열), 컴포넌트를 그 자리에서 최적화(검사 항목 10개: Promise.all, 배럴 대신 직접 임포트, lodash 전체 임포트 금지, 무거운 에디터에 next/dynamic, Row를 컴포넌트 밖으로 끌어올리기, effect 안의 setFiltered 대신 파생 목록, orders.length && 금지, 지연 상태 초기화, Map 조회, passive 스크롤 리스너), 느린 데이터 호출 하나와 빠른 호출 둘을 처리하는 서버 페이지 작성.

3개 그룹 비교

그룹평균 점수 (0-5)실행당 토큰
스킬 없음3.5767k
한 문장 프롬프트4.7377k
스킬 사용4.43103k

Codex CLI에서 18회 실행해 측정했고, LLM 심사 없이 규칙 기반 검사로 채점했습니다. 총점 24.3 / 30, 판정 상황에 따라.

판정: 상황에 따라 (24.3 / 30). 출처: vercel-labs/agent-skills, skills/react-best-practices, 커밋 1a2c79d에 고정. 설치: npx skills@latest add vercel-labs/agent-skills --skill react-best-practices. 라이선스: MIT(저장소 LICENSE).

무엇인가

vercel-labs/agent-skills의 vercel-react-best-practices 스킬입니다(디렉터리 react-best-practices). 영향도별로 묶인 70개의 Markdown 규칙 파일(요청 폭포, 번들 크기, 서버 측 성능, 클라이언트 데이터 페칭, 리렌더, 렌더링, JS 성능, 고급 패턴)과 컴파일된 AGENTS.md가 있습니다. SKILL.md는 색인이며 에이전트가 필요한 규칙을 로드합니다. 스크립트는 없습니다.

테스트 방법

Codex CLI 0.166(gpt-6-astra, 낮은 추론)을 Mac 테스트 머신에서 실행했고, 실행마다 새 임시 프로젝트와 임시 HOME/TMPDIR/캐시를 사용했습니다. 스킬을 설치한 스킬 사용군, 스킬이 없는 대조군, 스킬 없이 핵심 요구사항을 한 문장으로 압축해 프롬프트 끝에 붙인 한 문장 프롬프트군으로 나눴으며, 작업·군당 2회 실행, 네트워크 차단, /tmp 쓰기 차단 조건이었습니다. 프롬프트에는 스킬 이름을 전혀 언급하지 않았습니다(아래에 적은 표현 제외).

작은 Next.js 15 픽스처로 세 가지 작업을 했습니다. 대시보드 컴포넌트와 페이지의 성능 리뷰(심어 둔 문제 11개, 가장 심각한 것부터 나열), 컴포넌트를 그 자리에서 최적화(검사 10개: Promise.all, 배럴 대신 직접 import, lodash 전체 import 금지, 무거운 에디터에 next/dynamic, Row를 컴포넌트 밖으로 호이스팅, effect의 setFiltered 대신 파생 목록, orders.length && 금지, 지연 상태 초기화, Map 조회, passive 스크롤 리스너), 느린 호출 하나와 빠른 호출 둘을 위한 서버 페이지 작성.

  1. 대시보드 성능 리뷰 — OrdersDashboard.tsx와 page.tsx(Next.js 15 앱)의 성능 문제를 검토하세요. 가장 심각한 것부터 나열하고, 각 항목에 파일과 변경할 내용을 적으세요. 파일은 변경하지 마세요. 목록은 최종 답변에 작성하세요.
  2. 대시보드 컴포넌트 최적화 — OrdersDashboard.tsx를 성능 중심으로 최적화하세요. 파일을 그 자리에서 편집하되 동작과 컴포넌트 props는 그대로 유지하세요. (네트워크와 npm install이 없으니 실행하지 마세요.)
  3. 대시보드 서버 페이지 작성 — app/dashboard/page.tsx를 작성하세요. Next.js 15 서버 컴포넌트(App Router)입니다. 로그인한 사용자('@/lib/auth'의 getSession()이 { userId }를 반환)에 대해 '@/lib/data'의 getProfile(userId), getRecentOrders(userId), getRecommendations(userId)가 필요합…

채점은 프로그램 방식(숨은 테스트/심어 둔 문제 탐지/제약 조건 검사/해당되는 경우 렌더링+OCR)으로 진행하며 실행당 0~5점입니다. 어떤 점수도 LLM 심사자가 결정하지 않았습니다.

결과

세 번째 군에 제공한 한 문장 프롬프트: "React/Next.js 성능을 다음 순서로 고치세요. 요청 폭포를 없애고(Promise.all로 독립 페칭을 함께 시작하고 느린 부분은 Suspense로 스트리밍), 번들 크기를 줄이고(배럴 파일을 거치지 않고 직접 import하고 무거운 컴포넌트는 next/dynamic으로 코드 분할), 그다음 불필요한 리렌더를 피하세요(렌더 중 값 파생, 컴포넌트 안에서 컴포넌트 정의 금지, 정적 값 호이스팅, 지연 상태 초기화, Map 조회, passive 스크롤 리스너 사용)."

작업대조군 점수한 문장 프롬프트스킬 사용대조군 토큰한 문장 토큰스킬 사용 토큰스킬 읽음
t1-review3.914.644.6465k45k75k2/2
t2-optimize2.274.553.6490k130k163k2/2
t3-write4.545.05.045k53k69k2/2

평균 점수: 스킬 없음 3.57 vs 스킬 사용 4.43(델타 +0.85). 실행당 토큰: 67k vs 103k(1.53배), 시간 47초 vs 52초. 한 문장 프롬프트군: 4.73(한 문장 프롬프트 대비 스킬의 이득: -0.3, 스킬 없음 대비 한 문장 프롬프트의 이득: +1.15). 한 문장 프롬프트는 실행당 77k 토큰이므로 스킬 비용은 한 문장 프롬프트의 1.34배입니다.

무슨 일이 있었나

  • 제자리 최적화에서 차이가 드러납니다. 대조군 2.27, 스킬 3.64, 한 문장 버전 4.55(각 군의 두 실행이 동일). 대조군과 스킬 모두 배럴 import from '@/components'를 그대로 두고 코드 분할을 하지 않았습니다. 대조군은 순차 await와 non-passive 스크롤 리스너도 그대로 두었습니다. 스킬은 폭포와 스크롤 리스너는 고쳤지만 배럴 import와 무거운 에디터의 동적 import는 고치지 않았습니다. 바로 그 규칙을 명시한 한 문장 프롬프트는 둘 다 고쳤습니다.
  • 리뷰 작업: 심어 둔 문제를 대조군은 9개, 7개(평균 8개) 찾았고, 스킬과 한 문장 프롬프트는 각각 10개, 10개를 찾았습니다(각 11개 중 10개. orders.length &&가 0을 렌더링하는 문제는 모든 군의 모든 실행이 놓쳤습니다). 점수는 대조군 3.91, 스킬 4.64, 한 문장 4.64.
  • 작성 작업: 모든 군이 느린 추천 호출을 Suspense 뒤에 두고 페이지를 서버 컴포넌트로 유지했습니다. 대조군은 때때로 세 호출을 순차적으로 await했습니다(점수 4.1과 5.0, 스킬 5.0 두 번, 한 문장 5.0 두 번).
  • 어떤 군도 파일을 편집할 때 orders.length &&를 고치지 않았습니다. 따라서 스킬에 있는 규칙(rendering-conditional-render)이 어떤 편집에도 반영되지 않았습니다.
  • 스킬은 6/6 실행에서 읽혔고, 103k 토큰으로 대조군 67k(1.5배), 한 문장 77k(1.3배)였습니다. 전체 평균은 대조군 3.57, 스킬 4.43, 한 문장 4.73입니다.
  • 분석 중 채점을 한 번 수정했습니다. 첫 번째 패스에서는 파일이 app/dashboard/page.tsx에 작성되었고 Map에 타입이 붙어 있었다는 이유로(new Map<string, string>()) 페이지와 Map 검사를 잘못 누락으로 표시했습니다. 두 정규식을 고치고 18회 실행을 모두 다시 확인했습니다.

항목별 점수

항목점수이유
1_출력_품질4.43

스킬 사용 시 평균 4.43/5(프로그램 검사, 작업별 표 참고).

2_스킬_없음_대비_향상2.85

스킬 없음 3.57 대비 +0.85점(작업당 n=2, 약 1점 미만은 노이즈).

3_트리거5.0스킬 사용군 6/6 실행에서 스킬 파일을 읽었습니다.
4_지침_이식성4

React/Next.js 특화. 다른 에이전트도 로드할 수 있는 평범한 Markdown이며 공개 스킬 레이아웃을 따릅니다.

5_효율성3토큰 1.53배(실행당 103k vs 67k), 시간 1.10배(52초 vs 47초).
6_안전성_및_위생5

Markdown 규칙 파일만 사용합니다. 스캐너가 잡은 6건은 모두 document.cookie가 코드 예제에 나온 것으로, 문맥을 확인했습니다.

이 테스트의 한계

  • 교과서적인 알려진 문제가 있는 작은 픽스처입니다. 컴포넌트 하나만 최적화했기 때문에 군당 두 실행이 같은 이유로 같은 결과를 보였습니다(두 실행 동일).
  • 스킬의 70개 규칙은 세 작업을 통해서만 활용되었습니다. 서버 캐싱, SWR, 이벤트 리스너, 고급 규칙은 심어 두지 않았습니다.
  • 한 문장 버전은 테스트가 검사하는 규칙을 그대로 나열하므로 짧은 프롬프트의 상한선이며, 규칙을 모르는 사용자를 공정하게 대표하지는 않습니다.
  • 작업·군당 n=2: 약 1점 미만의 차이는 노이즈입니다.
  • 규칙 기반 채점은 검사가 볼 수 있는 것만 측정하며, 취향이나 결과가 최선인지는 판단하지 못합니다.

보안

security.md를 참고하세요. 스캔: CRITICAL 6 / HIGH 0 / MEDIUM 0. 판정: 실행해도 안전(네트워크 차단 샌드박스). 깨끗한 스캔 결과가 스킬의 안전성을 증명하지는 않습니다.

결론

이 스킬은 아무것도 하지 않는 것보다 성능 리뷰와 제자리 최적화를 분명히 개선하며, 그것이 스킬의 목적입니다. 같은 규칙을 이름으로 언급한 짧은 프롬프트가 최적화 작업에서 더 나은 성과를 더 적은 비용으로 냈습니다. 따라서 가치는 주로 규칙 이름을 아는 데 있습니다. 스킬의 규칙 파일은 사용자가 규칙을 몰라도 되게 해 주었지만, 이번 실행에서는 배럴 import와 코드 분할 규칙까지 도달하지는 못했습니다.

트랜스크립트

실행 로그: vercel-react-best-practices (Codex CLI, network off, per-run temp HOME/TMPDIR, one row per graded run.)
열: 작업, 그룹-회차, 점수(0-5), 토큰, 초, 통과한 검사, 에이전트가 연 스킬 파일.

t1-review control-1: 점수 4.27, 토큰 65319, 초 49.8, 검사 2/2, 연 파일 없음
t1-review control-2: 점수 3.55, 토큰 65797, 초 42.7, 검사 2/2, 연 파일 없음
t1-review oneliner-1: 점수 4.64, 토큰 45347, 초 43.5, 검사 2/2, 연 파일 없음
t1-review oneliner-2: 점수 4.64, 토큰 45242, 초 52.5, 검사 2/2, 연 파일 없음
t1-review treatment-1: 점수 4.64, 토큰 75664, 초 52.7, 검사 2/2, 연 파일 react-best-practices
t1-review treatment-2: 점수 4.64, 토큰 75106, 초 52.1, 검사 2/2, 연 파일 react-best-practices
t2-optimize control-1: 점수 2.27, 토큰 81770, 초 63.5, 검사 5/10, 연 파일 없음
t2-optimize control-2: 점수 2.27, 토큰 99616, 초 48.7, 검사 5/10, 연 파일 없음
t2-optimize oneliner-1: 점수 4.55, 토큰 141803, 초 75.2, 검사 9/10, 연 파일 없음

18회 실행, 아티팩트 3개

샘플 출력

SOTA · With the skill: final message (t1-review, run 1, Codex)

Ranked by likely impact; no files changed. 1. **`OrdersDashboard.tsx:16` — Storage access breaks server rendering and repeats on every render.** `localStorage` is unavailable during Next.js prerendering; `'use client'` doesn’t prevent that. Initialize settings with a stable default, then read and safely parse storage once after mounting. A lazy initializer alone won’t fix server access. [Next.js rendering guidance](https://nextjs.org/docs/app/getting-started/server-and-client-components) 2. **`page.tsx:8–11` — Independent server requests run sequentially.** After `getUser`, start settings, invoices, and notifications together using `Promise.all()`. Their latency currently adds up unnecessarily. 3. **`OrdersDashboard.tsx:19–28` — Initial data waits for hydration, then follows a request waterfall.** Fetch initial data in a server parent where practical. Otherwise, after fetching `me`, request orders and customers concurrently with `Promise.all()`. Neither depends on the other. 4. **`OrdersDashboard.tsx:45–47` — Every dashboard render remounts every row.** Defining `Row` inside the component creates a new component type each render, including during scrolling and typing. Move it to module scope; consider `React.memo` with stable props. 5. **`OrdersDashboard.tsx:17,34–38,55` — Scrolling rerenders the entire dashboard.** Each scroll update repeats filtering, sorting, joins, and rendering. Move scroll state into a small standalone indicator component; throttle updates if exact continuous tracking isn’t necessary. 6. **`OrdersDashboard.tsx:7,54` — The markdown preview is eagerly loaded even for an empty footer.** Use `next/dynamic` for the preview and render it only when footer content exists. Defer mounting until needed if it is below the fold. 7. **`OrdersDashboard.tsx:40–43` — Repeated expensive calculations and quadratic customer lookups.** Memoize derived results, build a customer-ID `Map` when customers change, and parse dates once before sorting instead of inside every comparison. The join then costs O(orders + customers), rather than O(orders × customers). 8. **`OrdersDashboard.tsx:15,30–32` — Derived state causes an extra render per search/data change.** Remove `filtered` state and its effect; derive it with `useMemo`. For large datasets, use `useDeferredValue(query)` with memoized results to keep typing responsive. 9. **`page.tsx:9–15` — All sections wait for the slowest request.** Start requests together, then await them inside separate async sections under `Suspense`. This allows the sidebar to appear without waiting for feed data; wrapping JSX after all awaits won’t help. 10. **`OrdersDashboard.tsx:53` — Every matching row is mounted.** For large order collections, paginate or virtualize the table. Prefer server pagination/filtering when fetching the entire collection also becomes expensive. 11. **`OrdersDashboard.tsx:3–6` — Import cleanup and a potential barrel-import cost.** Remove unused lodash, icons, `Modal`, and `isAfter`; import used local components directly rather than through `@/components`. Confirm bundle impact before claiming unused imports ship to clients. Named `date-fns` and `lucide-react` imports already rece [... excerpt: first 3200 of 3335 characters]

Pro 보기