브라우저 성능개선

devAnderson·2022년 2월 4일
0

TIL

목록 보기
52/103

전적으로 레퍼런스를 참조한 내용입니다

1. 이러한 요구를 받을 수 있다

"현재 사이트에는 Hero가 있고"
"아래에는 각종 이미지들이 있습니다"
"Lighthouse 95점 이상"
"Hero 이미지크기 120kb 미만"
"script resource 크기 60kb 미만"
"fast 3g 환경일 시, Home 첫 로드 2.5초 미만, 두번째 이후로 1.5초 미만으로 만들어주세요"

Lighthouse? fast 3G 이게 도대체 무슨소리야

2. 성능측정도구

구글은 브라우저 성능 측정을 위한 도구로 lighthouse라는 것을 제공한다.
이것은 개발자 탭을 열면 확인 가능하다.

그리고 네트워크 탭에 가보면 캐싱 설정을 할 것인지, 인터넷 속도를 어떻게 제어할것인지에 대한 탭이 존재한다.

light하우스의 성능측넝을 눌러보면 분석을 시작한다.
깃헙의 성능측정 결과는 아래와 같다.

참고로, 매 측정마다 백신프로그램이나 캐싱 등 상황이 달라져서 속도나 점수가 달라지므로,
모든것을 초기상태에서 해줄 수 있는 secretMode에서 실험하는게 좋다.

해당 측정결과 나오는 내용은 아래와 같다
-Performance : 콘텐츠가 얼마나 빨리 표시되는지에 대한 지표
-Accessibility : 서비스 접근성 ( alt 태그와 같이 모든 사용자의 웹 접근성과 관련된 내용 )

  • Best Practice : 웹에 대한 표준 모범사례를 잘 따르는지
  • SEO : 서치엔진 검색 점수 ( 웹표준과 관련된 태그들을 잘 사용했는지, 결국 웹 접근성과 연계됨)

3. 성능향상을 위한 방법

a. 요청의 크기를 줄인다

만약 CRA이 아닌 일반 webpack의 형태로 커스텀해 사용하고 있을 경우, 환경옵션을 추가한다.
(기본적으론 production으로 되어있지만 필요에 따라 빌드의 조건부 환경을 설정해줄 수 있다.)

// webpack.config.js

// production 
module.exports = {
  mode: 'production'
}

// development, production에 맞추어 mode 정해주기
module.exports = () => {
  const mode = process.env.NODE_ENV || 'development'
    
  return {
    mode,
    entry: './src/index.js'
    ...
  }
}

아니면 package.json으로 설정해줘도 된다

// package.json

// 빌드를 하거나 local 서버를 돌릴 때, 명시하는 방법도 있다.
"scripts": {
  "build:prod": "webpack --mode=production --node-env=production",
  "serve": "webpack serve --mode=development"
}

mode를 production으로 설정 시, 웹팩은 자동으로 JS 코드를 압축해준다.
일반적으로 CRA으로 만들 시에는 해당 JS 파일의 압축에 대해서는 걱정할 필요가 없지만 나중에 웹팩 공부를 꼭 해서 커스텀하는 환경도 고려해야 한다

또한, 만약 웹팩을 따로 설정하여 사용중이라면 CSS의 로더 역시 설정해줘야한다.
일반적으로 웹팩은 css파일을 읽지 못하지만 css-loader을 추가해주면 해당 내용을 분석하여 head태그에 style 태그로 만들어 삽입해준다.

이때, 너무 헤드가 커지는 문제가 생기기 때문에 코드 스플리팅으로 필요한 css만 분리하여 삽입하길 윈한다면

rules: [
  ...
  {
    test: /\.css$/i,
    use: [MiniCssExtractPlugin.loader, 'css-loader'],
  },
  plugins: [
    ...
    new MiniCssExtractPlugin({
      filename: '[name].css'  // 파일 네임을 지정해 줄 수 있다.
    })
  ]
  

이처럼 MiniCssExtractPlugin이라고 하는 내용을 삽입해준다. css분할뿐만 아니라, css의 압축 역시 진행하기 위해

module.exports = {
  ...,
  optimization: {
    splitChunks: { chunks: 'all' },
    minimizer: [new CssMinimizerPlugin(), '...'],
  },
}

이와같은 압축내용을 설정하여 최적화를 시킬 수 있다.

b. 가장 큰 문제, 이미지

이미지는 기본적으로 아무렇게나 저장해두고 쓰고 있다면 크기가 너무 크다. 따라서 해당 내용을 적절하게 압축할 필요가 있다.
일단 근본적으로 이미지를 서버에 저장할 때, sharp와 같은 패키지를 이용하여 업로드 당시에 이미지 크기를 압축하는 방법이 있다.

또한 클라이언트단에선 이미지를 요청할 때, 태그를 이용하여 조건부로 이미지를 가져오게 할 수 있다.

 <picture>
   <source
     type='image/webp'
     srcSet={`
       ${heroImageWebpMobile} 375w, // w는 pixel 수를 나타낸다.
       ${heroImageWebpTablet} 768w,
       ${heroImageWebp} 1980w,
     `}
   	alt='hero'
   	className={styles.heroImage}
   />
   <img className={styles.heroImage} src={heroImage} alt='hero' />
 </picture>

만약 Next.js를 쓰면 Image 컴포넌트가 자동으로 이미지 최적화 작업을 해준다.

c. React.lazy

아직 실험중인 기능이라고는 들었는데, 아무래도 1년정도 지났으니 이제 슬슬 공식화 해도 될거라고 판단되는 분위기이다.

React.lazy를 이용하면 필요한 컴포넌트 모듈을 필요에 따라서만 따로 요청해 가져오게 할 수 있다(즉 마운트 시점에만)

const Search = React.lazy((_) => import('./pages/Search/Search'));
const Home = React.lazy((_) => import('./pages/Home/Home'));

const App = () => {
  return (
    <Router>
      <Switch>
        <Suspense fallback={<div>loading..</div>}>
          <Route exact path='/' component={Home} />
          <Route exact path='/search' component={Search} />
        </Suspense>
      </Switch>
    </Router>
  ); 
};

Next.js를 사용하면 얘가 알아서 코드 스플리팅을 다 진행하고 있기 때문에 굳이 고려할 필요사항은 아니게된다.
아무래도 핵심 트랜드는 Next.js로 넘어가지 않을까 싶다.

fin. preload, preconnect, prefetch, async

<link rel="preload" as="script" href="super-important.js">
<link rel="preload" as="style" href="critical.css">

이처럼 다른 내용들보다 우선적으로 가져와 표현할 내용을 preload로 설정하여 가져온다.

<link rel="preconnect" href="https://example.com">

preconnect를 활용하면 미리 서버와 연결을 구축해놓을 수 있다는 장점이 있지만 CPU를 많이 사용한다. 미디어 스트리밍과 같은 경우, 스트리밍이 켜지기 전에 미리 연결을 해놓고 UI가 구축되면서 함께 연결이 진행되도록 만들 수 있다.

<link rel="prefetch" href="page-2.html">

prefetch를 진행하면, 미리 미래에 사용될 것인 자원을 가져다가 캐싱할 수 있다.
다만 순수하게 해당자원만 가져오고, 그 내용물 안에 있는 링크들을 추적해서 추가요청을 하지는 않는다.
또한, 설정하면 우선순위가 가장 나중으로 책정되기 때문에 정확하게 미래에 반드시 사용될 가능성이 보이는 자원을 미리 준비해두는 용도로 사용해야 한다.

결론

-일단 절대적으로 요청받는 자원의 크기를 줄인다 (압축, 코드 스플리팅, 이미지 크기, 폰트사이즈, 미디어사이즈 등)
-환경에 따라서 자원을 전달받는 내용을 달리한다 (특히 이미지)
-그 외에는 사용자에게 가장 의미있는 정보들이 먼저 전달될 수 있도록 preload, prefetch등을 활용하고, 스켈레톤 ui와 코드 스플리팅을 적극 활용한다.

referrence

브라우저 성능향상

profile
자라나라 프론트엔드 개발새싹!

0개의 댓글