브라우저 미리 로드 스캐너와 싸우지 마세요.

브라우저 미리 로드 스캐너가 무엇인지, 성능에 어떤 도움이 되는지, 어떻게 방해받지 않을 수 있는지 알아보세요.

페이지 속도 최적화에서 간과된 측면 중 하나는 브라우저 내부 기능에 대해 아는 것입니다. 브라우저는 개발자가 할 수 없는 방식으로 성능을 개선하기 위해 특정 최적화를 수행합니다. 단, 이러한 최적화가 의도치 않게 방해되지 않는 경우에 한합니다.

이해해야 할 한 가지 내부 브라우저 최적화는 브라우저 미리 로드 스캐너입니다. 이 게시물에서는 미리 로드 스캐너의 작동 방식과 방해 요소를 방지하는 방법을 다룹니다.

미리 로드 스캐너란 무엇인가요?

모든 브라우저에는 원시 마크업을 토큰화하고 이를 객체 모델로 처리하는 기본 HTML 파서가 있습니다. <link> 요소로 로드된 스타일시트나 async 또는 defer 속성이 없는 <script> 요소로 로드된 스크립트와 같은 차단 리소스를 발견하면 파서가 일시중지될 때까지 이 모든 작업이 원활하게 진행됩니다.

HTML 파서 다이어그램
그림 1: 브라우저의 기본 HTML 파서 차단 방식을 보여주는 다이어그램 이 경우 파서는 외부 CSS 파일의 <link> 요소로 실행되어 CSS가 다운로드되고 파싱될 때까지 브라우저가 문서의 나머지 부분을 파싱하거나 렌더링하는 것을 차단합니다.

CSS 파일의 경우 스타일이 적용되기 전에 페이지의 스타일이 지정되지 않은 버전을 잠시 볼 수 있는 스타일이 지정되지 않은 콘텐츠 플래시 (FOUC)를 방지하기 위해 파싱과 렌더링이 모두 차단됩니다.

스타일이 지정되지 않은 상태 (왼쪽)와 스타일이 지정된 상태 (오른쪽)의 web.dev 홈페이지
그림 2: FOUC를 시뮬레이션한 예 왼쪽은 스타일이 없는 web.dev의 첫 페이지입니다. 오른쪽은 스타일이 적용된 같은 페이지입니다. 스타일시트를 다운로드하고 처리하는 동안 브라우저가 렌더링을 차단하지 않으면 플래시에서 스타일이 지정되지 않을 수 있습니다.

또한 브라우저에서 defer 또는 async 속성이 없는 <script> 요소가 있는 경우 페이지의 파싱과 렌더링을 차단합니다.

그 이유는 기본 HTML 파서가 작업을 수행하는 동안에는 지정된 스크립트가 DOM을 수정할지 브라우저가 확실히 알 수 없기 때문입니다. 따라서 차단된 파싱 및 렌더링의 영향이 미미하게 되도록 문서 끝에 자바스크립트를 로드하는 것이 일반적입니다.

브라우저가 파싱과 렌더링을 모두 차단해야 하는 이유는 다음과 같습니다. 그러나 이러한 중요한 단계 중 하나를 차단하는 것은 바람직하지 않습니다. 다른 중요한 리소스의 검색을 지연시켜 프로그램 참여를 지연시킬 수 있기 때문입니다. 다행히 브라우저는 미리 로드 스캐너라고 하는 보조 HTML 파서를 통해 이러한 문제를 완화하기 위해 최선을 다합니다.

기본 HTML 파서 (왼쪽)와 보조 HTML 파서인 미리 로드 스캐너 (오른쪽)의 다이어그램.
그림 3: 미리 로드 스캐너가 기본 HTML 파서와 동시에 작동하여 애셋을 추측하는 방법을 보여주는 다이어그램 여기서 기본 HTML 파서는 <body> 요소의 이미지 마크업 처리를 시작하기 전에 CSS를 로드하고 처리할 때 차단됩니다. 하지만 미리 로드 스캐너는 원시 마크업에서 이미지 리소스를 찾아 기본 HTML 파서의 차단이 해제되기 전에 로드를 시작할 수 있습니다.

미리 로드 스캐너의 역할은 추측성입니다. 즉, 기본 HTML 파서가 리소스를 발견하기 전에 기회적으로 가져올 리소스를 찾기 위해 원시 마크업을 검사합니다.

미리 로드 스캐너가 작동하는지 확인하는 방법

미리 로드 스캐너는 차단된 렌더링 및 파싱으로 인해 존재합니다. 이 두 가지 성능 문제가 한 번도 없었다면 미리 로드 스캐너가 그다지 유용하지 않을 것입니다. 웹페이지가 미리 로드 스캐너의 이점을 제공하는지 여부를 파악하기 위한 핵심은 이러한 차단 현상에 따라 달라집니다. 이를 위해 미리 로드 스캐너가 작동하는 위치를 확인하는 요청에 인위적인 지연을 적용할 수 있습니다.

기본 텍스트 및 이미지가 포함된 이 페이지를 스타일시트와 함께 예시로 들어보세요. CSS 파일은 렌더링과 파싱을 모두 차단하기 때문에 프록시 서비스를 통해 스타일시트에 대해 인위적인 지연이 2초 발생하게 됩니다. 이러한 지연으로 인해 미리 로드 스캐너가 작동하는 네트워크 폭포식 구조에서 더 쉽게 확인할 수 있습니다.

WebPageTest 네트워크 워터폴 차트는 스타일시트에 인위적으로 2초 지연된 효과를 보여줍니다.
그림 4: 시뮬레이션된 3G 연결을 통해 휴대기기의 Chrome에서 실행된 웹페이지WebPageTest 네트워크 워터폴 차트 스타일시트가 로드되기 전에 프록시를 통해 인위적으로 2초 지연되더라도, 마크업 페이로드의 후반부에 있는 이미지는 미리 로드 스캐너에 의해 검색됩니다.

폭포식 구조에서 볼 수 있듯이 미리 로드 스캐너는 렌더링 및 문서 파싱이 차단되는 동안에도 <img> 요소를 검색합니다. 이러한 최적화가 없으면 브라우저는 차단 기간 동안 편의적으로 항목을 가져올 수 없으며 더 많은 리소스 요청이 동시 요청이 아니라 연속적이 됩니다.

이 장난감 예를 살펴봤으니 미리 로드 스캐너를 물리칠 수 있는 실제 패턴과 이를 해결하기 위해 할 수 있는 작업을 살펴보겠습니다.

async 스크립트가 삽입됨

<head>에 다음과 같은 인라인 JavaScript가 포함된 HTML이 있다고 가정해 보겠습니다.

<script>
  const scriptEl = document.createElement('script');
  scriptEl.src = '/yall.min.js';

  document.head.appendChild(scriptEl);
</script>

삽입된 스크립트는 기본적으로 async이므로 이 스크립트가 삽입되면 async 속성이 적용된 것처럼 작동합니다. 즉, 최대한 빨리 실행되며 렌더링을 차단하지 않습니다. 최적이라고 할 수 있겠죠? 그러나 이 인라인 <script>가 외부 CSS 파일을 로드하는 <link> 요소 다음에 온다고 가정하면 최적화되지 않은 결과가 나오게 됩니다.

이 WebPageTest 차트는 스크립트가 삽입될 때 무효화된 미리 로드 스캔을 보여줍니다.
그림 5: 시뮬레이션된 3G 연결을 통해 휴대기기의 Chrome에서 실행된 웹페이지의 WebPageTest 네트워크 워터폴 차트 페이지에는 단일 스타일시트와 삽입된 async 스크립트가 포함되어 있습니다. 미리 로드 스캐너는 스크립트가 클라이언트에 삽입되므로 렌더링 차단 단계에서 스크립트를 검색할 수 없습니다.

여기에서 어떤 일이 발생했는지 분석해 보겠습니다.

  1. 0초에 기본 문서가 요청됩니다.
  2. 1.4초에 탐색 요청의 첫 번째 바이트가 도착합니다.
  3. 2.0초에 CSS와 이미지가 요청됩니다.
  4. 파서가 스타일시트 로드를 차단하며 async 스크립트를 삽입하는 인라인 자바스크립트는 2.6초에 해당 스타일시트 뒤에 오기 때문에 스크립트가 제공하는 기능을 최대한 빨리 사용할 수 없습니다.

이는 스타일시트가 다운로드를 완료한 후에만 스크립트 요청이 발생하므로 최적의 방법이 아닙니다. 이렇게 하면 스크립트가 최대한 빨리 실행되지 않습니다. 반대로 <img> 요소는 서버에서 제공하는 마크업에서 검색할 수 있으므로 미리 로드 스캐너에서 탐색합니다.

그렇다면 DOM에 스크립트를 삽입하는 대신 일반 <script> 태그를 async 속성과 함께 사용하면 어떻게 될까요?

<script src="/yall.min.js" async></script>

결과는 다음과 같습니다.

스타일시트를 다운로드하고 처리하는 동안 브라우저의 기본 HTML 파서가 차단되더라도 HTML 스크립트 요소를 사용하여 로드된 비동기 스크립트가 브라우저 미리 로드 스캐너에서 어떻게 검색되는지 보여주는 WebPageTest 네트워크 폭포식 구조입니다.
그림 6: 시뮬레이션된 3G 연결을 통해 휴대기기의 Chrome에서 실행된 웹페이지의 WebPageTest 네트워크 워터폴 차트 페이지에는 하나의 스타일시트와 하나의 async <script> 요소가 포함됩니다. 미리 로드 스캐너는 렌더링 차단 단계에서 스크립트를 발견하고 CSS와 동시에 로드합니다.

rel=preload를 사용하면 이러한 문제를 해결할 수 있다고 제안하고 싶은 유혹이 들 수도 있습니다. 이 방법은 효과적이지만 몇 가지 부작용이 있을 수 있습니다. 결국 rel=preload를 사용하여 <script> 요소를 DOM에 삽입하지 않으면 피할 수 있는 문제를 왜 해결할까요?

의도하지 않은 부작용이 발생할 수 있는 방식이지만 rel=preload 리소스 힌트를 사용하여 비동기가 삽입된 스크립트의 검색을 촉진하는 방법을 보여주는 WebPageTest 폭포식 구조
그림 7: 시뮬레이션된 3G 연결을 통해 휴대기기의 Chrome에서 실행된 웹페이지의 WebPageTest 네트워크 워터폴 차트 페이지에는 단일 스타일시트와 삽입된 async 스크립트가 포함되어 있지만, 더 빨리 검색되도록 async 스크립트가 미리 로드됩니다.

여기서 문제를 미리 로드하면 문제가 '해결'되지만 첫 번째 두 데모의 async 스크립트는 <head>에 로드되었음에도 불구하고 '낮음' 우선순위로 로드되지만 스타일시트는 '가장 높은' 우선순위로 로드됩니다. async 스크립트가 미리 로드된 마지막 데모에서 스타일시트는 여전히 '가장 높은' 우선순위로 로드되지만 스크립트의 우선순위는 '높음'으로 승격되었습니다.

리소스의 우선순위가 높아지면 브라우저는 리소스에 더 많은 대역폭을 할당합니다. 즉, 스타일시트의 우선순위가 가장 높더라도 스크립트의 우선순위가 높아질 경우 대역폭 경합이 발생할 수 있습니다. 이는 연결이 느린 경우나 리소스가 상당히 큰 경우 하나의 요인이 될 수 있습니다.

여기서 답은 간단합니다. 시작 시 스크립트가 필요한 경우 미리 로드 스캐너를 DOM에 삽입하여 이 스캐너를 무효화하면 안 됩니다. 필요에 따라 <script> 요소 배치뿐만 아니라 deferasync와 같은 속성도 실험해 봅니다.

JavaScript를 사용한 지연 로드

지연 로드는 데이터를 보존하는 좋은 방법이며 종종 이미지에 적용됩니다. 그러나 말하자면 '스크롤 없이 볼 수 있는 부분'의 이미지에 지연 로드가 잘못 적용되는 경우가 있습니다.

이로 인해 미리 로드 스캐너와 관련된 리소스 검색 가능성에 문제가 발생할 수 있으며, 이미지에 대한 참조를 검색, 다운로드, 디코딩, 표시하는 데 걸리는 시간이 불필요하게 지연될 수 있습니다. 다음 이미지 마크업을 예로 들어 보겠습니다.

<img data-src="/sand-wasp.jpg" alt="Sand Wasp" width="384" height="255">

data- 접두사 사용은 JavaScript 기반 지연 로더에서 일반적인 패턴입니다. 이미지가 표시 영역으로 스크롤되면 지연 로더는 data- 접두사를 제거합니다. 즉, 앞의 예에서 data-srcsrc가 됩니다. 이 업데이트는 브라우저에 리소스를 가져오라는 메시지를 표시합니다.

이 패턴은 시작 시 표시 영역에 있는 이미지에 적용할 때까지 문제가 되지 않습니다. 미리 로드 스캐너는 src (또는 srcset) 속성과 동일한 방식으로 data-src 속성을 읽지 않으므로 이미지 참조는 더 일찍 검색되지 않습니다. 더 안 좋은 점은 지연 로더 JavaScript가 다운로드, 컴파일, 실행된 이후까지 이미지 로드가 지연된다는 점입니다.

브라우저 미리 로드 스캐너가 이미지 리소스를 찾을 수 없어 시작 시 표시 영역에 있는 지연 로드된 이미지가 지연 로드되고 지연 로드 작업에 필요한 JavaScript가 로드되는 경우에만 로드되는 WebPageTest 네트워크 워터폴 차트입니다. 이미지가 생각보다 훨씬 늦게 발견된 경우
그림 8: 시뮬레이션된 3G 연결을 통해 휴대기기의 Chrome에서 실행된 웹페이지의 WebPageTest 네트워크 워터폴 차트 이미지 리소스는 시작 중에 표시 영역에 표시되더라도 불필요하게 지연 로드됩니다. 그러면 미리 로드 스캐너가 무효화되고 불필요한 지연이 발생합니다.

표시 영역의 크기에 따라 이미지의 크기에 따라 최대 콘텐츠 렌더링 시간 (LCP)의 후보 요소가 될 수 있습니다. 미리 로드 스캐너가 미리(아마도 페이지의 스타일시트가 렌더링을 차단하는 시점) 이미지 리소스를 추측하여 가져올 수 없는 경우 LCP에 문제가 발생합니다.

해결 방법은 이미지 마크업을 변경하는 것입니다.

<img src="/sand-wasp.jpg" alt="Sand Wasp" width="384" height="255">

미리 로드 스캐너가 이미지 리소스를 더 빠르게 검색하여 가져오기 때문에 시작 시 표시 영역에 있는 이미지에 가장 적합한 패턴입니다.

시작 시 표시 영역의 이미지 로드 시나리오를 보여주는 WebPageTest 네트워크 워터폴 차트 이미지가 느리게 로드되지 않았습니다. 즉, 로드할 스크립트에 의존하지 않습니다. 즉, 미리 로드 스캐너에서 더 빨리 검색할 수 있습니다.
그림 9: 시뮬레이션된 3G 연결을 통해 휴대기기의 Chrome에서 실행된 웹페이지의 WebPageTest 네트워크 워터폴 차트 미리 로드 스캐너는 CSS 및 JavaScript가 로드되기 전에 이미지 리소스를 발견하므로 브라우저가 이미지 리소스를 쉽게 로드할 수 있습니다.

이 간단한 예의 결과는 느린 연결에서 LCP가 100밀리초 개선된 것입니다. 큰 개선이 아닌 것처럼 보일 수 있지만, 이 솔루션은 빠른 마크업 수정이며 대부분의 웹페이지가 이 예제보다 더 복잡하다고 생각하면 됩니다. 즉, LCP 후보는 다른 많은 리소스와 대역폭을 두고 경합해야 할 수 있으므로 이와 같은 최적화가 점점 더 중요해집니다.

CSS 배경 이미지

브라우저 미리 로드 스캐너는 마크업을 스캔합니다. background-image 속성에서 참조하는 이미지의 가져오기가 포함될 수 있는 CSS와 같은 다른 리소스 유형은 검색하지 않습니다.

HTML과 마찬가지로 브라우저는 CSS를 CSSOM이라고 하는 자체 개체 모델로 처리합니다. CSSOM이 구성될 때 외부 리소스가 검색되는 경우 이러한 리소스는 미리 로드 스캐너가 아니라 검색 시 요청됩니다.

페이지의 LCP 후보가 CSS background-image 속성이 포함된 요소라고 가정해 보겠습니다. 리소스가 로드되면 다음과 같은 결과가 발생합니다.

배경 이미지 속성을 사용하여 CSS에서 LCP 후보가 로드된 페이지를 보여주는 WebPageTest 네트워크 워터폴 차트입니다. LCP 후보 이미지가 브라우저 미리 로드 스캐너가 검사할 수 없는 리소스 유형이므로 CSS가 다운로드되고 처리될 때까지 리소스의 로드가 지연되어 LCP 후보의 페인트 시간이 지연됩니다.
그림 10: 시뮬레이션된 3G 연결을 통해 휴대기기의 Chrome에서 실행된 웹페이지의 WebPageTest 네트워크 워터폴 차트 페이지의 LCP 후보는 CSS background-image 속성이 있는 요소입니다 (행 3). 요청한 이미지는 CSS 파서가 찾을 때까지 가져오기를 시작하지 않습니다.

이 경우 미리 로드 스캐너는 관련이 없으므로 많이 무효화되지 않습니다. 그렇더라도 페이지의 LCP 후보가 background-image CSS 속성의 LCP 후보라면 이미지를 미리 로드하는 것이 좋습니다.

<!-- Make sure this is in the <head> below any
     stylesheets, so as not to block them from loading -->
<link rel="preload" as="image" href="lcp-image.jpg">

rel=preload 힌트는 작지만 브라우저가 이미지를 찾는 데 도움이 됩니다.

rel=preload 힌트를 사용하여 훨씬 빨리 로드되는 CSS 배경 이미지 (LCP 후보)를 보여주는 WebPageTest 네트워크 폭포식 구조 차트입니다. LCP 시간은 약 250밀리초 향상됩니다.
그림 11: 시뮬레이션된 3G 연결을 통해 휴대기기의 Chrome에서 실행된 웹페이지의 WebPageTest 네트워크 워터폴 차트 페이지의 LCP 후보는 CSS background-image 속성이 있는 요소입니다 (행 3). rel=preload 힌트는 브라우저가 힌트가 없는 경우보다 약 250밀리초 더 빨리 이미지를 찾도록 도와줍니다.

rel=preload 힌트를 사용하면 LCP 후보가 더 빨리 발견되어 LCP 시간이 줄어듭니다. 이 힌트는 이 문제를 해결하는 데 도움이 되지만 이미지 LCP 후보가 CSS에서 로드되어야 하는지 여부를 평가하는 것이 더 나을 수 있습니다. <img> 태그를 사용하면 미리 로드 스캐너가 검색하도록 허용하면서 표시 영역에 적합한 이미지를 로드하는 작업을 더 효과적으로 제어할 수 있습니다.

너무 많은 리소스 삽입

인라인 처리는 HTML 내부에 리소스를 배치하는 방법입니다. base64 인코딩을 사용하여 <style> 요소의 스타일시트, <script> 요소의 스크립트, 기타 거의 모든 리소스의 인라인을 삽입할 수 있습니다.

리소스에 대해 별도의 요청이 발행되지 않으므로 리소스를 인라인 처리하는 것이 다운로드하는 것보다 빠를 수 있습니다. 이 파일은 문서 내에 표시되며 바로 로드됩니다. 하지만 다음과 같은 중대한 단점이 있습니다.

  • HTML을 캐시하지 않고 HTML 응답이 동적일 경우 캐시할 수 없는 경우 인라인 리소스는 절대 캐시되지 않습니다. 이는 인라인된 리소스를 재사용할 수 없기 때문에 성능에 영향을 미칩니다.
  • HTML을 캐시할 수 있더라도 인라인 리소스는 문서 간에 공유되지 않습니다. 따라서 전체 출처에서 캐시하고 재사용할 수 있는 외부 파일에 비해 캐싱 효율성이 저하됩니다.
  • 인라인을 너무 많이 사용하면 미리 로드 스캐너가 문서의 후반부에서 리소스를 검색하지 않도록 지연됩니다. 인라인 처리된 여분의 콘텐츠를 다운로드하는 데 시간이 더 오래 걸리기 때문입니다.

이 페이지를 예로 들어보겠습니다. 특정 조건에서 LCP 후보는 페이지 상단의 이미지이고 CSS는 <link> 요소에 의해 로드된 별도의 파일에 있습니다. 또한 페이지는 CSS 리소스에서 별도의 파일로 요청되는 4개의 웹 글꼴을 사용합니다.

4개의 글꼴이 참조된 외부 CSS 파일이 있는 페이지의 WebPageTest 네트워크 워터폴 차트 LCP 후보 이미지는 일정 기간에 미리 로드 스캐너에서 검색됩니다.
그림 12: 시뮬레이션된 3G 연결을 통해 휴대기기의 Chrome에서 실행된 웹페이지의 WebPageTest 네트워크 워터폴 차트 페이지의 LCP 후보는 <img> 요소에서 로드된 이미지이지만 미리 로드 스캐너에서 발견됩니다. 페이지에 필요한 CSS와 글꼴은 별도의 리소스에서 로드되어 미리 로드 스캐너의 작업 수행이 지연되지 않기 때문입니다.

그러면 CSS 모든 글꼴이 base64 리소스로 인라인 처리되면 어떻게 될까요?

4개의 글꼴이 참조된 외부 CSS 파일이 있는 페이지의 WebPageTest 네트워크 워터폴 차트 미리 로드 스캐너에서 LCP 이미지 탐색이 상당히 지연되고 있습니다 .
그림 13: 시뮬레이션된 3G 연결을 통해 휴대기기의 Chrome에서 실행된 웹페이지의 WebPageTest 네트워크 워터폴 차트 페이지의 LCP 후보는 <img> 요소에서 로드된 이미지이지만 `` 에 있는 CSS 및 네 개의 글꼴 리소스의 인라인 처리는 이러한 리소스가 완전히 다운로드될 때까지 미리 로드 스캐너가 이미지를 검색하는 것을 지연시킵니다.

인라인 처리의 영향은 이 예시에서 LCP 및 전반적인 성능에 부정적인 영향을 미칩니다. 아무것도 인라인하지 않은 페이지 버전은 약 3.5초 내에 LCP 이미지를 페인팅합니다. 모든 항목을 인라인으로 표시하는 페이지가 7초가 되기 전까지는 LCP 이미지를 페인트하지 않습니다.

미리 로드 스캐너 외에 더 많은 기능이 있습니다. base64는 바이너리 리소스에 비효율적인 형식이므로 글꼴 인라인 처리는 좋은 전략이 아닙니다. 또 다른 중요한 요소는 CSSOM에서 필요하다고 판단하지 않는 한 외부 글꼴 리소스는 다운로드되지 않는다는 것입니다. 이러한 글꼴이 base64로 인라인 처리되면 현재 페이지에 필요한지 여부와 관계없이 다운로드됩니다.

미리 로드로 문제를 개선할 수 있을까요? 물론입니다. LCP 이미지를 미리 로드하여 LCP 시간을 단축할 수는 있지만, 인라인 리소스로 캐시할 수 없을 가능성이 있는 HTML을 팽창시키면 다른 부정적인 결과가 나타납니다. 콘텐츠가 포함된 첫 페인트 (FCP)도 이 패턴의 영향을 받습니다. 아무것도 인라인되지 않는 페이지 버전에서는 FCP가 약 2.7초입니다. 모든 항목이 인라인된 버전에서 FCP는 약 5.8초입니다.

HTML에 항목, 특히 base64로 인코딩된 리소스를 인라인 처리할 때 매우 주의해야 합니다. 매우 작은 리소스를 제외하고는 일반적으로 권장되지 않습니다. 인라인을 너무 많이 하면 불이 붙은 곳이기 때문에 가능한 한 인라인으로 배치해야 합니다.

클라이언트 측 JavaScript로 렌더링 마크업

자바스크립트는 페이지 속도에 명백하게 영향을 준다는 점에는 의심의 여지가 없습니다. 개발자들은 상호작용 기능을 제공하기 위해 이를 사용할 뿐만 아니라, 콘텐츠 자체를 제공하기 위해 이를 사용하는 경향도 있었습니다. 이를 통해 어떤 면에서 더 나은 개발자 환경을 제공할 수 있지만, 개발자가 얻는 이점이 사용자에게 항상 이점이 되는 것은 아닙니다.

미리 로드 스캐너를 무력화할 수 있는 한 가지 패턴은 클라이언트 측 JavaScript로 마크업을 렌더링하는 것입니다.

JavaScript로 클라이언트에서 완전히 렌더링된 이미지와 텍스트가 포함된 기본 페이지를 보여주는 WebPageTest 네트워크 폭포식 구조입니다. 마크업은 자바스크립트 내에 포함되어 있기 때문에 미리 로드 스캐너는 어떠한 리소스도 감지할 수 없습니다. JavaScript 프레임워크에 필요한 추가 네트워크 및 처리 시간으로 인해 모든 리소스가 추가로 지연됩니다.
그림 14: 시뮬레이션된 3G 연결을 통해 휴대기기의 Chrome에서 실행된 클라이언트 렌더링 웹페이지의 WebPageTest 네트워크 워터폴 차트 콘텐츠는 JavaScript에 포함되어 있으며 프레임워크에 의존하여 렌더링되므로 클라이언트가 렌더링한 마크업의 이미지 리소스는 미리 로드 스캐너에서 숨겨집니다. 이와 동등한 서버 렌더링 환경은 그림 9에 묘사되어 있습니다.

마크업 페이로드가 포함되어 있고 브라우저에서 JavaScript에 의해 전적으로 렌더링되는 경우, 해당 마크업의 리소스는 사실상 미리 로드 스캐너에 표시되지 않습니다. 이렇게 하면 중요한 리소스의 검색이 지연되어 LCP에 확실히 영향을 줍니다. 이 예에서는 JavaScript를 표시할 필요가 없는 동등한 서버 렌더링 환경과 비교했을 때 LCP 이미지 요청이 상당히 지연됩니다.

이는 이 문서의 초점에서 다소 벗어나지만, 렌더링 마크업이 클라이언트에 미치는 영향은 미리 로드 스캐너를 무력화하는 것에 그치지 않습니다. 우선, 필요하지 않은 환경을 지원하기 위해 자바스크립트를 도입하면 다음 페인트와의 상호작용 (INP)에 영향을 미칠 수 있는 불필요한 처리 시간이 발생합니다.

또한 클라이언트에서 매우 많은 양의 마크업을 렌더링하면 서버에서 전송하는 마크업의 양에 비해 장기 작업이 생성될 가능성이 높습니다. 그 이유는 자바스크립트가 수반하는 추가 처리를 제외하고, 브라우저가 서버에서 마크업을 스트리밍하고, 긴 작업을 피하는 방식으로 렌더링을 분할하기 때문입니다. 반면 클라이언트 렌더링 마크업은 단일 모놀리식 작업으로 처리되어 INP 외에도 총 차단 시간 (TBT) 또는 최초 입력 반응 시간 (FID)과 같은 페이지 응답성 측정항목에 영향을 미칠 수 있습니다.

이 시나리오에 대한 해결 방법은 다음 질문에 대한 답변에 따라 달라집니다. 페이지의 마크업이 클라이언트에서 렌더링되지 않고 서버에서 제공되지 않는 이유가 있습니까? 이 질문에 대한 답이 '아니요'라면 서버 측 렌더링 (SSR) 또는 정적으로 생성된 마크업을 가능한 한 고려해야 합니다. 미리 로드 스캐너가 중요한 리소스를 미리 찾아서 편의적으로 가져오는 데 도움이 되기 때문입니다.

페이지에서 자바스크립트가 필요한 경우 페이지 마크업의 일부에 기능을 추가해야 하는 경우에도 SSR(바닐라 JavaScript 또는 하이드레이션)을 통해 이를 수행하여 두 기능을 모두 활용할 수 있습니다.

미리 로드 스캐너의 도움 받기

미리 로드 스캐너는 시작 시 페이지를 더 빠르게 로드하는 데 도움이 되는 매우 효과적인 브라우저 최적화 기능입니다. 중요한 리소스를 미리 발견하는 데 방해가 되는 패턴을 피하면 개발을 간소화할 뿐만 아니라 일부 웹 바이탈을 비롯한 여러 측정항목에서 더 나은 결과를 제공하는 더 나은 사용자 환경을 조성할 수 있습니다.

요약하자면, 이 게시물에서 기억해야 할 사항은 다음과 같습니다.

  • 브라우저 미리 로드 스캐너는 더 빨리 가져올 수 있는 리소스를 편의적으로 검색하도록 차단된 경우 기본 HTML 파서보다 먼저 검사하는 보조 HTML 파서입니다.
  • 초기 탐색 요청 시 서버에서 제공한 마크업에 없는 리소스는 미리 로드 스캐너에서 검색할 수 없습니다. 미리 로드 스캐너가 무효화되는 방법에는 다음이 포함되나 이에 국한되지 않습니다.
    • 자바스크립트, 이미지, 스타일시트 등 서버의 초기 마크업 페이로드에서 더 나은 결과를 가져올 수 있는 리소스를 JavaScript를 사용하여 DOM에 삽입합니다.
    • 자바스크립트 솔루션을 사용하여 스크롤 없이 볼 수 있는 이미지 또는 iframe의 지연 로드
    • JavaScript를 사용하는 문서 하위 리소스에 대한 참조를 포함할 수 있는 클라이언트의 렌더링 마크업
  • 미리 로드 스캐너는 HTML만 스캔합니다. LCP 후보를 비롯해 중요한 자산에 대한 참조를 포함할 수 있는 다른 리소스, 특히 CSS의 콘텐츠는 검사하지 않습니다.

어떤 이유로든 로드 성능을 높이는 미리 로드 스캐너의 기능에 부정적인 영향을 미치는 패턴을 피할 수 없다면 rel=preload 리소스 힌트를 고려해 보세요. rel=preload사용하는 경우 실험실 도구에서 테스트하여 원하는 효과를 제공하는지 확인합니다. 마지막으로, 너무 많은 리소스를 미리 로드하지 마세요. 모든 것에 우선순위를 두면 아무 일도 일어나지 않습니다.

자료

Unsplash의 히어로 이미지(Mohammad Rahmani )