우리 팀의 성능 최적화 이야기♻️

Sally·2022년 9월 11일
61
post-thumbnail

공식의 성능🧪

이제, 우테코에서의 배운 내용을 토대로 우리 팀의 프로젝트의 성능을 최적화할 시간이 왔다.

우리의 팀 프로젝트는 오랫동안 성능 최적화에 목 말라왔었는데, 바로 지금을 위해서 기다려왔던 것이 아닌가 싶다. 뭐든 극적이면 좋지 않은가🤔


팀 프로젝트의 성능 측정 도구로는 "Lighthouse" 를 활용했다.

크롬의 개발자 도구에서 바로 측정을 할 수 있기에 편리하고,
어떻게 개선해야할지도 제안해주어서 성능 측정 도구로 채택하게 되었다.

우리 팀의 프로젝트의 경우 모바일과 데스크탑 모두를 대응하고 있기 때문에 ,
모바일 환경과 데스크탑 환경에 대해서 각각 성능 측정을 진행하게 되었다.

  • 모바일 환경에서의 점수

  • 데스크탑 환경에서의 점수

결과는 처참했는데, 당연한 결과이기도 하였다.
그도 그럴 것이 , 현재 Home 페이지에서 불러들리는 main.js의 크기가 18.8MB나 되기 때문이다.

이 어마어마한 크기의 main.bundle.js를 로드 하는 동안 뒤에 이어지는 파일들을 업로드 하지 못하기 때문에 페이지가 보여지기까지 오랜 시간이 걸린다.


*이 main.bundle.js의 폭포 부분을 보면 알 수 있다. main.bundle.js가 로드 될 동안 다른 파일들은 모두 대기 중이다.

성능 결과를 받아보고 우리 팀의 성능 최적화의 최대 목표는 자연스럽게main.bundle.js의 크기를 줄이는 것이 되었다!


devtool의 설정을 주의하자!🔧

웹팩에서는 source mapping 스타일을 정할 수 있는 devtool 옵션이 존재한다. 자세한 설명은 이곳에서 볼 수 있다.

기존의 경우, inline-sourcemap을 사용하고 있었다.
inline-sourcemap의 경우 단일 파일을 내보낼 때에는 효과적이다.
하지만, 우리 팀의 경우 개발하는 과정에서 페이지의 개수가 많아지고 여러 개의 파일로 내보내야 하므로 이제는 우리 팀에게는 불필요한 옵션이다.

이 때문에, 웹팩에서 production 모드에서 추천하는 source-map을 도입하게 되었다.
source-map의 경우 전체 소스맵을 별도의 파일로 내보내고 번들에 참조 주석을 추가하여 개발 도구에서 찾을 수 있도록 도와준다.

다만, 이때에 주의 할 점은 소스맵 파일에 다른 유저가 접근하지 못하도록 막아야 한다. (코드 전체가 공개되고 디버깅이 쉽도록 되어 있어서 보안에 문제가 발생할 수 있다) 그래서 우리 팀의 경우 build명령어에 제거 명령어를 추가하여 이를 해결하였다.

"build": "webpack --mode=production --config webpack/webpack.prod.js &&  rm dist/*.map",


이렇게 devtool옵션을 바꿔주는 것 만으로 main.bundle.js 의 크기를 1.6MB까지 줄일 수 있었다.


코드 스플리팅 ⚔️

자 이제는, 코드를 다 갈갈이 찢어놓을 시간이다.
현재 팀 프로젝트의 경우 Home 페이지를 접속하기만 하여도, Search페이지, Article페이지 글쓰기 페이지 등등 모든 페이지에 대한 정보를 다 가져오게 된다

이는 유저가 다른 페이지로 이동하지 않았음에도, 모든 페이지에 대한 정보를 다 가져옴으로써 불필요하게 main.bundle.js의 크기가 커지게 만든다.

또한, 유저가 다른 페이지에 접근하지 않았을 경우 (예를 들어 Home페이지만 머물다 가는 경우 등)에 대한 대응으로도 부적절하다.
유저의 입장에서는 필요없는 정보까지 받아오느라 사이트의 로딩 속도가 느려지는 것이니 말이다.

이럴 때에는 코드 스플리팅을 단행해야한다.

홈페이지에 접근할 때에 바로 불러오지 않는 페이지들과 관련된 컴포넌트들의 경우에는 React.lazy를 활용한 동적 import를 적용한다.

이렇게 동적 import들을 해준 컴포넌트들에 대한 js들은 main.bundle.js에서 빠져나와 각각의 번들 파일을 만들게 된다.

이때 주의해야할 점은, 동적 import된 컴포넌트들이 필요로 해질 때에 새롭게 해당 컴포넌트들을 import하게 된다. 이때에 걸리는 시간이 있으므로, Suspense를 통하여 로딩되는 시간 동안 보여줄 대체재를 fallback을 통해 지정해주어야 한다.


이런 과정을 거친 결과, main.bundle.js의 크기는 375kb까지 줄게되었다! 18.8MB에서 눈에 띄는 결과였다.
하지만, 이것에서 만족할 수 없다. 더 더 줄여보자!


react-icons 🗂

우리팀은 현재, 아이콘을 편리하게 사용하기 위해서 react-icons라는 외부 라이브러리를 사용하고 있는 중이다.

하지만 react-icons에는 편리한만큼 단점도 있었으니 react-icons가 좀 많이 크다
아무래도 많은 종류의 아이콘에 대해서 지원을 하다보니 어쩔 수 없는 일인 것 같다. react-icons도 이를 아는지, 자동으로 트리쉐이킹을 지원하고 있어 자신이 사용하지 않는 아이콘 묶음들에 대해서는 번들되지 않는다.

이것이 문제가 되는 이유는 현재 프로젝트에서 여러가지 아이콘 묶음에서 가지고와서 아이콘을 보여주고 있다는 것이다. 단 한 가지의 아이콘을 사용해야함에도 불구하고 그 아이콘 묶음 전체를 다 가져와야 하는 불상사가 팀 프로젝트 내부에서 일어나게 된 것이다.

그래서 가지고 오는 아이콘 묶음들을 줄여주기 위해서, 다른 아이콘 묶음에서 가져오고 있는 아이콘 중에서 대체할 수 있는 것들은 ai라는 한 가지 폴더 내에서 아이콘을 가지고 올 수 있도록 아이콘들을 조정하게 되었다.
그 결과 355MB까지 줄일 수 있었다.


대체 폰트 설정해주기 🖋

현재, 우리팀은 G-market sans라는 외부 글꼴을 사용하고있다.
팀의 아이디어를 빛내기에는 외부의 디자인 된 글꼴은 큰 도움이된다. 하지만 외부 글꼴을 사용하게 하게되면, 해당 글꼴을 다운 받아 올 때까지 화면상에는 아무런 글자를 보여주지 못하게 된다. 그 글 내용을 보여줄 폰트가 없으니 말이다!

글꼴이 다운 받아와질 때까지 흰 화면만 표시되면서, 유저에게 빠르게 내용을 보여주지 못한다는 단점이 있다.
이 때문에 FCP(First Contentful Paint)LCP(Largest Content Paint)와 관련된 성능 점수도 낮아질 수 밖에 없다.

해결방법은 단순하다. 외부 글꼴을 받아올 동안만 사용할 기본 글꼴을 설정해주면 된다. 다행이도, 단순한 방법으로 문제를 해결할 수 있다.

그저 @font-face를 설정할 때에
font-display : swap을 적용해주면 된다

swap은 글꼴을 사용하는 텍스트가 시스템 글꼴을 사용하여 즉시 표시하여야 함을 브라우저에게 알리고, 사용자 정의 글꼴이 준비되면 시스템 글꼴을 대체하여주는 옵션이다.

  • 새로고침을 하게 되면 원래의 글꼴이 나오기 전까지 대체 폰트가 나오는 것을 확인할 수 있다

최종 결과 👩🏻‍⚖️

앞의 모든 단계를 완수한 후의 Lighthouse의 성능 측정 결과는 다음과 같다.

  • 모바일 화면
  • 데스크탑 화면

아직 팀 내에서 캐싱 정책에 대해서 정해지지 않아서, 캐싱이 되어있지 않고 손 봐야할 곳들이 좀 더 많지만

  • 모바일은 18점에서 81점으로
  • 데스크탑은 33점에서 99점으로

처음 점수에 비하면 많은 성장을 해냈다. 🚀
이제, 빠른 속도로 사용자들을 만날 일들만 남았다😆

더 궁금한 점이 있다면 공식 레포로 방문해주세요 :)

4개의 댓글

comment-user-thumbnail
2022년 9월 11일

와 성능 최적화하니까 점수가 확 올라가네요! 보기만해도 뿌듯하네요 😄

답글 달기
comment-user-thumbnail
2022년 9월 14일

최적화하니 확실히 눈에띄는 수치가 보이네요!
그 결과 355MB까지 여기 오타입니다

답글 달기
comment-user-thumbnail
2022년 9월 15일

와 진짜 대박 ㅎㅎ

답글 달기
comment-user-thumbnail
2022년 9월 18일

개선된 성능을 보니 제가 다 뿌듯하네요! 최고에요~

답글 달기