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

웹페이지를 열면 브라우저가 서버에 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">

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

리소스 힌트(예: preconnect, prefetch)는 브라우저가 적합하다고 판단한 대로 실행됩니다. 반면 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 파일 미리 로드

브라우저는 미리 로드된 파일을 실행하지 않으므로 미리 로드는 실행과 가져오기를 분리하는 데 유용하며, 이를 통해 상호작용 시작 시간과 같은 측정항목을 개선할 수 있습니다. 미리 로드는 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-displayoptional 값을 사용합니다. 웹 글꼴이 사용자 환경에 중요하지는 않지만 많은 양의 페이지 텍스트를 렌더링하는 데 계속 사용되는 경우 optional 값을 사용하는 것이 좋습니다. 부정적인 조건에서 optional는 다음 탐색을 위해 백그라운드에서 글꼴을 로드하는 동안 페이지 텍스트를 대체 글꼴로 표시합니다. 이러한 조건의 최종 결과는 CLS가 개선됩니다. 시스템 글꼴이 즉시 렌더링되고 후속 페이지 로드 시 레이아웃 변경 없이 글꼴이 즉시 로드되기 때문입니다.

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

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

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

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

결론

페이지 속도를 높이려면 브라우저에서 나중에 발견한 중요한 리소스를 미리 로드하세요. 모든 것을 미리 로드하면 비생산적이므로 preload는 가급적 사용하지 말고 실제 상황에서의 영향을 측정하세요.