렌더링 최적화와 관련해서는 무수한 내용이 있으며 하나의 파일에 담아내는 데 한계가 있다고 판단하여 (기존의 내용 + Front-End-Performance-Checklist 레포지토리)를 정리하여 작성하였습니다.
이외에도 많은 최적화 내용이 있으니 찾아보시는 걸 추천해 드립니다.
프론트엔드 분야가 관심을 받게 되면서, 성능 향상을 도와주는 기술과 도구들이 많이 생겼다. 지금, 이 순간에도 만들어지고 있다.
분야별로 많은 최적화 방법이 있지만, 프론트엔드에서 가장 많이 보면서 사용하는 5가지에 대해서만 알아보려고 한다.
- HTML 코드를 압축하며, 최종적으로 나오는 번들된 파일에서 주석, 공백, 줄바꿈을 제거한다.
프로트엔드 개발을 하는 데 있어서 Webpack 같은 번들링 도구를 사용하면서 플러그인을 적용해주면 HTML 파일도 Compress 작업을 거치기 때문에 크게 고려하지 않아도 된다. 실제로 크기를 줄이고 측정 시 로딩 속도를 높여주며, 다운로드 시간을 줄여주는 것을 확인했다.
간단하게 Big Size의 파일을 가지고 확인을 해보자
- CSS 태그를 자바스크립트 태그 앞에 두어 자바스크립트 코드보다 먼저 로드가 되도록 한다.
자바스크립트 전에 CSS 태그를 두면 브라우저의 렌더링 속도를 높이는 병렬 다운로드가 가능해진다.
- 다른 기술적 가능성이 없을 때 iframe을 사용하고, 최대한 iframe을 사용하지 말아야 한다.
iframe을 기본적으로 Main 페이지와 리소스를 공유하지 않아서 iframe 내부적으로 리소스를 다시 호출한다. 이렇게 되면 한 화면의 2개의 렌더링 페이지를 보게 되는 것과 동일하게 된다.
- CSS 파일을 압축하고, 최종적으로 나오는 번들된 파일에서 주석, 공백, 줄바꿈을 제거한다.
프로트엔드 개발을 하는 데 있어서 Webpack 같은 번들링 도구를 사용하면서 플러그인을 적용해주면 CSS 파일도 Compress 작업을 거치기 때문에 크게 고려하지 않아도 된다. 실제로 크기를 줄이고 측정 시 로딩 속도를 높여주며, 다운로드 시간을 줄여주는 것을 확인했다.
- DOM이 로드되는 데 시간이 오래 걸리지 않도록 CSS 파일은 Non-Blocking이 되어야 한다.
CSS 파일은 페이지 로드와 렌더링을 지연시킬 수 있다. 이에 방안으로 preload
를 통해 브라우저가 페이지의 콘텐츠를 보여주기 전에 CSS 파일을 미리 로드할 수 있다.
<link rel="preload" href="style.min.css" as="style" onload="this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="style.min.css"></noscript>
위와 같이 link tag에 rel="preload"
와 as="style"
를 넣어주면 된다.
이와 관련된 아래의 글을 읽어보는 것을 추천한다.
- CSS 크리티컬(또는 '스크롤 없이 볼 수 있는 부분')은 페이지의 보이는 부분을 렌더링하는데 사용되는 모든 CSS를 수집한다. 주요 CSS 호출 전,
<style></style>
사이에 한 줄로 추가하게 된다.
화면에 필요한 부분만 모아서 inline으로 삽입하면서, 초기 렌더링 속도를 높이면서 inline으로 삽입하여 request를 줄이게 된다.
- 외부 또는 인라인 CSS를
<body>
안에 작성해서는 안된다. (HTTP/2에서는 다르게 평가될 수 있다.)
먼저 디자인에서 콘텐츠를 분리하는 것이 좋다. 또한 코드 유지보수를 쉽게 만들고 사이트 접근성을 높인다.
HTML 페이지의 파일 크기와 로딩 시간을 줄여준다.
결론적으로 항상 외부 스타일을 사용하거나 CSS를 <head>
에 작성한다.
- 스타일 시트를 분석하여 불필요한 중복 CSS 선택자를 찾는다.
중복, 또는 유효성 처리가 CSS 코드에서 발생한다. CSS 파일을 분석하고 복잡성을 해결하게 되면 파일을 읽는 속도를 높일 수 있다.
- CSS 스프라이트 기법을 사용하여 많은 아이콘을 사용하는 곳에서 request의 수를 줄인다.
CSS 스프라이트 기법은 이미지 여러 개를 하나로 만들고 background-position
속성을 사용하여 필요한 부분의 이미지만 보여주는 기법이다.
다수의 이미지가 포함된 웹 사이트의 경우, 이미지의 수 만큼 HTTP 요청을 했던 방식을 한 번의 요청으로 줄일 수 있어 초기 Rendering에 걸리는 시간을 줄인다.
<style>
.up,
.down,
.right,
.left {
background: url("./img_css_image_sprites.png") no-repeat;
}
.up {
width: 21px;
height: 20px;
background-position: 0 0;
}
.down {
width: 21px;
height: 20px;
background-position: -21px 0;
}
.right {
width: 22px;
height: 20px;
background-position: -42px 0;
}
.left {
width: 22px;
height: 20px;
background-position: -65px 0;
}
</style>
<body>
<div class="up"></div>
<div class="down"></div>
<div class="right"></div>
<div class="left"></div>
</body>
- 웹 또는 어플리케이션에서 WOFF(Web Open Font Format) 2 포맷 을 사용하는 것이 좋다.
WOFF 이후 WOFF2 형식이 개발되었는데, WOFF에 비해 30%~50% 정도 더 압축되어 훨씬 가벼워졌다. 2018년 기준으로는 IE를 제외한 거의 모든 브라우저의 최신 버전에서 지원하고 있다.
구글의 자료에 따르면 WOFF 2.0 폰트 압축 포맷은 WOFF 1.0보다 평균 30% 더 많이 쓰인다고 한다.
- 폰트를 더 빨리 로드하기 위해
preconnect
를 사용한다.
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
웹 사이트에 접속하면, 브라우저는 DNS 서버를 찾고, 리소스(폰트, CSS...) 수집이 끝나기 전, 조회가 완료될 때까지 대기한다.
이 경우 prefetch와 preconnect를 사용하게 되면 브라우저가 DNS 정보를 찾고 폰트 파일을 호스팅하는 서버에 대한 TCP 연결을 허용받는다.
브라우저가 폰트 정보와 서버에 요청해야 하는 폰트 파일이 담긴 CSS 파일을 파싱할 때 DNS 정보를 확인하고, 커넥션 풀에 있는 서버에 대한 개방형 연결을 준비하게 되어 성능을 높일 수 있다.
- 이미지는 최적화되어야 한다. 최종 사용자에게 영향을 미치지 않는 선에서 압축되어야 한다.
당연히 압축된 이미지는 용량이 작아지기 때문에 브라우저에서 더 빨리 로드되고, 적은 데이터를 소비한다.
- 적절한 이미지 형식.
적절한 이미지 형식이란 웹 사이트를 느리게 만들지 않을 형식을 사용하자는 것이다. 요즘은 차세대 포맷인 JPEG 2000m, JPEG XR 또는 WebP를 사용하는 것이 좋다.
대부분의 브라우저에서 현재 WebP 포맷이 지원되고 있다. (사파리 제외)
- Image Lazy Loading
이미지 레이지 로딩에 관련된 많은 글이 존재한다.
레이지 로딩에 따른 여러 방법이 존재하지만, 기본적인 방법인
- facebook과 같이 skeleton UI 를 사용하는 방법,
- Medium과 같은 progressive image loading,
- 무한스크롤시 IntersectionObserver를 사용하여 클래스로 background-image를 주는 방법
등등이 있다.
위와 관련된 글은 아래의 참조 글을 읽어보는 것이 좋다.
🔗 (Developers Google)[https://developers.google.com/web/fundamentals/performance/lazy-loading-guidance/images-and-video/]
- JS 파일을 압축하고, 최종적으로 나오는 번들된 파일에서 주석, 공백, 줄바꿈을 제거한다.
프로트엔드 개발을 하는 데 있어서 Webpack 같은 번들링 도구를 사용하면서 플러그인을 적용해주면 JS 파일도 Compress 작업을 거치기 때문에 크게 고려하지 않아도 된다. 실제로 크기를 줄이고 측정 시 로딩 속도를 높여주며, 다운로드 시간을 줄여주는 것을 확인했다.
- 자바스크립트 코드를
<body>
중간에 두어서는 안 된다.
코드를 그룹화를 하여 외부 파일로 만들거나 페이지의 마지막(</body>
이후)에 작성하는 것이 좋다.
자바스크립트 코드를 <body>
중간에 넣게 되면 DOM이 구성되는 과정에서 코드가 로드되기 때문에 페이지 속도를 떨어뜨리게 된다.
가장 좋은 옵션은 외부 파일을 async
또는 defer
속성과 함께 사용하여 DOM 로딩을 막지 않도록 하는 것이다.
- 자바스크립트 파일을 비동기적으로 로드하기 위해
async
를 사용하거나 지연시키기 위해defer
속성을 사용해야 한다.
<!-- Defer Attribute -->
<script defer src="foo.js">
<!-- Async Attribute -->
<script async src="foo.js">
자바스크립트는 HTML 문서의 파싱을 차단하기 때문에, 파서는 <script>
태그에 도달할 때 (특히 <head>
안에 있을 때) 파싱을 멈추고 스크립트를 실행한다. 스크립트를 페이지의 상단에 두는 경우 async
또는 defer
를 사용하는 것이 권장되지만 언제나 이 속성을 사용하여 성능 이슈를 피하는 것은 좋은 습관이다.
-
외부 라이브러리를 잘 보고 선택해서 사용하자. 대부분의 경우, 똑같은 기능을 하지만 더 가벼운 라이브러리가 있다.
-
자바스크립트 파일의 성능 문제를 확인해야 한다.
자바스크립트의 복잡도는 런타임 성능을 떨어뜨릴 수 있다. 크롬 개발자 도구의 타임라인 툴을 이용하여 스크립트 이벤트를 테스트하고 너무 오랜 시간이 걸리는 이벤트를 찾아서 수정하여야 한다.