클라이언트 사이드 A/B 테스트는 변형이 동적으로 주입될 때 레이아웃 시프트(CLS)를 유발한다. Vercel 팀이 Next.js Edge Middleware를 사용해 캐시 히트 전 서버 단에서 변형을 배정하는 방식으로 이 문제를 해결한 구현을 공유했다. 새 템플릿 마켓플레이스를 20%→50%→100% 단계적 롤아웃으로 검증한 실제 사례다.
핵심 포인트- Edge Middleware가 요청 경로를 변경해 서버 단에서 변형 배정 — CLS 없음
- 쿠키 기반 변형 유지: 첫 방문 시 쿠키 설정, 이후 요청은 쿠키 값 재사용
- 단계적 롤아웃: THRESHOLD 변수 하나(0.2→0.5→1.0)로 배포 없이 트래픽 비율 조정
- 쿼리 파라미터 있는 URL은 Skeleton 로더 라우트로 리라이트해 데이터 로딩 중 CLS 방지
- 결과: Heap 분석 기반 신규 변형 전환율 16% 향상 확인
상세 정리- 문제: 클라이언트 A/B 테스트는 JS 실행 후 DOM 변경으로 CLS 발생. Edge Middleware는 캐시 레이어 이전에 실행돼 이 문제를 원천 차단.
- 변형 배정 로직: middleware.ts에서 req.cookies.get(COOKIE_NAME) 확인 후 없으면 Math.random() < THRESHOLD로 신규/구버전 배정. 쿠키에 저장해 세션 전체 일관성 유지.
- 라우트 구조: 신규 마켓플레이스 /templates/[[...slug]].tsx (catch-all), 구버전 /templates-old.tsx. 구버전 변형은 /templates-old로 rewrite, 신규 변형은 쿼리 파라미터 있을 때 /templates/skeleton으로 rewrite.
- Skeleton 로더: 쿼리 파라미터 포함 URL 접근 시 Middleware가 /templates/skeleton으로 리라이트. Skeleton 컴포넌트가 PlaceholderCard 6개를 렌더하고 SWR로 실제 데이터 fetch 완료 시 교체. 데이터 없이도 CLS 없는 즉각적 응답.
- ISR + On-demand Revalidation: templates 페이지를 정적 생성해 빠른 로딩. 템플릿 추가 시 온디맨드 revalidate로 정적 페이지 갱신.
- 단계별 롤아웃: THRESHOLD 변수를 0.2 → 0.5 → 1.0으로 변경하는 것만으로 배포 없이 트래픽 비율 조정 가능.
- 데이터 수집: Heap Analytics로 배포 성공률 추적 → 신규 변형 16% 전환율 향상 확인. Algolia Search Without Results로 주간 30건 이상 WordPress 템플릿 검색 발견 → GA 전 미리 추가.
왜 읽나Next.js 앱에서 CLS 없이 서버사이드 A/B 테스트를 구현하려는 프론트엔드 엔지니어에게 Edge Middleware + 쿠키 + Skeleton 라우트 조합의 완성된 코드와 실제 전환율 데이터를 함께 제공한다.