Skip to content

성능 리포트

KIM DAEUN edited this page Dec 28, 2024 · 4 revisions

1단계 - 성능 관리 대상 설정

‘크루루’의 핵심 기능 영역

  1. 지원자 현황 대시보드
  2. 신규 공고 및 지원서 생성 화면
  3. (지원자 입장에서의) 공고 조회 화면

주요 사용자 경험 환경 : 데스크탑

  • ‘크루루’는 리크루팅 업무 플랫폼으로서, 지원자 및 공고 관리에 특화된 서비스입니다.
  • ‘크루루’의 핵심 기능은 칸반보드 형태의 대시보드, 공고 및 지원서 생성 기능입니다. 이들은 모두 리크루팅 실무자의 업무 환경을 고려하여 데스크탑 화면을 기준으로 개발되었습니다.
  • 이러한 개발 의도에 따라, 성능 측정/관리는 데스크탑 환경을 기준으로 진행합니다.

2단계 - 성능 예산 세우기

측정 환경 설정

구분 내용
Device Macbook Air 15(M3 24GB, 2024)
OS/Browser macOS 14.5, Chrome 128
Network Throttling Fast 4G
CPU Throttling 6X throttling

성능 지표 및 예산

구분 성능 지표 성능 예산 비고
정량 기반 각 페이지에서 로드되는 JS 번들 용량 (압축 전) ≤ 500kb 기존 대비 50%+ 절감
개별 이미지 용량 ≤ 150kb
웹 폰트(Pretendard) 총 용량 < 2mb 기존 대비 50%+ 절감
시간 기반 LCP 시간 < 2.5초 Lighthouse의 ‘Good’ 판별 기준 ㅡ
FCP 시간 < 1.8초 Lighthouse의 ‘Good’ 판별 기준
CLS 점수 < 0.1 Lighthouse의 ‘Good’ 판별 기준
규칙 기반 Lighthouse 성능 점수 ≥ 95점

성능 지표별 선정 이유

  • 정량 기반 (번들, 이미지, 폰트 용량)
    • 서비스 페이지가 완전히 로드되어 사용자와 상호작용이 가능하게 되기까지의 딜레이를 줄여서 사용자의 서비스 체감 속도를 높이고자 합니다.
  • 시간 기반 (LCP, FCP, CLS)
    • LCP(Largest Contentful Paint) : 사용자가 실제로 볼 수 있는 가장 큰 요소의 출력 타이밍을 앞당깁니다.
    • FCP(First Contentful Paint) : 사용자의 초기 로딩 경험을 개선합니다.
    • CLS(Cumulative Layout Shift) : 불필요한 레이아웃 변화를 최소화하여 시각적 안정성을 개선합니다.
  • 규칙 기반 (Lighthouse 성능 점수)
    • 위의 요소들을 종합적으로 모니터링 할 수 있는 Lighthouse 성능 점수를 모니터링 합니다.

3단계 - 측정하고 개선 포인트 찾기

측정 결과 1) 주요 리소스 용량

image

구분 용량 비고
JS 번들 용량 992.22kb 압축시 252.98kb
개별 이미지 용량 없음 4kb 미만의 이미지는 base64 로 번들에 포함
웹 폰트 수량/용량 4개 / 각 파일당 약 1.2mb Regular, Medium, SemiBold, Bold 사용

측정 결과 2) 페이지별 Lighthouse, Performance 측정 결과

페이지 Lighthouse Chrome DevTools > Performance
지원자 현황 대시보드 78점
신규 공고 및 지원서 생성 화면 81점
공고 조회 화면 81점

image

image

image

image

image

image

개선 포인트

  • 리소스별 용량 절감 및 LCP 개선
    • 페이지/Route별 번들링 분할 및 소스 최적화
      • Chunk 분할 단위 설정 및 Code Splliting
      • CSS Extract & Minify
    • 웹 폰트 용량 절감, 로드 최적화
      • Subset 이용
      • weight 옵션 간소화
      • CSS, Font 파일 각각 preload 처리
    • 추후 이미지 추가시 화질 대비 용량 최적화 실행 (예: 랜딩 페이지)
  • 리소스 로드 우선순위 변경
    • 번들 파일, CSS, 웹 폰트, GA, Sentry 등 모니터링 스크립트
  • 기타 렌더링 성능 개선
    • 반복 렌더링 요소에 메모이제이션 적용 (공고 카드, 지원자 카드 등)
    • 하나의 컴포넌트에 대한 복수/중복 애니메이션 발생 현상 수정

image


성능 개선 결과

구분 성능 지표 성능 예산 개선 결과 비고
정량 기반 각 페이지에서 로드되는 JS 번들 용량 (압축 전) ≤ 500kb 521kb Quill 에디터 제외시
< 500kb
개별 이미지 용량 ≤ 150kb 랜딩페이지 첫 커버 이미지 제외
150kb 내외로 조정
웹 폰트(Pretendard) 총 용량 < 2mb 랜딩페이지 기준
< 300kb
시간 기반 LCP 시간 < 2.5초 < 1초
FCP 시간 < 1.8초 < 1초
CLS 점수 < 0.1 < 0.1
규칙 기반 Lighthouse 성능 점수 ≥ 95점 99~100

리소스별 용량 절감 및 로드 우선순위 조정

번들 사이즈 최적화

💡 기존에 모든 프론트엔드 코드가 하나의 파일(main.js)로 번들링되어 서비스되던 문제 개선

refactor-fe: 코드 스플리팅으로 로딩 성능 개선 by github-actions[bot] · Pull Request #678 · woowacourse-teams/2024-cruru

작업 사항

  1. Route 단위로 React.lazy를 이용하여 Code Splitting 진행

    const ErrorPage = lazy(() => import(/* webpackChunkName: "ErrorPage" */ '@pages/ErrorPage'));
    const SignIn = lazy(() => import(/* webpackChunkName: "SignIn" */ '@pages/SignIn'));
    const SignUp = lazy(() => import(/* webpackChunkName: "SignUp" */ '@pages/SignUp'));
    const Dashboard = lazy(() => import(/* webpackChunkName: "Dashboard" */ '@pages/Dashboard'));
    const RecruitmentPost = lazy(() => import(/* webpackChunkName: "RecruitmentPost" */ '@pages/RecruitmentPost'));
    const ConfirmApply = lazy(() => import(/* webpackChunkName: "SignConfirmApplyUp" */ '@pages/ConfirmApply'));
    const DashboardLayout = lazy(() => import(/* webpackChunkName: "DashboardLayout" */ '@pages/DashboardLayout'));
    const DashboardList = lazy(() => import(/* webpackChunkName: "DashBoardList" */ '@pages/DashBoardList'));
    const DashboardCreate = lazy(() => import(/* webpackChunkName: "DashboardCreate" */ '@pages/DashboardCreate'));
  2. 빌드 파일명에 contenthash 추가하여 Cache Busting 유도

  3. Quill 에디터 등 특정 페이지에서만 사용되는 모듈/라이브러리는 별도의 Chunk로 분리 → 로드 효율 높임

작업 결과

Metric Pre-Code Splitting Post-Code Splitting Sentry Optimization
Main JS Bundle Size 998 KiB 528 KiB (-470KiB) 521 KiB (-7KiB)
Gzipped Size 252.98 KiB 166.5 KiB 164.87 KiB

image

  • 메인 번들 크기 47.8% 감소

웹폰트 로드 최적화 및 우선순위 상향

💡 서비스 접속시 가장 큰 네트워크 병목을 일으킨 웹폰트 로드의 최적화 적용

chore-fe: Pretendard 웹폰트 로드 최적화 적용 by github-actions[bot] · Pull Request #691 · woowacourse-teams/2024-cruru

작업 사항

  1. 웹폰트를 각 weight마다 통째로 불러오던 것을 가변 다이나믹 서브셋으로 변경
    • 가변 다이나믹 서브셋이란?
      • 다이나믹 서브셋 : CSS의 unicode-range 속성을 이용하여 해당 유니코드 영역의 문자가 사용될 때 폰트를 다운로드 하는 방식
      • 가변 서체 : 모든 폰트의 굵기를 담고 있는 서체. 개별 폰트보다는 무거우나, 여러 개의 서로 다른 굵기 정보를 가진 폰트보다는 훨씬 가볍다는 장점이 있음
      • 위의 두 가지 기술이 가진 장점을 합친 방식으로, 현재 모던 브라우저에서 모두 지원됨
  2. 웹폰트 CDN 경로에 대한 preconnect, 웹폰트 CSS 리소스에 대한 preload 적용
    • preload : 현재 페이지에서 필요한 리소스를 미리 로드
    • preconnect : 브라우저가 현재 페이지에서 필요할 외부 도메인과의 연결을 미리 설정

작업 결과 (4G 네트워크 기준)

  • 기존에는 웹폰트 하나를 다운로드 받는 데에 무려 5.99초가 소요되며, 전체 약 4.7MB를 차지했습니다.

image

  • 개선 이후에는 웹폰트 서브셋 하나당 다운로드가 0.45초 이내에 이루어지며, 전체 262KB만 차지합니다.

image

Lighthouse Performance Score

성능 개선 전

image

성능 개선 후

image

image

image

image

캐싱 정책 추가

💡 Production 환경에 한하여, 아래와 같은 캐싱 정책을 수립하여 배포 환경에 적용했습니다.

구분 브라우저 캐시 CDN 캐시 비고
HTML 0 1년 Cache invalidation 활용 여부에 따라 CDN 캐시 기한을 조정 필요
CSS/JS 1년 1년 파일명을 이용한 캐시 버스팅 활용
Image 1년 1년 파일명을 이용한 캐시 버스팅 활용
Font 1년 1년
Etc (Default) 1일 (기본값 1일)

AWS S3/CloudFront 환경에서의 리소스 캐싱 정책 및 적용 방안

기타 작업 (요구사항 외)

SEO 개선

💡 서비스 모니터링/테스트 과정에서 발견한 검색 노출 이슈를 해결하기 위한 작업을 진행했습니다.

작업 배경

image

  • 검색에서 노출되어선 안 되는 경로들이 검색에 노출됨 (beta.cruru.kr)
  • 본 서비스에 대해 파악 가능한 콘텐츠가 검색 노출 결과에 나타나지 않음
  • 파비콘(Favicon) 미등록

작업 내용

  • Favicon 디자인, 제작
  • Open Graph용 커버 이미지(1200x630) 디자인, 제작
  • 검색 노출시 우선적으로 크롤링되는 meta 태그에 title, description 등 정보 추가
  • 카카오톡, 슬랙, 페이스북 등 여러 플랫폼에서 링크 공유시 노출되는 Open Graph 정보 추가
  • 검색 엔진의 크롤링 로봇에 적용시킬 robots.txt를 beta, prod 용으로 나누어 각각 추가
  • 위의 모든 변동사항 적용에 필요한 webpack 설정 및 github actions workflow 수정

검색 노출 정책

경로 페이지 베타(beta.cruru.kr) 운영(cruru.kr) 비고
/ 랜딩페이지 X O
/sign-in 로그인 X X
/sign-up 회원가입 X X 로그인 필요
/dashboard/ 대시보드 X X 로그인 필요
/post/ 공고 X X 로그인 필요

파비콘, OG 리소스

image

image

Clone this wiki locally