WebView 도입 후 성능 점검해보기

뱀기·2025년 8월 11일
0

Nurihaus

목록 보기
17/18

앱 안에 WebView를 새로 붙였다. 앱 내에서 웹이 버벅이면 사용성이 매우 안 좋을 것이라 생각이 들었다!
“지금 웹이 잘 최적화돼 있나?”를 숫자로 확인해보려고 Web Vitals를 넣어 봄.

결과를 보고, 다음 단계에서 무엇을 고칠지 정리하는 게 목표.

클라이언트 – Web Vitals 수집기

브라우저에서 화면 속도 지표를 모아 서버로 보내도록 만듦.
서버는 Next App Router의 API 라우트로 간단히 받음.
아래 같이 만들어서 넣어주었음.

// src/providers/WebVitalsReporter.tsx
'use client';
import { useEffect } from 'react';
import axios from 'axios';
import { onCLS, onFCP, onINP, onLCP, onTTFB } from 'web-vitals';

const sent = new Set<string>();

function send(metric: any) {
  const id = `${metric.name}-${metric.id}`;
  if (sent.has(id)) return;
  sent.add(id);

  const payload = { ...metric, path: location.pathname, ts: Date.now() };
  const ok = navigator.sendBeacon?.('/api/vitals', JSON.stringify(payload));
  if (!ok) void axios.post('/api/vitals', payload, { headers: { 'content-type': 'application/json' } });
}

export default function WebVitalsReporter() {
  useEffect(() => {
    onTTFB(send);
    onFCP(send);
    onLCP(send, { reportAllChanges: false });
    onCLS(send, { reportAllChanges: false });
    onINP(send, { reportAllChanges: false });
  }, []);
  return null;
}

서버 – API 라우트

// src/app/api/vitals/route.ts
import { NextRequest, NextResponse } from 'next/server';

export async function POST(req: NextRequest) {
  const metric = await req.json();
  console.log('[WEB-VITALS]', metric); // 나중에 대시보드로 보내면 됨
  return NextResponse.json({ ok: true });
}

Provider에 연결

// src/app/providers.tsx (발췌)
'use client';
import WebVitalsReporter from '@/providers/WebVitalsReporter';

export default function Providers({ children }: { children: React.ReactNode }) {
  return (
    <>
      {children}
      <WebVitalsReporter />
    </>
  );
}

왜 App Router API로 받았나

• 같은 도메인이라 CORS 설정 불필요
• 브라우저에서 비밀키 노출 없이 서버에서만 외부 분석 툴로 전송 가능
• 별도 서버 없이 프로젝트 안에서 끝낼 수 있어 관리가 편함
• WebView에서도 추가 화이트리스트 없이 동작

어떤 값이 나왔는가

  • TTFB: 서버가 첫 바이트를 돌려줄 때까지의 시간. 네트워크/서버 속도 지표. 235ms → 좋음(권장 < 800ms).
  • FCP: 첫 텍스트/이미지 등 “처음 보이는 픽셀”이 그려진 시점. 312ms → 좋음(권장 < 1.8s).
  • LCP: 화면에서 가장 큰 의미 있는 요소가 보이는 시점(주로 히어로 이미지/큰 텍스트). 920ms → 좋음(권장 < 2.5s).
  • INP: 사용자가 조작했을 때 다음 화면 업데이트까지 걸린 시간(반응성). 0ms → 매우 좋음(권장 < 200ms, 이번 샘플은 사실상 지연 없음).
  • CLS: 화면 요소가 로딩 중 밀리거나 튀는 “흔들림”의 누적 정도. 0.1003 → 기준 0.1을 살짝 넘음(개선 필요: 이미지 자리 고정, 스켈레톤, absolute 레이어, transform 위주 애니메이션 등으로 낮추기).

개선

어떤걸 하게 될 지 알 수 없지만 아래 같은 항목들을 살피고자 한다.

  • 이미지 등과 같은 자리를 미리 확보 안해서 로딩 후 밀림...?
  • 폰트 로딩 지연?
  • 애니메이션?
  • SSR로 아이템, 레이아웃 같은 컴포넌트를 서버에서 렌더해보자?
  • 등등
profile
FE 입니다.

0개의 댓글