최적화(Optimization)

play·2022년 8월 4일
0

Chapter1. Optimization

Chapter2. Optimization 기법

2-1. 최적화 기법
2-2. Tree Shaking
2-3. Lighthouse




Chapter1. 최적화(Optimization)

최적화, 最適化, optimization

주어진 상황에서 원하는 가장 알맞은 결과를 얻을 수 있도록 처리하는 과정.
최적화는 허용된 자원의 한계 내에서 주어진 요구사항을 만족시키면서 최선의 결과를 얻는 과정이다. 수익과 관련되는 분야에서는 이익을 최대로 내는 과정을 말하기도 한다. 다양한 분야와 때에 따라 다르게 정의할 수 있고 물류(logistics), 설계(design) 문제 등에 응용된다.

컴퓨터 공학에서의 최적화

가능한 적은 리소스를 소모하면서 가능한 빠르게 원하는 결과를 얻을 수 있도록 하는 것

웹 개발에서의 최적화

주어진 조건 아래에서 최대한 빠르게 화면을 표시하도록 만드는 것.

✨ 최적화의 필요성 및 효과

1. 이탈률 감소

최적화가 잘 되지 않은 웹 페이지 = 화면 로딩에 긴 시간 소요 → 사용자가 페이지를 이탈할 확률 증가

2. 전환율 증가

전환율 : 웹 사이트 방문한 사용자 중 회원가입, 상품구매, 게시글 조회 등의 행위를 한 방문자의 비율
전환율을 늘려 서비스 이용자를 늘리기 위해선 이탈률을 줄여야 한다.

3. 수익 증대

빠른 웹 사이트 로딩 속도는 이탈률 감소, 전환율 증가로 이어져 수익 증대까지 이어질 수 있다.

4. 사용자 경험(UX)향상

페이지 로딩 빠를수록 UX는 향상된다.
만약 긴 로딩이 필요한 경우, 로딩 중임을 알려주는 UI를 표시해 방문자의 체류 시간을 좀 더 늘리게 하는 방법도 있다.
따라서 이탈률 감소와 UX 향상 효과를 위해 웹 사이트 성능 최적화는 필수.




Chapter2. Optimization 기법

📌 최적화 기법

🌱 HTML, CSS 코드 최적화하기

  • 화면 렌더링할 때 HTML, CSS 파일이 필요하다.
    • HTML 파일 : DOM 트리 생성
    • CSS 파일 : CSSOM 트리 생성
    • 두 트리를 결합해 렌더링에 사용.
    • 이 중 하나라도 변경되면 리렌더링을 유발
  • 따라서 HTML, CSS 코드를 최적화함으로써 렌더링 성능을 향상시킬 수 있다.

1. HTML 최적화 방법

1) DOM 트리 가볍게 만들기

  • DOM트리가 깊을수록, 자식 요소가 많을수록 DOM 트리의 복잡도는 커짐
  • 복잡도가 클수록 DOM 트리가 변경될 때 계산해야 하는 것도 많아짐.
// 수정 전
<div>
	<ol>
		<li> 첫 번째 </li>
		<li> 두 번째 </li>
		<li> 세 번째 </li>
	</ol>
</div>

// 수정 후 : 불필요한 div 요소 제거
<ol>
	<li> 첫 번째 </li>
	<li> 두 번째 </li>
	<li> 세 번째 </li>
</ol>

2) 인라인 스타일 사용 X

  • 인라인 스타일 : 개별 요소에 스타일 속성을 작성
    • 클래스로 묶어서 한 번에 작성해도 될 스타일 속성을 중복으로 작성하게 되는 경우가 생김
    • CSS 파일을 따로 작성하면 단 한번의 리플로우만 발생하는 것과 달리, 인라인 스타일은 리플로우를 계속해서 발생시켜 렌더링 완료시점을 늦추므로 지양하자. 웹 표준에도 맞지 않음

2. CSS 최적화 방법

1) 사용하지 않는 CSS 제거

2) 간결한 셀렉터 사용




🌱 리소스 로딩 최적화하기

  • HTML 파일에서 JavaScript 파일을 불러올 땐 <script> 요소를,
  • CSS 파일을 불러올 땐 <link> 요소를 사용한다.
  • 파일 위치에 따라서 렌더링 완료 시점이 달라질 수 있다.

1. CSS 파일 불러오기

  • DOM 트리 : HTML코드를 순서대로 읽으며 순차적 구성 가능

  • CSSOM 트리 : CSS 코드를 모두 해석해야 구성 가능

  • 그러므로 CSSOM 트리를 빠르게 구성할 수 있게 HTML 문서 최상단에 배치할 것.

  • <head> 태그 안에 Defer 속성을 줘서 스크립트를 작성하는 게 제일 빠른 방법이다.

    // CSS 파일은 HTML 파일 상단의 head 요소 안에서 불러올 것.
    <head>
    	<link href="style.css" rel="stylesheet" />
    </head>

2. JavaScript 파일 불러오기

  • JavaScript 파일은 DOM 트리 생성이 완료되는 시점인 HTML 문서 최하단에 배치할 것.
    • HTML 코드 파싱 중에 <script> 요소를 만나는 순간부터<script> 요소 이전까지 해당 스크립트가 실행된다.
    • 따라서 해당 요소 이후에 DOM을 수정한 코드는 의도한 대로 화면에 표시되지 않는다.
      <body>
      	// JavsScript 파일은 body 요소 마지막에 작성.
      	<script src="script.js" type="text/javascript"></script>
      </body>



🌱 브라우저 이미지 최적화하기

  • 페이지의 대부분 용량은 : 코드 데이터가 아닌 이미지 파일, 미디어 파일이 차지.
  • 따라서 이미지의 용량을 줄이거나 요청의 수를 줄이자.

1. 이미지 스프라이트 : 서버 요청 수를 줄이기

여러 개의 이미지를 모아 하나의 스프라이트 이미지로 만들고 CSS의 background-position 속성을 사용해 이미지 일정 부분만 클래스 등으로 구분하여 사용하는 방법

  • 클라이언트 서버 요청이 많을수록 로딩 시간은 길어짐
  • 이 서버 요청 수를 줄이기 위해 이미지 스프라이트 기법을 사용.

  • 장점
    • 한번의 이미지 요청으로 대부분의 개별 이미지 사용 가능
    • 네트워크 로딩 시간을 줄일 수 있음
    • 특정 스프라이트 이미지 파일만 관리하면 되므로 관리 용이

이미지 스프라이트 제작 사이트
이미지의 좌표를 알려주는 사이트

2. 아이콘 폰트 사용하기

  • 아이콘을 이미지로 사용하는 게 아니라 아이콘 폰트롤 사용해 용량을 줄이자

Font Awesome 사용 방법

1) CDN으로 사용하기

  • Font Awesome 가입 키트를 HTML 파일의 <head> 요소에 넣기
  • 사용하고 싶은 아이콘을 찾아 코드 복붙

2) Font Awesome 모듈 설치하기

  • React 환경에서 사용할 경우
// 핵심 패키지 설치
npm i --save @fortawesome/fontawesome-svg-core

// 아이콘 패키지 설치 (무료 아이콘)
npm i --save @fortawesome/free-solid-svg-icons
npm i --save @fortawesome/free-regular-svg-icons
npm i --save @fortawesome/free-brands-svg-icons

// Font Awesome React 구성 요소 설치
npm i --save @fortawesome/react-fontawesome@latest

3. WebP & AVIF 이미지 포맷 사용

  • JPEG 또는 PNG 형식이 아닌 새로운 이미지 포맷
  • 용량 감소에 효과적
  • 하지만 최근에 등장해서 모든 브라우저에 호환되지 않는다는 단점.
  • <picture> 태그로 각 브라우저의 호환에 맞도록 분기를 대체할 수 있다.
// 이와 같이 HTML 작성시 <source>태그 내의 srcset에 정의한 WebP 포맷을 지원하지 않는다면,
// 해당 <source> 태그는 무시된다. 
<picture>
  <source srcset="logo.webp" type="image/webp">
  <img src="logo.png" alt="logo">
</picture>



🌱 캐시 사용하기

캐시 : 다운로드 받은 데이터나 값을 미리 복사해 놓는 임시 장소

  • 데이터에 접근하는 시간이 오래 걸리는 경우나, 다시 계산하는 값을 절약하고 싶을 때 사용.
  • 캐시를 사용하면 리소스를 매번 다운받을 필요 없이 꺼내와 재사용하면 되므로 로딩시간을 줄일 수 있다.
  • 프론트엔드단에서 캐시를 사용
    • HTTP 요청을 보낼 때 조건부 요청 헤더를 작성하여 캐시를 재사용해도 되는지 확인한다.
      • If-Modified-Since : 캐시된 리소스의 Last-Modified 값 이후에 서버 리소스가 수정되었는지 확인하고, 수정되지 않았다면 캐시된 리소스를 사용
      • If-None-Match : 캐시된 리소스의 ETag 값과 현재 서버 리소스의 ETag 값이 같은지 확인하고, 같으면 캐시된 리소스를 사용
    • 보통 두 헤더를 동시에 사용한다. 둘 중 하나만 사용했다가 매칭되는 응답 헤더가 없는 경우 재사용 가능한데도 리소스를 다시 받아와야 할 수 있기 때문



🌱 CDN 사용하기

CDN은 유저와 서버의 거리가 멀어서 생기는 네트워크 지연(latency) 해결하고자 세계 곳곳에 분포한 분산된 서버에 콘텐츠를 저장한다.

CDN은 유저가 가까운 곳에 위치한 데이터 센터(서버)의 데이터를 가져온다.

→ 데이터가 전달되기 위해 거쳐야하는 서버 갯수가 줄어들어 로딩 속도 빨라짐




📌 트리쉐이킹(Tree Shaking)

트리쉐이킹(Tree Shaking) : 나무를 흔들어 잔가지를 털어내듯 불필요한 코드를 제거하는 것

🌲 트리쉐이킹 필요한 이유

1. JavaScript 파일의 크기

  • 웹 사이트 인터랙션 증가에 따라 JavaScript 파일의 크기도 커지고 HTTP 요청 횟수 또한 증가, 네트워크 리소스 소모가 커짐
    • 그만큼 화면 표시가 늦어지게 되고 네트워크 속도가 느린 환경에선 병목현상을 유발한다.
    • 따라서 트리쉐이킹을 통해 파일 크기를 줄이자.

2. JavaScript 파일의 실행 시간

  • JavaScript 파일의 실행 시간
      1. 파일을 다운받아 온 다음 압축 해제
      1. JavaScript 코드를 파싱해 DOM 트리 생성
      1. 파싱 후 컴파일하여 컴퓨터가 이해가능한 언어로 바꿔줌
      1. 컴파일이 끝나야 비로소 코드 실행 가능
  • 거쳐야할 과정이 많으므로 JavaScript는 다른 리소스에 비해 실행까지 상대적으로 많은 시간을 소모하게 됨.
  • 자스 파일 실행은 CPU에 크게 영향을 받는다 → 페이지 로딩이 3초가 넘어가면 사용자는 그 페이지를 이탈한다

🌲 JavaScript 트리쉐이킹

기본적인 트리쉐이킹 제공 : ES6 모듈(import, export를 사용하는 모듈), React

1. 필요한 모듈만 import 하기

import 구문을 사용해서 라이브러리를 불러와서 사용할 때, 필요한 모듈만 불러오면 번들링 과정에서 사용하는 부분의 코드만 포함시키기 때문에 트리쉐이킹이 가능해진다.

import { useState, useEffect } from 'react'

2. Babelrc 파일 설정하기

  • Babel : 자바스크립트 문법이 구형 브라우저에서도 호환이 가능하도록 ES5 문법으로 변환하는 라이브러리
  • ES5 : import 지원X → commonJS 문법의 require로 변경시킴
    • 이 과정이 트리쉐이킹에 걸림돌이 됨
    • requireexport 되는 모든 모듈을 불러오기 때문
      • 해결방안
      • Barbelrc 파일에 다음과 같은 코드를 작성해 ES5로 변환하는 것을 막아주자.
      {
        “presets”: [ 
          [
            “@babel/preset-env”,
            {
      	    "modules": false // 반대로 true로 설정하면 항상 ES5문법으로 변환한다.
            }
          ]
       ]
      }

3. sideEffects 설정하기

  • 웹팩은 사이드 이펙트를 일으킬 수 있는 코드의 경우, 사용하지 않는 코드라도 트리쉐이킹 대상에서 제외시킨다.
  • 이 때, package.json 파일에서 sideEffects를 설정하여 사이드 이펙트가 생기지 않을 것이므로 코드를 제외시켜도 됨을 웹팩에게 알려줄 수 있다.
{
  "name": "tree-shaking",
  "version": "1.0.0",
  "sideEffects": false
}
// 또는 특정 파일에서 발생하지 않을 것임을 알려줄 수 있다.
{
  "name": "tree-shaking",
  "version": "1.0.0",
  "sideEffects": ["./src/components/NoSideEffect.js"]
}



📌 Lighthouse

구글에서 개발한 오픈소스로 웹 페이지의 품질을 개선할 수 있는 자동화 툴

  • 성능, 접근성, PWA, SEO 등을 검사하며 이를 이용해 사용자는 어떤 웹페이지든 품질 검사를 할 수 있다.
  • 검사할 페이지의 url을 Lighthouse에 전달하면 Lighthouse는 해당 페이지에 대한 여러 검사를 실행한다.
  • 검사 결과 리포트를 생성하고 개선방법도 알려준다.

Lighthouse 시작하기

1. Chrome 개발자 도구에서 실행하기

  1. 검사하고 싶은 페이지의 url 접속
  2. 개발자 도구를 열어서 lighthouse 탭 클릭

2. Node CLI에서 실행하기

  1. -g 옵션을 사용하여 Lighthouse를 전역 모듈로 설치
npm install -g lighthouse
  1. 검사 실행
lighthouse <url>

모든 옵션 보기

lighthouse --help 

Lighthouse 분석 결과 항목

  • Performance : 웹 성능을 측정(콘텐츠 표시되는데 걸리는 시간, 불안정한 요소 등)
  • Accessibility : 웹 접근성 측정(대체 텍스트 작성, 콘텐츠 색상 대비, WAI-ARIA속성 사용 등)
  • Best Practices : 웹 표준 모범 사례(HTTPS 프로토콜 사용, 콘솔 창에 오류가 표시되는지)
  • SEO : 검색 엔진 최적화(플리케이션의 robots.txt가 유효한지, <meta> 요소는 잘 작성되어 있는지, 텍스트 크기가 읽기에 무리가 없는지)
  • PWA (Progressive Web App) : 모바일 애플리케이션에서도 잘 작동하는지 확인(앱 아이콘 제공, 스플래시 화면 여부, 화면 크기에 맞는 콘텐츠 등을 체크리스트로 확인)

Lighthouse의 Performance 측정 메트릭

  • FCP(First Contentful Paint) : 브라우저가 DOM 컨텐츠의 첫 번째 부분을 렌더링하는데 걸리는 시간을 측정
  • LCP(Largest Contentful Paint) : 뷰포트를 차지하는 가장 큰 콘텐츠의 렌더링 시간을 측정
  • Speed Index : 페이지를 로드하는동안 얼마나 빨리 컨텐츠가 시각적으로 표시되는지 측정
  • TTI(Time to interactive) : 페이지가 로드되는 시점부터 사용자와 상호작용 가능한 시점까지의 시간 측정
    • 기준
      • 페이지에 FCP로 측정된 컨텐츠가9표시되어야 합니다.
      • 이벤트 핸들러가 가장 잘 보이는 페이지의 엘리먼트에 등록됩니다.
      • 페이지가 0.05초안에 사용자의 상호작용에 응답합니다.
  • TBT(Total Blocking Time) : 페이지가 유저와 상호작용하기까지의 막혀있는 시간
  • CLS(Cumulative Layout Shift) : 예상치못한 레이아웃 이동을 경험하는 빈도 측정

개선 방향

  • Lighthouse는 어떻게 개선하여 최적화 할 수 있을지 해결책을 제시한다.
  • Opportunities 항목을 확인해 각 메트릭별 문제를 확인할 수 있다.

profile
블로그 이사했습니다 🧳

0개의 댓글