React Rendering 속도 개선 해보기

yeon_·2020년 7월 5일
27

react

목록 보기
4/4

개선하기 전에 생각해 볼 것들.

1. 먼저 생각해보자

랜더링 속도를 개선하기 전에 몇가지 질문들을 생각해보려고 합니다.

  • 랜더링 속도는 어떻게 측정할까?
  • 렌더링 속도는 어떤 것을 느리다고 하는걸까?
  • 렌더링 속도는 왜 느릴까?
  • 렌더링 속도를 왜 개선해야 할까?

위의 질문들을 먼저 나름대로 해겨해보고 그 다음에 랜더링 속도 개선을 진행해 보려고 합니다.

2. 질문을 해결해보자

🧐 렌더링 속도를 왜 개선해야 할까?

사용성에 대한 점 때문이라고 생각합니다. 사용자의 인터넷 환경은 각자 다르기 때문에 프로덕트가 대상으로 하는 서비스 지역에 따라서 적절한 렌더링 속도 개선을 통해서 사용성을 개선할 수 있다고 생각합니다.

🧐 렌더링 속도는 어떻게 측정할까?

당연히 랜더링 속도를 개선하려면 현재 랜더링 속도가 몇인지를 측정 할 수 있어야 합니다. 초기 속도를 측정 할 수 있어야 또 얼만큼 개선되었는지를 알 수 있으니까요.
그것을 측정하는 도구로 lighthouse를 사용해서 측정하려고 합니다

lightHouse는 웹 앱의 품질을 개선하는 오픈 소스 자동화 도구입니다.

라이트하우스는 웹 품질을 측정하는 도구입니다. 그 안에서 다양한 지표를 확인 할 수 있는데, 그 중 performance 지표를 중심으로 확인해 보려고 합니다.

performance는 웹 속도 점수 지표들의 가중치 평균으로 구성되어 있습니다. 가치가 더 높은 지표는 performance 점수에 더 많은 영향을 주게 됩니다.
lighthouse 계산지표

퍼포먼스 안에서 계산되는 여러 지표들이 의미하는 바는 다릅니다. 그 중 전 TTI 지표에 중점을 맞추서 렌더링 속도를 확인했습니다.

📌 llighthouse performace 지표들
TTITime to interaction 으로 사용자가 웹에서 클릭이나 스크롤링을 수행 할 수 있는 시점을 이야기 합니다. 실제 사용자가 확인 할 수 있는 시간이 짧아져야 사용성이 높아진다고 생각했기 때문에 이 지표를 중점적으로 확인했습니다.

  • TTI(Time to interaction) : 사용자가 웹에서 클릭이나 스크롤링을 수행 할 수 있는 시점
  • FCP(First Contentful Paint) : 브라우저에 첫번째 콘텐츠가 로딩되는 시간을 의미합니다. 이미지나 캔버스 svg도 포함되지만 iframe은 포함되지 않습니다. 스켈레톤 ui를 먼저 로드하는 것도 FCP 를 빠르게 할 수 있겠네요.
  • SI(Speed Index) : 콘텐츠가 시각적으로 얼마나 빨리 표시되는지를 의미합니다.
  • LCP(Largest Contentful Paint) : 가장 큰 컨텐트가 로드되는 시간을 이야기합니다.
  • Total Blocking Time : 웹을 로딩할 때 중간중간 blocking된 시간들의 합을 의미합니다.

참고
lighthouse 6.0 업데이트 내역

  • 계산되는 지표의 웨이트나 지표들은 버전마다 바뀌기도 합니다.

🧐 렌더링 속도는 어떤 것을 느리다고 하는걸까?

객관적으로 느리다고 하는 점은 lighthouse내에 지표 별로 기준 시간들이 있습니다. 사실 모든 지표들을 만족시키기는 것이 좋겠지만. 엄격하게 모두 green을 만들어야 한다고는 생각하지 않습니다. 웹의 성격과 인터넷 환경에 따라 다를 수 있으니까요.

그래서 우선적으로 TTI를 기준으로 속도를 개선했습니다.

🧐 렌더링 속도는 왜 느릴까?

물론 렌더링 속도는 인터넷이 빠르면 빨라집니다. 뒤에서 점점 개선하면서 다시한번 다루겠지만,크게는 블로킹 되는 리소스, 큰 리소스에 원인이 있다고 생각합니다.
그래서 번들 사이즈를 줄이고, 블로킹 되는 요소들을 제거하는 방향으로 개선을 진행해 보았습니다.

왜 번들 사이즈를 줄일까요?

번들 사이즈를 줄이면 렌더링 속도가 개선되는 이유는 랜더링 과정에 있습니다. 랜더링 과정인 CRP는 다음과 같은데요. 페인팅이 실제 웹에 그리지는 순서라고 할 수 있습니다.
그럼 페인팅 이전의 단계에서 시간을 줄일수록 렌더링 시간이 줄어들게 됩니다.

  1. 객체 모델 생성
    • DOM 트리 구축
    • CSSOM 트리 구축
  2. 랜더링 트리 구축
  3. 레이아웃 생성
  4. 페인팅

❗️ JavaScript 실행
파싱을 진행하다가 javascript 파일을 만나게 되면 파싱을 중단하고 js를 받아와서 실행하게 된다.

blocking JS
  • 스크립트를 만나면 실행되고 종료될 때까지 DOM 생성이 일시 중지됨
  • 자바스크립트 실행은 CSSOM 이 준비될 때까지 미뤄진다.
    js 가 실행되면서 어떤 작업을 할지 모르기 때문에 js를 실행 할 때는 무조건 dom 파싱을 일시정지시킵니다.

파일로 받아오는 js 파일이 준비되는대로 실행하고 싶을 때 async 속성으로 중간에 실행되도록 설정 가능


REACT 초기 렌더링 개선하기

어떤 방법들을 찾아보고 적용해봤는지에 대한 부분입니다. 자세한 설정, 구현에 대한 부분보다는 어떤 방법들을 어떤식으로 추가했는지 정도의 내용만 적었습니다.

시도1 : 코드 스플리팅

처음 시도한 방법은 코드 스플릿팅입니다.

왜 자를까요?

/main
/detail
/mypace

spa 에서 javascript 파일을 받아올 때 모든 페이지에 대한 js 파일을 받아올 필요는 없습니다. 메인페이지에 접속 할 때는 메인페이지에 필요한 javascript 파일만, detail 페이지에서는 detail에 필요한 javascipt 파일만 받아오면 됩니다.

이렇게 하면 js 파일 사이즈를 줄여서 렌더링 속도를 줄일 수 있습니다.
(js 파일을 줄이면 파일이 작아지니까 받는 속도도 빨라지고 blocking되는 부분도 더 적어지게 됩니다.)

어떻게 자를까요? (in react)

고전 jsp라면 페이지에 맞게 import 해주는 방식이 있습니다. 하지만 React는 SPA로 동작하게 되기 때문에 이 방법을 선택 할 수 없습니다.
대신 React 에서는 lazy 와 suspend를 사용해서 간단하게 dynamic import를 적용해 볼 수 있습니다.

dynamic import는 지원 범위가 다를 수 있으니 꼭 버전을 확인해야 합니다.

그리고 그중 공통 모듈의 경우 공통 청크를 설정하는 작업을 통해 번들 사이즈를 줄였습니다.

시도 2 : 사용하지 않는 모듈 지우기

두번째는 사용하지 않는 모듈을 지우고 모듈 내에서 필요한 부분만 포함시키는 작업입니다.
Tree Shaking
개발을 하다보면 모듈을 통으로 import 하는 경우가 많습니다. 이 때 실제 사용되는 부분만 번들링 할 수 있도록 하는 게 Tree Shaking입니다. 공식 도큐먼트와 많은 사이트들에서 방법은 다루고 있으니 자세하게 방법을 설명하지는 않겠습니다.

저는 webpack의 BundleAnalyzerPlugin를 사용해서 번들 사이즈를 확인하였고, 큰 번들 사이즈를 줄여나가는 작업을 진행했습니다.

📌 TIPS

  • momentjs의 locale설정은 필요한 부분만 로드하도록 설정하면 번들 사이즈가 작아집니다
  • antd의 경우 v3 →v4 로 올리면서 필요한 모듈만 가지고오도록 지원하고 있습니다. 라이브러리 버전 상세도 확인해봅시다.

시도 3 : 파일 사이즈 줄이기

정리한 번들을 공백을 없애서 사이즈를 줄이기 위해 minimize 되도록 웹팩에 설정할 수 있습니다.

시도 4 : production sourcmap

production의 경우 번들 파일의 코드를 소스파일로 연결해서 디버깅 할 필요가 없기 때문에 sourcemap설정을 hidden source map으로 변경해 주었습니다.
REACT CRA를 사용한다면 기본으로 설정되어 있는 부분입니다.

시도 5 : RSSR 적용

SSR은 서버쪽에서 초기 렌더링을 진행해서 보내기 때문에 초기 렌더링 속도를 개선 할 수 있는 방법 중 하나입니다.
하지만 제가 생각하는 TTI 속도 개선에는 큰 효과는 없습니다. TTI 의 경우에는 js 파일을 다 받은 후의 시점이기 때문에 크게 개선이 되지 않습니다.

오히려 페인팅 되는 시점부터 인터렉션이 가능한 시점까지의 화면 처리를 어떻게 할 것인지에 대해 고민이 필요합니다. 제시되어 있는 방법은 블러처리나 로딩화면 등이 있습니다.

시도 6 : GZ 서빙

번들 파일을 GZ으로 서빙하도록 하였습니다.
하지만 IE는 GZ 파일 형식을 받을 수 없으므로 브라우저에 맞게 처리해 주는 부분이 필요합니다.
SSR을 사용했기 때문에 브라우져 환경에 맞게 서빙하도록 하는 미들웨어를 추가하는 방식으로 처리했습니다.

gzip support browsers list


마무리

엄청 새로운 내용은 아니지만, 렌더링 과정에 대해 이해해 가는 과정이었다고 생각합니다. 왜 번들 사이즈를 줄일수록 빠른지, 또 왜 rssr이 렌더링 속도 개선에 도움이 되는지 등을 이해해볼 수 있었습니다. (+번들러 최고)

또한 기술 선택 과정의 필요성? 중요성? 에 대해서도 느꼈습니다. 번들 사이즈를 줄이기보다 원래 작은게 더 좋으니까요. (물론 다 작다고 좋은 건 아니라고 생각합니다. 개발하고자 하는 것에 따라 다르다고 생각합니다.) 하지만 이전에 생각했던 "다다익선" "다 되면 좋은 것" 이런 생각에서 더 생각 해 볼 수 있었습니다.

🧐 참고한 자료

1개의 댓글

comment-user-thumbnail
2021년 6월 16일

좋은 글 감사합니다 :)

답글 달기