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

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

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

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

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

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

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

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

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

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

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

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

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

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

사용 사례

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

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

CSS 파일 미리 로드

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

JavaScript 파일 미리 로드

브라우저는 미리 로드된 파일을 실행하지 않으므로 미리 로드는 가져오기를 실행과 분리하는 데 유용하며, 이를 통해 Time to Interactive와 같은 측정항목을 개선할 수 있습니다. 미리 로드는 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으로 JavaScript 모듈 미리 로드

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

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

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

Core Web Vitals에 미리 로드가 미치는 영향

미리 로드는 로드 속도에 영향을 미치는 강력한 성능 최적화 기능입니다. 이러한 최적화로 인해 사이트의 Core Web Vitals가 변경될 수 있으므로 숙지하는 것이 중요합니다.

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

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

하지만 미리 로드 및 기타 최적화에는 주의해야 합니다. 특히 리소스를 너무 많이 미리 로드하지 마세요. 우선순위가 지정된 리소스가 너무 많으면 사실상 어느 리소스도 우선순위가 지정되지 않은 것과 마찬가지입니다. 과도한 미리 로드 힌트의 효과는 대역폭 경합이 더 두드러지는 느린 네트워크의 사용자에게 특히 해로울 수 있습니다.

대신 적절한 위치에 미리 로드하면 도움이 될 것으로 알고 있는 몇 가지 가치가 높은 리소스에 집중하세요. 글꼴을 미리 로드할 때는 리소스 로드 시간을 최대한 줄이기 위해 WOFF 2.0 형식으로 글꼴을 게재해야 합니다. WOFF 2.0은 우수한 브라우저 지원을 제공하므로 LCP 후보가 텍스트 노드인 경우 WOFF 1.0 또는 TTF (TrueType)와 같은 이전 형식을 사용하면 LCP가 지연됩니다.

LCP 및 JavaScript의 경우 브라우저의 미리 로드 스캐너가 제대로 작동하려면 서버에서 전체 마크업을 전송해야 합니다. 마크업을 렌더링하는 데 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-display에 미리 로드 없이 optional 값을 사용합니다. 웹 글꼴이 사용자 환경에 중요하지 않지만 상당한 양의 페이지 텍스트를 렌더링하는 데 사용되는 경우 optional 값을 사용하는 것이 좋습니다. 불리한 조건에서 optional는 대체 글꼴로 페이지 텍스트를 표시하는 동시에 다음 탐색을 위해 백그라운드에서 글꼴을 로드합니다. 이러한 조건에서 최종 결과는 CLS가 개선되는 것입니다. 시스템 글꼴이 즉시 렌더링되고 후속 페이지 로드 시 레이아웃 전환 없이 글꼴이 즉시 로드되기 때문입니다.

CLS는 웹 글꼴과 관련하여 최적화하기가 어려운 측정항목입니다. 언제나 그렇듯이 실습에서 실험해 보고, 글꼴 로드 전략이 CLS를 개선하는지 아니면 악화되는지 판단하려면 필드 데이터를 신뢰하세요.

다음 페인트에 대한 상호작용(INP)

다음 페인트에 대한 상호작용은 사용자 입력에 대한 응답성을 측정하는 측정항목입니다. 웹에서의 상호작용의 대부분은 JavaScript로 구동되므로 중요한 상호작용을 지원하는 JavaScript를 미리 로드하면 페이지의 INP를 낮추는 데 도움이 될 수 있습니다. 그러나 시작 중에 너무 많은 JavaScript를 미리 로드하면 너무 많은 리소스가 대역폭을 두고 경합하고 있는 경우 의도치 않은 부정적인 결과를 초래할 수 있습니다.

코드 분할을 수행하는 방법에도 주의를 기울이는 것이 좋습니다. 코드 분할은 시작 중에 로드되는 JavaScript의 양을 줄이는 데 매우 효과적인 최적화이지만 상호작용 시작 시 바로 로드되는 JavaScript를 사용하는 경우 상호작용이 지연될 수 있습니다. 이를 보완하려면 사용자의 의도를 검사하고 상호작용이 발생하기 전에 필요한 JavaScript 청크의 미리 로드를 삽입해야 합니다. 한 가지 예로 양식의 필드 중 하나에 포커스가 있을 때 양식 콘텐츠의 유효성을 검사하는 데 필요한 JavaScript를 미리 로드하는 것이 있습니다.

결론

페이지 속도를 개선하려면 브라우저에서 늦게 발견되는 중요한 리소스를 미리 로드하세요. 모든 항목을 미리 로드하면 효과가 없으므로 preload를 가급적 적게 사용하고 실제 환경에서 영향을 측정하세요.