Next.js에서 서드 파티 스크립트 로드 최적화

서드 파티 스크립트 로드를 최적화하는 내장 솔루션을 제공하는 Next.js 스크립트 구성요소의 비전을 이해합니다.

리나 소호니
리나 소호니
후세인 지르데
후세인 지르데

모바일 및 데스크톱에 게재되는 웹사이트에서 발생하는 요청의 약 45%가 서드 파티 요청이며 33% 가 스크립트입니다. 서드 파티 스크립트의 크기, 지연 시간, 로드는 사이트 성능에 상당한 영향을 미칠 수 있습니다. Next.js 스크립트 구성요소에는 권장사항과 기본값이 포함되어 있어 개발자가 애플리케이션에 서드 파티 스크립트를 도입하는 동시에 잠재적인 성능 문제를 즉시 해결할 수 있습니다.

서드 파티 스크립트 및 이러한 스크립트가 성능에 미치는 영향

서드 파티 스크립트를 사용하면 웹 개발자가 기존 솔루션을 활용하여 공통 기능을 구현하고 개발 시간을 줄일 수 있습니다. 그러나 이러한 스크립트의 작성자는 일반적으로 소비하는 웹사이트의 성능에 미치는 영향을 고려할 동기가 없습니다. 또한 이러한 스크립트는 이를 사용하는 개발자에게 블랙박스 역할을 합니다.

스크립트는 다양한 카테고리의 서드 파티 요청에서 웹사이트에서 다운로드하는 상당수의 서드 파티 바이트를 차지합니다. 기본적으로 브라우저는 문서 내 위치에 따라 스크립트의 우선순위를 지정하므로 사용자 환경에 중요한 스크립트의 검색 또는 실행이 지연될 수 있습니다.

페이지를 렌더링하려면 레이아웃에 필요한 서드 파티 라이브러리를 초기에 로드해야 합니다. 초기 렌더링에 필요하지 않은 서드 파티는 기본 스레드에서 다른 처리를 차단하지 않도록 지연되어야 합니다. Lighthouse에는 렌더링 차단 또는 기본 스레드 차단 스크립트에 플래그를 지정하는 두 가지 감사가 있습니다.

렌더링 차단 리소스 제거 및 서드 파티 사용량 최소화를 위한 Lighthouse 감사

중요한 리소스가 지연되지 않고 중요하지 않은 리소스가 중요한 리소스를 차단하지 않도록 페이지의 리소스 로드 순서를 고려하는 것이 중요합니다.

서드 파티의 영향을 줄이기 위한 권장사항이 있지만, 서드 파티가 이용하는 모든 서드 파티에 대해 이러한 권장사항을 구현하는 방법을 모르는 사용자도 있을 수 있습니다. 이는 다음과 같은 이유로 복잡할 수 있습니다.

  • 평균적으로 웹사이트는 모바일과 데스크톱에서 21~23개의 서로 다른 서드 파티(스크립트 포함)를 사용합니다. 사용법 및 권장사항은 기기마다 다를 수 있습니다.
  • 많은 서드 파티 구현은 특정 프레임워크 또는 UI 라이브러리가 사용되는지에 따라 다를 수 있습니다.
  • 최신 서드 파티 라이브러리가 자주 도입됩니다.
  • 동일한 서드 파티와 관련된 비즈니스 요구사항이 다양하면 개발자가 사용을 표준화하기가 어렵습니다.

서드 파티 스크립트에 집중하는 Aurora

Aurora는 오픈소스 웹 프레임워크 및 도구와 협력하여 개발자가 성능, 접근성, 보안, 모바일 준비도와 같은 사용자 경험의 측면을 개선할 수 있도록 강력한 기본값과 독보적인 도구를 제공합니다. 2021년에는 프레임워크 스택이 사용자 경험과 코어 웹 바이탈 측정항목을 개선할 수 있도록 지원하는 데 주력했습니다.

프레임워크 성능 개선 목표를 달성하기 위한 가장 중요한 단계 중 하나는 Next.js에서 서드 파티 스크립트의 이상적인 로드 순서를 연구하는 것이었습니다. Next.js와 같은 프레임워크는 개발자가 서드 파티를 포함한 리소스를 효율적으로 로드하는 데 도움이 되는 유용한 기본값과 기능을 제공하도록 특별히 마련되어 있습니다. Google은 다양한 프레임워크에서 가장 많이 렌더링을 차단하는 서드 파티를 찾기 위해 광범위한 HTTP Archive 및 Lighthouse 데이터를 조사했습니다.

애플리케이션에서 사용되는 기본 스레드 차단 타사 스크립트 문제를 해결하기 위해 스크립트 구성요소를 빌드했습니다. 이 구성요소는 시퀀싱 기능을 캡슐화하여 개발자에게 서드 파티 스크립트 로드를 더 효과적으로 제어할 수 있도록 합니다.

프레임워크 구성요소 없이 서드 파티 스크립트 시퀀싱

렌더링 차단 스크립트의 영향을 줄이기 위한 사용 가능한 안내는 서드 파티 스크립트를 효율적으로 로드하고 시퀀싱하기 위한 다음과 같은 방법을 제공합니다.

  1. 문서 파서를 차단하지 않고 브라우저에 중요하지 않은 서드 파티 스크립트를 로드하도록 지시하는 <script> 태그와 함께 async 또는 defer 속성을 사용합니다. 최초 페이지 로드 또는 첫 번째 사용자 상호작용에 필요하지 않은 스크립트는 중요하지 않은 것으로 간주될 수 있습니다.

       <script src="https://example.com/script1.js" defer></script>
       <script src="https://example.com/script2.js" async></script>
    
  2. 사전 연결 및 DNS 미리 가져오기를 사용하여 필수 출처에 대한 조기 연결을 설정합니다. 이렇게 하면 중요한 스크립트를 미리 다운로드할 수 있습니다.

       <head>
           <link rel="preconnect" href="http://PreconnThis.com">
           <link rel="dns-prefetch" href="http://PrefetchThis.com">
       </head>
    
  3. 기본 페이지 콘텐츠 로드가 완료되거나 사용자가 페이지에서 콘텐츠가 포함된 부분으로 스크롤할 때 서드 파티 리소스 및 삽입을 지연 로드합니다.

Next.js 스크립트 구성요소

Next.js 스크립트 구성요소는 스크립트 시퀀싱을 위한 위의 메서드를 구현하고 개발자가 로드 전략을 정의할 수 있는 템플릿을 제공합니다. 적절한 전략이 지정되면 다른 중요한 리소스를 차단하지 않고 최적으로 로드됩니다.

스크립트 구성요소는 HTML <script> 태그를 기반으로 하며, 전략 속성을 사용하여 타사 스크립트의 로드 우선순위를 설정하는 옵션을 제공합니다.

// Example for beforeInteractive:
<Script src="https://polyfill.io/v3/polyfill.min.js?features=IntersectionObserverEntry%2CIntersectionObserver" strategy="beforeInteractive" />

// Example for afterInteractive (default):
<Script src="https://example.com/samplescript.js" />

// Example for lazyonload:
<Script src="https://connect.facebook.net/en_US/sdk.js" strategy="lazyOnload" />

전략 속성은 세 가지 값을 사용할 수 있습니다.

  1. beforeInteractive: 이 옵션은 페이지가 상호작용하기 전에 실행해야 하는 중요한 스크립트에 사용할 수 있습니다. Next.js는 이러한 스크립트가 서버의 초기 HTML에 삽입되고 자체 번들된 다른 자바스크립트보다 먼저 실행되도록 합니다. 중요한 콘텐츠를 렌더링하는 데 필요한 동의 관리, 봇 감지 스크립트 또는 도우미 라이브러리가 이 전략에 적합합니다.

  2. afterInteractive: 적용되는 기본 전략이며 defer 속성을 사용하여 스크립트를 로드하는 것과 같습니다. 페이지가 대화형이 된 후에 브라우저에서 실행할 수 있는 스크립트(예: 애널리틱스 스크립트)에 사용해야 합니다. Next.js는 클라이언트 측에서 이러한 스크립트를 삽입하며, 페이지가 하이드레이션된 후에 실행됩니다. 따라서 달리 명시되지 않는 한 스크립트 구성요소를 사용하여 정의된 모든 타사 스크립트는 Next.js에 의해 지연되므로 강력한 기본값을 제공합니다.

  3. lazyOnload: 이 옵션은 브라우저가 유휴 상태일 때 우선순위가 낮은 스크립트를 지연 로드하는 데 사용할 수 있습니다. 이러한 스크립트에서 제공하는 기능은 페이지가 대화형이 된 직후(예: 채팅 또는 소셜 미디어 플러그인) 필요하지 않습니다.

개발자는 전략을 지정하여 애플리케이션에서 스크립트를 사용하는 방법을 Next.js에 알릴 수 있습니다. 이를 통해 프레임워크는 최적의 로드 순서를 보장하면서 스크립트를 로드하기 위한 최적화와 권장사항을 적용할 수 있습니다.

스크립트 구성요소를 사용하면 개발자는 늦게 로드되는 서드 파티를 위해 애플리케이션의 어느 위치에나 서드 파티 스크립트를 배치할 수 있으며 중요한 스크립트의 경우 문서 수준에 배치할 수 있습니다. 이는 스크립트 구성요소가 스크립트를 사용하는 구성요소와 같은 위치에 배치될 수 있음을 의미합니다. 하이드레이션 후에는 사용된 전략에 따라 스크립트가 처음 렌더링된 문서의 헤드 또는 본문 하단에 삽입됩니다.

영향 측정

Google에서는 Next.js 상거래 앱시작 블로그용 템플릿을 사용하여 서드 파티 스크립트를 포함할 경우의 영향을 측정하는 데 도움이 되는 두 가지 데모 앱을 만들었습니다. Google 태그 관리자 및 소셜 미디어 삽입에 일반적으로 사용되는 서드 파티가 이러한 앱의 페이지에 먼저 직접 포함된 다음 스크립트 구성요소를 통해 포함되었습니다. 그런 다음 WebPageTest에서 이러한 페이지의 성능을 비교했습니다.

Next.js 상거래 앱의 서드 파티 스크립트

아래에 나온 데모용 상거래 앱 템플릿에 서드 파티 스크립트가 추가되었습니다.

변경 전 변경 후
Google 태그 관리자(비동기식) 전략이 포함된 스크립트 구성요소 = afterInteractive 두 스크립트 모두
async 또는 defer가 없는 트위터 팔로우 버튼
스크립트 2개가 포함된 데모 1의 스크립트 및 스크립트 구성요소 구성

다음 비교에서는 두 버전의 Next.js 상거래 스타터 키트의 진행 상황을 시각적으로 보여줍니다. 보시다시피 LCP는 올바른 로딩 전략으로 스크립트 구성요소를 사용 설정하면 거의 1초 일찍 발생합니다.

LCP의 즉흥 연주를 보여주는 필름 스트립 비교

Next.js 블로그의 서드 파티 스크립트

아래와 같이 타사 스크립트가 데모 블로그 앱에 추가되었습니다.

변경 전 변경 후
Google 태그 관리자(비동기식) 전략이 포함된 스크립트 구성요소 = 4개의 스크립트 각각에 대한 decimalonload
비동기식 Twitter 팔로우 버튼
비동기 또는 연기가 없는 YouTube 구독 버튼
async 또는 defer가 없는 LinkedIn 팔로우 버튼
데모 2의 스크립트 및 스크립트 구성요소 구성(스크립트 4개)
스크립트 구성요소 유무에 따른 색인 페이지의 로드 진행률을 보여주는 동영상입니다. Script 구성요소를 사용하면 FCP가 0.5초 향상됩니다.

동영상에서 볼 수 있듯이 콘텐츠가 포함된 첫 페인트 (FCP)는 페이지에서 스크립트 구성요소가 없는 경우 0.9초, 스크립트 구성요소에서는 0.4초에 발생합니다.

스크립트 구성요소의 다음 단계

afterInteractivelazyOnload의 전략 옵션이 렌더링 차단 스크립트를 상당히 제어할 수 있는 반면, 스크립트 구성요소의 유용성을 높여주는 다른 옵션도 살펴봅니다.

웹 작업자 사용

웹 작업자를 사용하여 백그라운드 스레드에서 독립 스크립트를 실행할 수 있으므로 기본 스레드에서 사용자 인터페이스 작업을 처리하고 성능을 개선할 수 있습니다. 웹 작업자는 기본 스레드에서 UI 작업이 아닌 자바스크립트 처리를 오프로드하는 데 가장 적합합니다. 고객 지원 또는 마케팅에 사용되는 스크립트(일반적으로 UI와 상호작용하지 않음)는 백그라운드 스레드에서 실행하기에 적합할 수 있습니다. 경량형 서드 파티 라이브러리인 PartyTown을 사용해 이러한 스크립트를 웹 작업자로 격리할 수 있습니다.

Next.js 스크립트 구성요소의 현재 구현에서는 전략을 afterInteractive 또는 lazyOnload로 설정하여 기본 스레드에서 이러한 스크립트를 연기하는 것이 좋습니다. 향후 Next.js가 PartyTown 또는 커스텀 솔루션을 사용하여 웹 작업자에서 스크립트를 실행할 수 있도록 하는 새로운 전략 옵션 'worker'을 도입할 것을 제안합니다. 이 RFC에 대한 개발자의 의견을 환영합니다.

CLS 최소화

광고, 동영상 또는 소셜 미디어 피드 삽입과 같은 서드 파티 삽입으로 인해 지연 로드 시 레이아웃이 변경될 수 있습니다. 이는 사용자 환경 및 페이지의 레이아웃 변경 횟수 (CLS) 측정항목에 영향을 미칩니다. CLS는 삽입이 로드될 컨테이너의 크기를 지정하여 최소화할 수 있습니다.

레이아웃 변경을 일으킬 수 있는 삽입을 로드하는 데 스크립트 구성요소를 사용할 수 있습니다. Google은 CLS를 줄이는 데 도움이 되는 구성 옵션을 제공하기 위해 이를 보강하는 방안을 고려하고 있습니다. 이는 스크립트 구성요소 내에서 또는 컴패니언 구성요소로 사용할 수 있습니다.

래퍼 구성요소

Google 애널리틱스나 Google 태그 관리자 (GTM)와 같이 널리 사용되는 서드 파티 스크립트를 포함하기 위한 구문 및 로드 전략은 일반적으로 수정되어 있습니다. 이는 각 유형의 스크립트에 대한 개별 래퍼 구성요소에 캡슐화될 수 있습니다. 개발자는 최소 애플리케이션 관련 속성 (예: 추적 ID)만 사용할 수 있습니다. Wrapper 구성요소는 다음과 같은 이점을 제공합니다.

  1. 많이 사용되는 스크립트 태그를 보다 쉽게 포함할 수 있습니다.
  2. 프레임워크가 내부적으로 가장 최적의 전략을 사용하도록 보장

결론

서드 파티 스크립트는 일반적으로 소비 웹사이트의 특정 기능을 포함하기 위해 만들어집니다. 중요하지 않은 스크립트의 영향을 줄이려면 Next.js 스크립트 구성요소가 기본적으로 수행하는 작업을 연기하는 것이 좋습니다. 개발자는 포함된 스크립트가 beforeInteractive 전략을 명시적으로 적용하지 않는 한 중요한 기능을 지연시키지 않을 것임을 확인할 수 있습니다. Next.js 스크립트 구성요소와 마찬가지로 프레임워크 개발자는 다른 프레임워크에서 이러한 기능을 빌드할 수도 있습니다. Google은 Nuxt.js 팀과 유사한 구성요소를 도입하는 방안을 적극적으로 모색하고 있습니다. 또한 의견을 바탕으로 스크립트 구성요소를 더욱 개선하여 추가 사용 사례를 지원할 수 있기를 바랍니다.

감사의 말

이 게시물에 대한 의견을 주신 Kara Erickson, Janicklas Ralph, Katie Hempenius, Philip Walton, Jeremy Wagner, Addy Osmani에게 감사드립니다.