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

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

Leena Sohoni
Leena Sohoni

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

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

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

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

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

렌더링을 지연시키는 리소스 제거 및 서드 파티 사용량 최소화를 위한 Lighthouse 감사

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

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

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

Aurora의 서드 파티 스크립트 중점사항

Aurora는 오픈소스 웹 프레임워크 및 도구와 공동작업을 통해 개발자가 성능, 접근성, 보안, 모바일 준비 상태와 같은 사용자 환경 측면을 개선하는 데 도움이 되는 강력한 기본값과 주관적인 도구를 제공합니다. 2021년에는 프레임워크 스택이 사용자 환경과 Core Web Vitals 측정항목을 개선할 수 있도록 지원하는 데 중점을 두었습니다.

프레임워크 성능을 개선하기 위한 목표를 달성하기 위한 가장 중요한 단계 중 하나는 Next.js에서 서드 파티 스크립트의 이상적인 로드 시퀀스를 연구하는 것이었습니다. Next.js와 같은 프레임워크는 개발자가 서드 파티를 포함한 리소스를 효율적으로 로드하는 데 도움이 되는 유용한 기본값과 기능을 제공할 수 있는 고유한 위치에 있습니다. Google에서는 광범위한 HTTP 보관 파일 및 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 스크립트 구성요소는 스크립트 시퀀싱을 위한 위의 메서드를 구현하고 개발자가 로드 전략을 정의할 수 있는 템플릿을 제공합니다. 적절한 전략이 지정되면 다른 중요한 리소스를 차단하지 않고 최적으로 로드됩니다.

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

// 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" />

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

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

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

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

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

개발자는 스크립트 구성요소를 사용하여 애플리케이션의 어느 위치에나 서드 파티 스크립트를 배치하여 서드 파티를 지연 로드하거나 중요한 스크립트의 경우 문서 수준에 배치할 수 있습니다. 즉, 스크립트 구성요소는 스크립트를 사용하는 구성요소와 함께 배치될 수 있습니다. 하이드라이션 후에는 사용된 전략에 따라 스크립트가 처음 렌더링된 문서의 헤드 또는 본문 하단에 삽입됩니다.

효과 측정

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

Next.js 커머스 앱의 서드 파티 스크립트

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

이전 이후
비동기식 Google 태그 관리자 두 스크립트 모두에 strategy = afterInteractive가 있는 스크립트 구성요소
비동기 또는 지연이 없는 트위터 팔로우 버튼
스크립트 2개가 있는 데모 1의 스크립트 및 스크립트 구성입니다.

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

LCP 개선을 보여주는 필름 스트립 비교

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

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

이전 이후
비동기식 Google 태그 관리자 4개의 스크립트 각각에 strategy = lazyonload가 있는 스크립트 구성요소
비동기식 트위터 팔로우 버튼
비동기 또는 지연이 없는 YouTube 구독 버튼
비동기 또는 지연 없이 LinkedIn 팔로우 버튼
스크립트 4개가 포함된 데모 2의 스크립트 및 스크립트 구성입니다.
스크립트 구성요소 유무와 관계없이 색인 페이지의 로드 진행률을 보여주는 동영상 스크립트 구성요소를 사용하면 FCP가 0.5초 개선됩니다.

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

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

afterInteractivelazyOnload의 전략 옵션은 렌더링 차단 스크립트를 효과적으로 제어할 수 있지만 스크립트 구성요소의 유용성을 높이는 다른 옵션도 모색하고 있습니다.

웹 작업자 사용

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

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

CLS 최소화

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

스크립트 구성요소는 레이아웃 이동을 일으킬 수 있는 삽입을 로드하는 데 사용될 수 있습니다. CLS를 줄이는 데 도움이 되는 구성 옵션을 제공하기 위해 이를 보완하는 방안을 고려하고 있습니다. 이는 스크립트 구성요소 자체 내에서 또는 호환 구성요소로 제공될 수 있습니다.

래퍼 구성요소

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

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

결론

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

감사의 말

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