Angular Image 지침으로 이미지 최적화

카라 에릭슨
카라 에릭슨
리나 소호니
리나 소호니

2022년 5월, Aurora 및 Angular팀은 Angular의 이미지 지침을 공동으로 수립하겠다고 발표했습니다. 이 지침은 최근 Angular v14.2의 일부로 개발자 프리뷰용으로 출시되었습니다. 이 게시물에서는 새 이미지 지시어인 NgOptimizedImage가 Angular에서 이미지 최적화를 어떻게 지원하는지 설명합니다.

배경

이미지는 웹 사용자 환경에서 널리 사용되고 중요한 구성요소로, 웹페이지의 99.9%가 하나 이상의 이미지를 요청합니다. 이미지는 페이지당 982킬로바이트의 중앙값을 차지할 만큼 페이지 크기를 결정하는 가장 중요한 요소이기도 합니다.

이미지는 이미지의 수와 크기가 커짐에 따라 웹페이지의 성능을 저하시키고 코어 웹 바이탈 측정항목에 영향을 미칠 수 있습니다. 데스크톱 페이지의 79.4%에서 이미지는 2021년 최대 콘텐츠 렌더링 시간 (LCP) 요소였습니다. 따라서 많은 사람이 최적화된 이미지를 추구하는 일이 끊임없는 노력이 되었습니다.

Aurora팀은 프레임워크의 힘을 활용하여 일반적인 개발자 과제에 대한 기본 솔루션을 제공할 수 있으리라 생각합니다. 이들이 이미지 최적화 공간에 처음 도전한 것은 Next.js 이미지 구성요소였습니다. 이들은 이미지 최적화의 개발자 환경 (DX)을 개선하면 프레임워크를 사용하는 더 많은 앱의 성능 향상으로 이어질 수 있는지를 판단할 수 있는 테스트 공간으로 이 구성요소를 고려했습니다.

Next.js 사용자 Leboncoin의 첫 번째 결과는 고무적이었습니다. Leboncoin은 next/image를 사용하기 시작한 후 LCP가 2.4초에서 1.7초로 크게 개선되었습니다. 이후 커뮤니티에서 next/image를 채택한 것이 LCP 기준점을 충족하는 Next.js 출처의 증가에 영향을 미쳤습니다. 곧 다른 프레임워크에도 유사한 기능에 대한 요청이 접수되었으며 그중 하나는 Angular입니다.

결과적으로 Aurora는 Angular 및 Nuxt와 협력하여 이러한 프레임워크용 이미지 구성요소의 프로토타입을 제작했습니다. Nuxt 이미지 구성요소는 작년에 출시되었습니다. 이제 Angular 이미지 지시문 (NgOptimizedImage)이 출시되어 이미지 최적화 기본값을 Angular로 변경합니다.

기회

Angular는 오늘날 개발자들이 사용하는 주요 자바스크립트 프레임워크 중 하나입니다. 이 API는 모바일의 HTTPArchive에서 크롤링한 출처의 5만 개 이상에 사용되고 있으며 NPM에서는 매주 약 300만 회의 다운로드를 기록하고 있습니다.

지난 1년간 Angular 웹사이트의 LCP

Core Web Vitals 점수를 보면 '양호'한 LCP 기준점을 충족하는 Angular 출처의 비율은 여전히 개선이 필요합니다. 2022년 6월, Angular 사이트의 18.74% 만이 모바일에서 양호한 LCP를 보였습니다. 이미지는 모바일 및 데스크톱 웹페이지의 70% 이상에서 LCP 요소이므로 최적화되지 않은 LCP 이미지가 Angular 웹사이트에서 LCP 저하의 주요 원인 중 하나일 수 있습니다.

Angular 이미지 지시어는 이러한 수치를 개선하는 데 도움이 되도록 설계되었습니다.

NgOptimizedImage 지시어 MVP

Angular 이미지 지시어의 MVP는 Aurora가 지금까지 빌드한 이미지 구성요소로부터 얻은 교훈을 바탕으로 하는 동시에 디자인을 Angular의 클라이언트 측 렌더링 환경에 맞게 조정했습니다. 표준 이미지 최적화 문제의 대부분은 다음 중 하나를 통해 해결되었습니다.

  • 강력한 기본값 제공
  • 권장사항 준수를 위해 오류 또는 경고 발생

디자인의 주요 특징은 다음과 같습니다.

  1. 지능형 지연 로드

    페이지 로드 시 사용자에게 표시되지 않는 이미지 (예: 스크롤해야 볼 수 있는 이미지 또는 숨겨진 캐러셀 이미지)는 지연 로드하는 것이 좋습니다. 지연 로드를 사용하면 브라우저 리소스가 다른 중요한 텍스트, 미디어 또는 스크립트를 로드할 수 있습니다. 대부분의 이미지는 중요하지 않고 지연 로드되어야 하지만, 2021년에는 페이지의 7.8%만 네이티브 지연 로드를 사용했습니다.

    Angular 이미지 지시어는 기본적으로 중요하지 않은 이미지를 지연 로드하며 priority이라고 특별히 표시된 이미지만 즉시 로드합니다. 이렇게 하면 대부분의 이미지가 최적의 로드 동작을 보입니다.

  2. 중요 이미지의 우선순위 지정

    리소스 힌트 (예: preload 또는 preconnect)을 사용하여 중요한 이미지를 로드하는 데 우선순위를 두는 것이 권장사항입니다. 하지만 대부분의 앱에서는 이 기능을 사용하지 않습니다. 2021년 Web Almanac에 따르면 모바일 페이지의 12.7%만 사전 연결 힌트를 사용하며 모바일 페이지의 22.1% 만 미리 로드 힌트를 사용합니다.

    image 지시문은 이미지가 우선순위로 표시될 때 두 가지 면에서 작동합니다.

    • 이미지의 fetchpriority"high"로 설정하여 브라우저가 우선순위가 높은 이미지를 다운로드해야 한다는 사실을 인지할 수 있습니다.
    • 개발 모드에서 런타임 검사는 이미지의 출처에 해당하는 preconnect 리소스 힌트가 포함되었는지 확인합니다.

    개발 모드에서는 지시어가 PerformanceObserver API를 사용하여 LCP 이미지가 예상대로 priority로 표시되었는지도 확인합니다. priority로 표시되지 않으면 오류가 발생하여 개발자에게 LCP 이미지에 priority 속성을 추가하도록 지시합니다.

    궁극적으로 이러한 자동화와 적합성의 조합은 LCP 이미지가 preconnect 힌트와 fetchpriority 속성 값 high을 가지며 지연 로드되지 않도록 합니다.

  3. 많이 사용되는 이미지 도구에 최적화된 구성

    Angular 애플리케이션은 기본적으로 최적화 서비스를 제공하는 이미지 CDN을 사용하는 것이 좋습니다.

    이 지시어는 앱에서 CDN을 구성할 수 있는 특히 매력적인 개발자 환경 (DX)을 제공하여 이미지 CDN 사용을 권장하며, 구성에서 CDN 제공업체와 기본 URL을 정의할 수 있는 로더 API를 지원합니다. 구성이 완료되면 마크업에서 애셋 이름만 정의하면 됩니다. 예를 들면 다음과 같습니다.

    // in module providers:
    provideImgixLoader('https://mysite.net/assets/')
    
    // in markup
    <img ngSrc="image.png" >
    <img ngSrc="image2.png" >
    

    이는 다음 이미지 태그를 포함하는 것과 같으며 개발자가 모든 이미지에 포함해야 하는 마크업을 줄입니다.

    <img src="https://mysite.net/assets/image.png">
    <img src="https://mysite.net/assets/image2.png">
    

    이미지 지시문은 가장 인기 있는 이미지 CDN에 대한 최적의 구성을 갖춘 로더를 기본 제공합니다. 이 로더는 각 CDN에 권장되는 이미지 형식과 압축 설정이 사용되도록 이미지 URL의 형식을 자동으로 지정합니다.

  4. 기본 제공 오류 및 경고

    위의 기본 제공 최적화 외에도 지시문에는 개발자가 이미지 마크업의 권장사항을 따랐는지 확인하는 검사 기능이 내장되어 있습니다. image 지시문은 다음 검사를 수행합니다.

    1. 크기가 지정되지 않은 이미지: 이미지 마크업에 명시적인 너비와 높이를 정의하지 않은 경우 이미지 지시문에서 오류가 발생합니다. 크기가 지정되지 않은 이미지는 레이아웃 변경을 유발하여 페이지의 레이아웃 변경 횟수 (CLS) 측정항목에 영향을 미칠 수 있습니다. 이를 방지하기 위한 권장사항은 이미지에 widthheight 속성을 지정하는 것입니다.

    2. 가로세로 비율: 이미지 지시문은 HTML에 정의된 width:height의 가로세로 비율이 렌더링된 이미지의 실제 가로세로 비율과 비슷한 경우 개발자에게 이를 알리는 오류를 발생시킵니다. 이로 인해 화면에서 이미지가 왜곡되어 보일 수 있습니다. 이는 다음과 같은 경우에 발생할 수 있습니다.

      1. 실수로 잘못된 크기 (너비 또는 높이)를 정의했거나
      2. CSS에서 한 측정기준을 비율로 정의했지만 다른 측정기준은 정의하지 않은 경우 (예: 이미지가 두 크기 모두에서 확장되도록 하려면 width: 100%에서 height: auto가 필요함)
    3. 대형 이미지: 이미지에 srcset가 정의되어 있지 않고 기본 이미지가 렌더링된 이미지보다 훨씬 큰 경우 지시어에 srcsetsizes 속성 사용을 제안하는 경고가 표시됩니다.

    4. 이미지 밀도: 픽셀 밀도가 3x보다 큰 이미지를 srcset에 포함하려고 하면 지시문에서 오류가 발생합니다. 2x보다 높은 설명어는 일반적으로 고해상도 휴대기기에서 대용량 이미지를 다운로드하게 되는 의도하지 않은 결과가 발생하므로 권장되지 않습니다. 게다가 사람의 눈으로는 2배 이상의 차이를 실제로 알 수 없습니다.

챌린지

클라이언트 측 프레임워크 내에서 작동하도록 이미지 최적화 전략을 조정하는 것은 NgOptimizedImage를 설계할 때 주된 과제였습니다. Next.js의 기본 렌더링 환경은 서버 측 렌더링 (SSR) 또는 정적 사이트 생성 (SSG)이며, Angular에서는 클라이언트 측 렌더링 (CSR)입니다. Angular가 SSR 라이브러리(angular/Universal)를 지원하더라도 대부분의 Angular 앱(~60%)은 CSR을 사용합니다.

이미지 지시어는 CSR이 Angular 앱의 일반적인 사용 사례에 맞추도록 전적으로 제작되었습니다. 이로 인해 추가적인 제약이 발생했고, 팀은 CSR 앱에 대한 특정 최적화를 구축하는 방법을 다시 생각해야 했습니다.

발생한 몇 가지 문제는 다음과 같습니다.

  1. 리소스 힌트 지원

    중요한 애셋을 미리 로드하면 브라우저가 자산을 미리 발견하는 데 도움이 됩니다. 그러나 Angular 앱에 리소스 힌트를 포함하는 것은 다음과 같은 이유로 복잡합니다.

    수동 추가: 개발자가 preload 리소스 힌트를 수동으로 추가하기 어렵습니다. Angular는 전체 프로젝트 또는 웹사이트의 모든 경로에 대해 하나의 공유 index.html 파일을 사용합니다. 따라서 문서의 <head>는 모든 경로에 대해 동일합니다 (최소한 제공 시간). preload 힌트를 <head>에 추가하면 리소스가 필요하지 않은 경우에도 모든 경로에 대해 리소스가 미리 로드됩니다. 따라서 preload 힌트를 수동으로 추가하지 않는 것이 좋습니다.

    렌더링 중 자동 추가: 프레임워크를 활용하여 CSR 앱에서 렌더링하는 동안 문서 헤드에 미리 로드 힌트를 추가하는 것은 도움이 되지 않습니다. JavaScript가 다운로드되고 실행된 후에 렌더링이 발생하므로 <head>는 값을 갖기에는 너무 늦게 렌더링됩니다.

    지시어의 첫 번째 버전에서는 preconnect 힌트와 fetchpriority 힌트의 조합이 preload 대신 이미지의 우선순위를 지정합니다. 그러나 Aurora는 현재 Angular CLI 팀과 협력하여 빌드 시간에 리소스 힌트를 자동으로 삽입할 수 있도록 하고 있습니다. 조금만 기다려 주세요.

  2. 서버에서 이미지 크기 및 형식 최적화

    Angular 앱은 일반적으로 클라이언트 측에서 렌더링되므로 파일 시스템의 이미지는 요청 시 압축될 수 없으며 그대로 제공됩니다. 따라서 이미지 CDN을 사용하여 이미지를 압축하여 WebP와 같은 최신 형식 또는 주문형 AVIF로 변환하는 것이 좋습니다.

    지시어가 이미지 CDN 사용을 강제하지는 않지만, 지시어와 함께 사용하는 것이 좋습니다. 기본 제공되는 로더는 올바른 구성 옵션이 사용되도록 해줍니다.

영향

다음 데모는 Angular 이미지 지시어가 이미지 성능에 미칠 수 있는 차이를 보여줍니다. 두 웹사이트를 비교합니다.

웹사이트 1: Imgix CDN을 통해 제공되는 이미지와 함께 네이티브 <img> 요소를 사용합니다 (기본 구성 옵션 포함).

웹사이트 2: 모든 이미지에 이미지 지시어를 사용합니다. 또한 지시어에서 발생한 경고나 오류에 의해 직접적으로 권장되는 최적화도 포함되어 있습니다.

슬라이드 비교: 네이티브 이미지 태그가 있는 웹사이트 One과 Angular 이미지 지시어가 있는 웹사이트 2 비교

이 팀은 파트너와 협력하여 이미지 지침이 실제 엔터프라이즈 Angular 애플리케이션에 미치는 성능 영향을 검증했습니다.

이 파트너 중 하나가 Land's End입니다. 이 사이트는 실제 애플리케이션에서 확인할 수 있는 결과를 확인하기에 좋은 테스트 사례가 될 것으로 예상했습니다.

Lighthouse 실험실 테스트는 이미지 지시어를 사용하기 전과 후에 QA 환경에서 수행되었습니다. 데스크톱에서는 LCP 중앙값이 12.0초에서 3.0초로 감소하여 LCP가 75% 개선되었습니다. 모바일의 LCP 중앙값은 20.2초에서 12.0초 (40.6% 개선)로 감소했습니다.

향후 로드맵

이는 Angular 이미지 지시어를 위한 설계의 첫 번째 파트입니다. 향후 버전에서는 다음을 비롯한 다른 많은 기능을 제공할 예정입니다.

  • 반응형 이미지 지원 향상:

    NgOptimizedImage는 현재 srcset 사용을 지원하지만 srcsetsizes 속성을 각 이미지에 수동으로 제공해야 합니다. 앞으로는 지시어가 srcsetsizes 속성을 자동으로 생성할 수 있습니다.

  • 리소스 힌트 자동 삽입

    Angular CLI와 통합하여 중요한 LCP 이미지의 사전 연결 및 미리 로드 태그를 생성할 수도 있습니다.

  • Angular SSR 지원

    MVP 버전은 Angular CSR 제약 조건을 염두에 두고 설계되었지만, Angular SSR (Angular/Universal)을 위한 이미지 최적화 솔루션을 살펴보는 것도 중요합니다.

  • 개발자 환경 개선

    NgOptimizedImage를 사용하려면 각 이미지에 widthheight 속성을 지정해야 합니다. 그러나 각 이미지에 대해 이러한 속성을 지정하는 것은 일부 개발자에게는 번거로울 수 있습니다. 다음과 같이 다음번 버전에서 개발자 환경을 개선할 수 있습니다.

    1. 명시적인 너비/높이 정의가 필요하지 않은 추가 모드 (Next.js의 'fill' 이미지 레이아웃 옵션과 유사)를 지원합니다.
    2. CLI 통합을 사용하여 이미지의 실제 크기를 결정함으로써 로컬 이미지의 너비와 높이를 자동으로 설정합니다.

결론

Angular 이미지 지시문은 v14.2.0의 개발자 프리뷰 버전부터 단계적으로 개발자에게 제공됩니다. NgOptimizedImage을(를) 사용해 보고 의견을 남겨주세요.

도움을 주신 케이티 헴페니우스와 알렉스 캐슬에 특별한 감사의 말을 전합니다.