개발 이야기/Vue

[Vue.js/Core web vitals] 웹 성능과 유저 경험 개선하기

Heman 2023. 9. 1. 19:43

[Vue.js/Core web vitals] 웹 성능과 유저 경험 개선하기

이번에는 Vue를 사용하는 새로운 프로젝트에서 레거시 코드로 이루어진 서비스의 웹 성능과 유저 경험(UX)을 개선한 내용을 기재해보려합니다~

 

History

협력업체로부터 새로운 프로젝트를 인수인계 받으며 코드분석을 진행하는데 아무리 보아도 적응되지 않는 이슈가 있었습니다.

 

메뉴를 이동할 때마다 화면의 모든 컴포넌트가 사라지고, 로딩 시간 동안 화면에서 아무것도 볼 수 없는 현상이었는데요.

화면이 깜빡인다 이말입니다!

 

이 문제는 프로젝트를 인수하는 저희 팀원들 뿐만 아니라, 서비스를 직접적으로 사용하는 회사 내부 사용자들에게서도 적지 않은 개선 요청을 받은 것으로 보입니다.

 

해당 프로젝트는 서비스의 규모가 큰 편이고, 도메인도 메뉴별로 다를뿐더러 코드량이 많다보니 프론트엔드 소스코드는 각 메뉴마다 별도의 패키지로 구성되어 있는데요.

UI는 비슷하게 보이지만 각 메뉴가 가지는 URL 주소도 다르고, 메뉴 이동시 새로 페이지를 로딩하고 있어 사용자가 보기에는 동일한 페이지 안에서 깜빡거리는 것처럼 보였습니다.

 

이 문제를 해결하기 위해 어떠한 방법으로 해결할 지 고민이 많이 되었습니다. 패키지를 합쳐 어플리케이션의 구조를 변경하거나, iframe을 사용해야한다는 의견도 있었습니다.

 

하지만 저는 조금 더 간결한 방법이 있을 것으로 생각했고, 불편한 이 현상을 개선할 방법에 대해 고민했습니다! 두둥탁

 

문제가 무엇이었나?

우선 화면에 아무것도 랜더링 되지 않는 시간이 사람이 체감할 정도로 길다는 것은 DOM 트리를 구성하거나 요소를 Paint 하는 과정에서 문제가 있거나 모종의 이유로 UI 랜더가 지연되고 있다는 것입니다. 저는 코드분석을 하면서 그 이유를 찾을 수 있었는데요.

 

이 프로젝트는 B2C 서비스가 아닌 회사 내부에서 사용하는 백오피스용 서비스기 때문에 유저가 가진 접근권한에 따라 화면을 다르게 보여주도록 기획되어 있습니다. 그렇기에 API 호출을 하여 권한을 획득한 후 response 결과에 따라 사용자 별로 권한에 맞는 UI를 그려주고 있었습니다.

 

모든 권한과 유저 정보를 새 페이지를 불러올 때마다 한꺼번에 호출하기에, 응답이나 처리가 늦어지는만큼 화면이 깜빡이는 것이지요.

 

문제 해결

서버에서 당장 성능을 개선 할 수 없는 상황이었지만, 클라이언트 파트에서 몇가지 수정을 통해 문제를 개선 할 수 있을 것 같습니다.

 

제가 적용한 방법은 두가지인데요.

 

그 중 첫번째 방법은 Skeleton UI를 적용하여 유저에게 현재 로딩 중이라는 정보를 전달하는 것이었습니다. 사용자가 로딩 중이라는 사실을 인지하기만 해도, 아무것도 보이지 않는 화면을 볼 때보다 훨씬 안정감을 가질 것입니다.

 

skeleton 을 적용한 예시 코드

 

위 코드를 보면 cloudReady라는 변수가 true일 때 header를 보여주고 있는데요.

cloudReady는 API 콜을 통해 받아온 데이터에 따라 변경되는 상태값이기에 cloudReady가 존재하지 않을 때, 기존의 header가 아닌 header-skeleton 컴포넌트가 보이도록 수정했습니다.

 

참고로 header-skeleton 컴포넌트는 라우팅과 비즈니스 로직을 제외시킨 컴포넌트이며, 퍼블릭한 권한으로 볼 수 있는 내용만을 header에 보여주고, 메뉴를 클릭할 수 없도록 작성했습니다. 따라서 사용자는 로딩 중에 화면에 나온 무언가(skeleton)를 볼 수 있지만, 클릭 이벤트를 발생시키지는 못하게 됩니다.

 

그 외 컴포넌트와 화면도 유저 정보와 권한을 획득하지 않았을때는 skeleton이 보이도록 작성했습니다.

 

Element UI 라이브러리의 Skeleton

 

두번째로 적용한 방법은 사이즈가 큰 이미지나 로고를 최적화하는 방법입니다.

 

이미지 최적화 예시 코드

 

이러한 방법으로 이미지를 최적화할 수 있는데요.

picture 태그는 한가지 children만 표시를 해주기 때문에 이미지 사이즈나 소스에 맞는 이미지를 선택적으로 보여줄 수 있습니다.

 

또한 이미지를 비동기적으로 디코딩하여 다른 콘텐츠를 표시하는 시간이 줄어들게 됩니다. 이미지의 사이즈를 특정할 수 있다면, 뒤에서 이야기 할 CLS(Cumulative Layout Shift)에 대한 이점도 가질 수 있습니다.

 

여기까지 코드를 수정하니 육안으로 볼때 깜빡거리는 현상은 사라졌네요! 

이제 실질적인 수치를 측정해보면 좋을 것 같습니다 ㅎㅎ  

 

코어 웹 바이탈 측정하기

코어 웹 바이탈이란 세가지 웹 성능 지표의 집합입니다. Google의 검색 엔진에서 페이지 표시를 결정하는 데 쓰이며, 검색 엔진 최적화를 위한 판단에 사용되는 수치입니다.


https://www.cloudflare.com/ko-kr/learning/performance/what-are-core-web-vitals/

 

코어 웹 바이탈에 대한 내용은 위 주소에서 좀 더 자세히 알 수 있습니다..! 

 

저는 이 코어 웹 바이탈을 측정하여 기존 화면과 개선된 화면의 측정 결과를 비교해 보았습니다.

 

코드 수정 전 성능 지표
코드 수정 후 성능 지표

 

첫번째 이미지가 코드 수정 전 측정한 프로젝트의 성능 지표이고, 두번째 이미지가 코드 수정 이후 측정한 성능지표입니다.

다행히 전체적으로 유의미한 수치가 나왔습니다!

 

가장 처음 화면에 보여지는 요소를 측정하는 FCP(First Contentful Paint) 수치가 2.3s 에서 0.4s 까지 단축되었습니다. 아마 유저권한에 디펜던시가 많지 않아도 어느정도 화면을 그릴 수 있는 header-skeleton이 적용되어 크게 개선된 듯 보입니다. 

 

화면에서 가장 큰 요소가 그려지는 시간을 측정하는 LCP(Largest Contentful Paint)도 10.4s 에서 4.6s 로 절반 이상 단축되었습니다.

 

마지막으로 레이아웃이 밀리는 빈도를 측정한 CLS(Cumulative Layout Shift) 수치는 0.046 에서 0 으로 수치상으로도 전혀 이슈가 발생하지 않는 것을 볼 수 있습니다!

 

마무리하며

이번 이슈를 해결하기 위해 적용한 내용들은 B2C 서비스에서 사용자 경험과 검색 성능 최적화를 위해 주로 쓰이는데요. 백오피스에서도 실질적인 업무로 다루어 볼 수 있었던 점에서 인상이 깊고, 유의미한 성능 개선이 있었다는 점에서 더 큰 의미와 경험으로 다가왔습니다 :)

 

본문에 자세한 코드나 화면을 기록하면 좋겠지만, 보안상 예시코드와 텍스트로만 설명을 남길 수 밖에 없는 점이 아쉽기도 하네요 ㅎㅎ