중요한 애셋을 미리 로드하여 로드 속도 개선

웹페이지를 열면 브라우저가 서버에서 HTML 문서를 요청하고, 해당 콘텐츠를 파싱하고, 참조된 리소스에 대해 별도의 요청을 제출합니다. 개발자는 페이지에 필요한 모든 리소스와 그 중 가장 중요한 리소스에 대해 이미 알고 있습니다. 이 지식을 활용하여 중요한 리소스를 미리 요청하고 로드 프로세스의 속도를 높일 수 있습니다. 이 게시물에서는 <link rel="preload">를 사용하여 이를 달성하는 방법을 설명합니다.

미리 로드 작동 방식

미리 로드는 일반적으로 브라우저에서 늦게 발견되는 리소스에 가장 적합합니다.

Chrome DevTools Network 패널의 스크린샷
이 예에서 Pacifico 글꼴은 @font-face 규칙을 사용하여 스타일시트에 정의되어 있습니다. 브라우저는 스타일시트를 다운로드하고 파싱한 후에만 글꼴 파일을 로드합니다.

특정 리소스를 미리 로드하면 현재 페이지에 중요하다고 확신하기 때문에 특정 리소스를 브라우저가 발견하는 것보다 더 빨리 가져오려고 한다는 것을 브라우저에 알리는 것입니다.

미리 로드를 적용한 후의 Chrome DevTools Network 패널 스크린샷
이 예시에서는 Pacifico 글꼴이 미리 로드되어 있으므로 스타일시트와 동시에 다운로드가 진행됩니다.

중요한 요청 체인은 브라우저에서 우선순위를 지정하고 가져오는 리소스의 순서를 나타냅니다. Lighthouse는 이 체인의 세 번째 수준에 있는 애셋을 늦게 발견된 것으로 식별합니다. 키 요청 미리 로드 감사를 사용하여 미리 로드할 리소스를 식별할 수 있습니다.

Lighthouse의 미리 로드 키 요청 감사입니다.

rel="preload"가 있는 <link> 태그를 HTML 문서 헤드에 추가하여 리소스를 미리 로드할 수 있습니다.

<link rel="preload" as="script" href="critical.js">

브라우저는 미리 로드된 리소스를 캐시에 저장하므로 필요할 때 즉시 사용할 수 있습니다. 스크립트를 실행하거나 스타일시트를 적용하지는 않습니다.

리소스 힌트(예: preconnectprefetch)는 브라우저에서 적합하다고 판단하면 실행됩니다. 반면 preload는 브라우저에 필수입니다. 최신 브라우저는 이미 리소스의 우선순위를 매우 높게 지정하므로 preload를 드물게 사용하고 가장 중요한 리소스만 미리 로드하는 것이 중요합니다.

사용되지 않은 미리 로드는 load 이벤트 후 약 3초 후에 Chrome에서 Console 경고를 트리거합니다.

미리 로드된 미사용 리소스에 관한 Chrome DevTools Console 경고

사용 사례

CSS에 정의된 리소스 미리 로드

@font-face 규칙으로 정의된 글꼴이나 CSS 파일에 정의된 배경 이미지는 브라우저가 해당 CSS 파일을 다운로드하고 파싱할 때까지 검색되지 않습니다. 이러한 리소스를 미리 로드하면 CSS 파일이 다운로드되기 전에 리소스를 가져오게 됩니다.

CSS 파일 미리 로드

중요한 CSS 접근 방식을 사용하는 경우 CSS를 두 부분으로 나눕니다. 스크롤 없이 볼 수 있는 콘텐츠를 렌더링하는 데 필요한 중요한 CSS는 문서의 <head>에서 인라인되며 중요하지 않은 CSS는 일반적으로 자바스크립트를 통해 지연 로드됩니다. 중요하지 않은 CSS를 로드하기 전에 자바스크립트가 실행될 때까지 기다리면 사용자가 스크롤할 때 렌더링이 지연될 수 있으므로 <link rel="preload">를 사용하여 다운로드를 더 빨리 시작하는 것이 좋습니다.

JavaScript 파일 미리 로드

브라우저는 미리 로드된 파일을 실행하지 않으므로 미리 로드된 파일을 실행과 분리하는 것이 유용하며, 이렇게 하면 상호작용까지의 시간과 같은 측정항목을 개선할 수 있습니다. 미리 로드는 JavaScript 번들을 분할하고 중요한 청크만 미리 로드하는 경우에 가장 잘 작동합니다.

rel=preload 구현 방법

preload를 구현하는 가장 간단한 방법은 <link> 태그를 문서의 <head>에 추가하는 것입니다.

<head>
  <link rel="preload" as="script" href="critical.js">
</head>

as 속성을 제공하면 브라우저가 미리 가져온 리소스의 우선순위를 유형에 따라 설정하고, 올바른 헤더를 설정하고, 리소스가 이미 캐시에 있는지 여부를 확인할 수 있습니다. 이 속성에 허용되는 값은 script, style, font, image, 기타입니다.

글꼴과 같은 일부 리소스 유형은 익명 모드로 로드됩니다. 이러한 경우 preloadcrossorigin 속성을 설정해야 합니다.

<link rel="preload" href="ComicSans.woff2" as="font" type="font/woff2" crossorigin>

<link> 요소는 연결된 리소스의 MIME 유형이 포함된 type 속성도 허용합니다. 브라우저는 type 속성의 값을 사용하여 파일 형식이 지원되는 경우에만 리소스가 미리 로드되도록 합니다. 지정된 리소스 유형을 지원하지 않는 브라우저는 <link rel="preload">를 무시합니다.

Link HTTP 헤더를 통해 모든 유형의 리소스를 미리 로드할 수도 있습니다.

Link: </css/style.css>; rel="preload"; as="style"

HTTP 헤더에서 preload를 지정하면 브라우저가 문서를 파싱하지 않고도 발견할 수 있으므로 경우에 따라 약간의 개선이 제공될 수 있습니다.

webpack으로 자바스크립트 모듈 미리 로드

애플리케이션의 빌드 파일을 생성하는 모듈 번들러를 사용 중인 경우 미리 로드 태그 삽입을 지원하는지 확인해야 합니다. webpack 버전 4.6.0 이상에서는 다음과 같이 import() 내에서 매직 주석을 사용하여 미리 로드가 지원됩니다.

import(_/* webpackPreload: true */_ "CriticalChunk")

이전 버전의 webpack을 사용하는 경우 preload-webpack-plugin과 같은 서드 파티 플러그인을 사용하세요.

미리 로드가 코어 웹 바이탈에 미치는 영향

미리 로드는 로드 속도에 영향을 미치는 강력한 성능 최적화입니다. 이러한 최적화로 인해 사이트의 코어 웹 바이탈이 변경될 수 있으므로 이를 인식하는 것이 중요합니다.

최대 콘텐츠 렌더링 시간(LCP)

이미지와 텍스트 노드 모두 LCP 후보가 될 수 있으므로 미리 로드는 글꼴과 이미지의 경우 최대 콘텐츠 렌더링 시간 (LCP)에 강력한 영향을 미칩니다. 웹 글꼴을 사용하여 렌더링되는 히어로 이미지와 대량의 텍스트는 잘 배치된 미리 로드 힌트를 통해 큰 이점을 누릴 수 있으며, 이러한 중요한 콘텐츠를 사용자에게 더 빠르게 제공할 기회가 있을 때 사용해야 합니다.

그러나 미리 로드 및 기타 최적화와 관련해서는 주의해야 합니다. 특히 너무 많은 리소스를 미리 로드하지 않는 것이 좋습니다. 너무 많은 리소스에 우선순위가 부여되면, 사실상 모든 리소스가 우선순위에서 배제됩니다. 과도한 미리 로드 힌트의 효과는 대역폭 경합이 더 두드러지는 느린 네트워크에서 특히 악영향을 끼칩니다.

대신 잘 배치된 미리 로드로 이점을 누릴 수 있는 몇 가지 고가치 리소스에 집중하세요. 글꼴을 미리 로드할 때는 리소스 로드 시간을 최대한 줄일 수 있도록 WOFF 2.0 형식으로 글꼴을 제공해야 합니다. WOFF 2.0은 우수한 브라우저 지원을 제공하므로 WOFF 1.0 또는 TrueType (TTF)과 같은 이전 형식을 사용하면 LCP 후보가 텍스트 노드인 경우 LCP가 지연됩니다.

LCP 및 자바스크립트의 경우 브라우저의 미리 로드 스캐너가 제대로 작동할 수 있도록 서버에서 완전한 마크업을 전송하는 것이 좋습니다. 전적으로 JavaScript에 의존하여 마크업을 렌더링하고 서버에서 렌더링된 HTML을 전송할 수 없는 환경을 제공하는 경우, 브라우저 미리 로드 스캐너가 불가능하도록 설정하고 JavaScript가 로드 및 실행을 완료할 때만 검색 가능한 리소스를 미리 로드하는 것이 좋습니다.

레이아웃 변경 횟수(CLS)

누적 레이아웃 변경 (CLS)은 웹 글꼴과 관련된 특히 중요한 측정항목이며, CLS는 글꼴 로드 방식을 관리하기 위해 font-display CSS 속성을 사용하는 웹 글꼴과 상당한 상호 작용이 있습니다. 웹 글꼴 관련 레이아웃 변경을 최소화하려면 다음 전략을 고려하세요.

  1. font-display에 기본값 block 값을 사용하는 동안 글꼴을 미리 로드합니다. 이것은 섬세한 균형입니다. 대체 없이 글꼴 표시를 차단하면 사용자 환경 문제로 간주될 수 있습니다. 한편 font-display: block;를 사용하여 글꼴을 로드하면 웹 글꼴과 관련된 레이아웃 변경이 사라집니다. 반면, 웹 글꼴이 사용자 환경에 중요한 경우 최대한 빨리 로드되도록 하는 것이 좋습니다. 미리 로드를 font-display: block;와 결합하는 것이 허용될 수도 있습니다.
  2. font-displayfallback 값을 사용하는 동안 글꼴을 미리 로드합니다. fallback는 차단 기간이 매우 짧다는 점에서 swapblock 간의 절충입니다.
  3. 미리 로드하지 않고 font-displayoptional 값을 사용합니다. 웹 글꼴이 사용자 환경에 중요하지는 않지만 여전히 많은 양의 페이지 텍스트를 렌더링하는 데 사용되는 경우 optional 값을 사용하는 것이 좋습니다. 악조건에서 optional는 다음 탐색을 위해 배경에 글꼴을 로드하는 동안 페이지 텍스트를 대체 글꼴로 표시합니다. 시스템 글꼴이 즉시 렌더링되고 후속 페이지 로드 시 레이아웃 변경 없이 글꼴이 즉시 로드되므로 이러한 조건으로 인해 CLS가 개선됩니다.

CLS는 웹 글꼴과 관련하여 최적화하기 어려운 측정항목입니다. 항상 그렇듯이 실험실에서 실험하되 필드 데이터를 신뢰하여 글꼴 로드 전략이 CLS를 개선하거나 더 악화시키고 있는지 확인하세요.

다음 페인트와의 상호작용 (INP)

Interaction to Next Paint(다음 페인트에 대한 상호작용)는 사용자 입력에 대한 응답성을 측정하는 측정항목입니다. 웹에서 상호작용의 가장 큰 비중은 JavaScript에 의해 좌우되므로, 중요한 상호작용을 지원하는 JavaScript를 미리 로드하면 페이지의 INP를 낮게 유지하는 데 도움이 될 수 있습니다. 하지만 시작 시 너무 많은 자바스크립트를 미리 로드하면 너무 많은 리소스가 대역폭을 두고 경합하는 경우 의도하지 않은 부정적인 결과를 초래할 수 있습니다.

또한 코드 분할 방법에 대해서도 주의해야 합니다. 코드 분할은 시작 중에 로드되는 JavaScript의 양을 줄이는 데 뛰어난 최적화 기능이지만, 상호작용 시작 시 바로 로드된 JavaScript에 의존하는 경우에는 상호작용이 지연될 수 있습니다. 이를 보완하려면 사용자의 의도를 검토하고 상호작용이 발생하기 전에 필요한 JavaScript 청크를 위해 미리 로드해야 합니다. 양식의 필드에 포커스가 맞춰질 때 양식 콘텐츠의 유효성을 검사하는 데 필요한 자바스크립트를 미리 로드하는 경우를 예로 들 수 있습니다.

결론

페이지 속도를 높이려면 브라우저에서 늦게 발견한 중요한 리소스를 미리 로드합니다. 모든 것을 미리 로드하면 비생산적이므로 preload를 드물게 사용하고 실제 환경에 미치는 영향을 측정하세요.