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

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

Leena Sohoni
Leena Sohoni

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

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

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

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

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

렌더링 차단 리소스를 제거하고 제3자 사용을 최소화하기 위한 Lighthouse 감사

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

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

  • 모바일과 데스크톱에서 평균적으로 웹사이트에서 스크립트를 포함한 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. preconnect 및 dns-prefetch를 사용하여 필수 출처에 대한 조기 연결을 설정합니다. 이렇게 하면 중요한 스크립트를 더 일찍 다운로드할 수 있습니다.

       <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://cdnjs.cloudflare.com/polyfill/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에 삽입되고 다른 자체 번들 JavaScript보다 먼저 실행되도록 합니다. 중요한 콘텐츠를 렌더링하는 데 필요한 동의 관리, 봇 감지 스크립트 또는 도우미 라이브러리가 이 전략에 적합한 후보입니다.

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

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

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

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

영향 측정

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

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

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

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

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

LCP에서의 즉흥성을 보여주는 필름 스트립 비교

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

서드 파티 스크립트는 아래와 같이 데모 블로그 앱에 추가되었습니다.

변경 전 변경 후
Google 태그 관리자(비동기) 4개의 스크립트 각각에 대해 layonload라는 전략이 있는 스크립트 구성요소
비동기를 사용하는 Twitter 팔로우 버튼
async 또는 defer가 없는 YouTube 구독 버튼
비동기 또는 지연 없이 LinkedIn 팔로우 버튼 사용
스크립트 4개가 포함된 데모 2의 스크립트 및 스크립트 구성요소 구성
스크립트 구성요소를 사용할 때와 사용하지 않을 때의 색인 페이지 로드 진행률을 보여주는 동영상 스크립트 구성요소를 사용하면 FCP가 0.5초 단축됩니다.

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

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

afterInteractivelazyOnload의 전략 옵션을 사용하면 렌더링 차단 스크립트를 세밀하게 제어할 수 있지만, 스크립트 구성요소의 유용성을 높일 수 있는 다른 옵션도 모색하고 있습니다.

웹 작업자 사용

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

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

CLS 최소화

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

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

래퍼 구성요소

Google 애널리틱스 또는 Google 태그 관리자 (GTM)와 같은 인기 있는 서드 파티 스크립트를 포함하기 위한 구문과 로드 전략은 보통 수정됩니다. 이는 각 스크립트 유형의 개별 래퍼 구성요소에 추가 캡슐화될 수 있습니다. 개발자는 최소한의 애플리케이션별 속성 (예: 추적 ID)만 사용할 수 있습니다. 래퍼 구성요소는 다음과 같은 방법으로 개발자에게 도움을 줍니다.

  1. 인기 있는 스크립트 태그를 더 쉽게 포함할 수 있습니다.
  2. 프레임워크가 내부에서 가장 최적의 전략을 사용하도록 합니다.

결론

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

감사의 말

이 게시물에 대한 의견을 제공해 주신 카라 에릭슨, 재니클라스 랄프, 케이티 헴페니우스, 필립 월튼, 제레미 와그너, 아디 오스마니님께 감사드립니다.