Hengxi's 개발 블로그

[React] 웹 성능 최적화하기 1 본문

개발/React

[React] 웹 성능 최적화하기 1

HENGXI 2022. 10. 25. 11:30

웹 성능 최적화는 왜 필요할까?

1. 사용자가 떠나지 않도록 하기 위해( 수익 증대 )

프런트엔드 개발자라면 상식적으로 다 알고 있듯이 페이지가 뜨는 시간이 늦어지면 서비스를 사용하는 사용자들은 점점 떠나갈 것이다. 반대로 성능이 좋아져서 사용자들이 우리 서비스에 오래 머문다면 그만큼 서비스에서 창출할 수 있는 수익은 증대할 것이다.

2.  프런트엔드 개발자로서, 경쟁력을 갖추기 위해

프런트엔드 개발을 하다 보면 일반적으로 어디서나 비슷한 일을 하게 되는데... 거기서 브라우저를 이해하고 웹 성능을 최적화할 수 있다면? 일단 프런트엔드 개발자 중에 상위 10%는 먹고 들어간다고 한다.(실화...?)

프런트엔드라는 분야가 나온 지 시간이 좀 흘러 몇몇 사람들은 성능 최적화에 관심을 가지고 있지만 아직 전반적인 상황은 성능 최적화에 대해 제대로 이해하고 있지 못한 게 현실이다.

 

성능 최적화를 공부해서 상위 프런트엔드 개발자로 거듭나 보자.

기본적인 웹 성능 최적화 방법

1. 이미지 최적화

이미지 리사이징 하기

이미지가 보이는 사이즈에 맞게 원본 이미지를 크기에 맞게 리사이징 해줘야 한다.

위의 이미지를 보면 120 x 120 px로 렌더링이 되고 있지만 그에 비해서 실제 이미지 사이즈는 1200 x 1200 px이다. 실제 필요한 사이즈보다 100배 큰 것이다. 그럼 이 이미지를 몇 사이즈로 불러와야 할까? 요즘 많이 쓰는 레티나 디스플레이는 같은 공간에 더 많은 픽셀을 그릴 수 있기 때문에 넓이에 비해 2배 정도 큰 이미지를 사용하는 것이 적절하다고 한다. 즉, 이미지를 240 x 240 px로 바꾸어 주는 것이 좋다.

그럼 api를 통해 이미지를 받아 오는 경우에는 어떻게 줄일 수 있을까? 바로 이미지 CDN(image processing CDN)을 사용하는 것이다. 이 이미지 CDN은 이미지를 사용자에게 보내기 전에 특정 형태로 가공(사이즈, 포맷)을 해서 전해주게 된다.

 

이미지 CDN 사용 예시

http://cdn.image.com?src=[img src]&width=240&height=240

브런치에서 직접 구축하여 사용하는 이미지 CDN

브런치처럼 직접 구현하지 않아도 imgIX라는 서비스를 이용하여 편하게 사용할 수 있다.

2.  bottleneck 코드 최적화

아래는 파라미터로 넘어온 문자열에서 일부 특수문자를 제거하는 함수이다.(Markdown으로 된 문자열의 특수문자를 제거하기 위함)

특수문자를 제거하기 위해서 반복문을 2번 돌고 있기도 하고, 인자로 받아오는 문자열도 api에서 주는 긴 Markdown 문자열일 텐데 그것을 많은 반복과 비효율적인 함수들로 처리하고 있기 때문에 느릴 수밖에 없다.

function removeSpecialCharacter(str) {
  const removeCharacters = ['#', '_', '*', '~', '&', ';', '!', '[', ']', '`', '>', '\n', '=', '-']
  let _str = str
  let i = 0,
    j = 0

  for (i = 0; i < removeCharacters.length; i++) {
    j = 0
    while (j < _str.length) {
      if (_str[j] === removeCharacters[i]) {
        _str = _str.substring(0, j).concat(_str.substring(j + 1))
        continue
      }
      j++
    }
  }

  return _str
}

Bottleneck 해결 방안

1. 특수 문자를 효율적으로 제거하기 - replace 함수와 정규식 사용, 마크다운 특수문자를 지워주는 라이브러리 사용하기(remove-markdown)

 

2. 작업하는 양 줄이기 - 필요한 문자열만 검사하기

function removeSpecialCharacter(str) {
  let _str = str.substring(0, 300);
  _str.replace(/[\#\_\*\~\&\;\!\[\]\`\>\n\=\-]/g, "");

  return _str;
}

3.  Code Splitting & Lazy Loading

code splitting이란 코드를 분할하는 것으로 덩치가 큰 번들 파일을 쪼개서 작은 사이즈의 파일로 만드는 것을 이야기한다.

보통 리액트를 사용하면 페이지 단위로 리액트 컴포넌트가 구분이 되어 있는데, 특정 페이지에서 다른 페이지에 진입하기 전에 해당 페이지들을 전부 로딩하는 과정은 불필요하다. 즉, 불필요한 코드 또는 중복되는 코드가 없이 적절한 사이즈의 코드가 적정한 타이밍에 로드될 수 있도록 하는 것이다.

리액트에서는 React.lazy(Lazy Loading)을 사용하여 코드 스플리팅을 간단히 구현할 수 있다.

// React.lazy 사용 X 
import OtherComponent from './OtherComponent'; 

// React.lazy 사용 
const OtherComponent = React.lazy(() => import('./OtherComponent'));

Lazy Loading은 Suspense 컴포넌트와 함께 사용되어야 한다. Suspense는 lazy 컴포넌트가 로딩되는 동안 '로딩 화면' 같은 fallback 콘텐츠를 보여줄 수 있게 해 준다.

import React, { Suspense } from 'react'; 

const OtherComponent = React.lazy(() => import('./OtherComponent')); 
const AnotherComponent = React.lazy(() => import('./AnotherComponent')); 

function MyComponent() { 
  return ( 
    <div> 
      <Suspense fallback={<div>Loading...</div>}> 
        <section> 
          <OtherComponent /> 
          <AnotherComponent /> 
        </section> 
      </Suspense> 
    </div> 
  ); 
}

Lazy Loading을 React Router와 함께 사용하면 '라우트 기반 코드 스플리팅'을 설정할 수 있다.

import React, { Suspense, lazy } from 'react'; 
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'; 

const Home = lazy(() => import('./routes/Home')); 
const About = lazy(() => import('./routes/About')); 

const App = () => ( 
  <Router> 
    <Suspense fallback={<div>Loading...</div>}> 
      <Switch> 
        <Route exact path="/" component={Home}/> 
        <Route path="/about" component={About}/> 
      </Switch> 
    </Suspense> 
  </Router> 
);

4. 텍스트 압축 적용

텍스트 기반의 HTML, CSS, JS 파일의 전송에 있어 GZIP은 최적의 성능을 낸다고 알려져 있다. 대부분의 최신 브라우저들은 GZIP 압축을 지원하고, 이를 자동으로 요청한다.

웹 페이지를 로드할 때는 그에 필요한 다양한 리소스들도 같이 다운로드하게 된다. 대표적으로 HTML, JS, CSS와 같은 텍스트들로 이루어져 있는 리소스들인데 당연히 이 파일들의 사이즈가 클수록 로딩 시간이 오래 걸리게 된다.

서버에서 보내는 리소스를 압축해서 보내면 다운로드하는 리소스의 사이즈가 작아지게 되니 더욱 빠르게 서비스가 될 수 있다.

압축은 클라이언트가 아닌 서비스해주는 서버에서 해줘야 하지만  대부분의 서버는 리소스를 제공할 때 자동으로 압축을 해준다. 

CDN을 사용하는 경우에는 GZIP 압축이 활성화되어있는지 잘 확인해줘야 한다.

대략 2KB를 기준으로 그 이하 사이즈인 파일은 압축은 안하는 것이 더 좋다고 한다!

Comments