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

Kara Erickson
Kara Erickson
Leena Sohoni
Leena Sohoni

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

배경

이미지는 웹 사용자 환경에서 일반적이고 중요한 구성요소로, 웹페이지의 99.9%가 하나 이상의 이미지를 요청합니다. 이미지는 페이지당 982KB의 중앙값을 차지하며 페이지 무게에 가장 큰 영향을 미칩니다.

이미지는 수와 크기가 증가하여 웹페이지의 성능을 저해하고 코어 웹 바이탈 측정항목에 영향을 줄 수 있습니다. 데스크톱 페이지의 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로 가져오기 위해 Angular 이미지 지시어 (NgOptimizedImage)가 출시되었습니다.

기회

Angular는 오늘날 개발자들이 사용하는 최고의 JavaScript 프레임워크 중 하나입니다. 모바일에서 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% 만 미리 로드 힌트를 사용합니다.

    이미지 지시어는 이미지가 우선순위로 표시될 때 두 가지 전선에서 작동합니다.

    • 이 코드는 이미지의 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. 기본 제공 오류 및 경고

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

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

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

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

    4. 이미지 밀도: srcset에 픽셀 밀도가 3x 이상인 이미지를 포함하려고 하면 지시어에서 오류가 발생합니다. 설명어가 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>는 모든 경로에서 (적어도 제공 시간에) 동일합니다. <head>preload 힌트를 추가하면 리소스가 필요하지 않은 경우에도 모든 경로에 대해 리소스가 미리 로드됩니다. 따라서 preload 힌트를 수동으로 추가하는 것은 권장하지 않습니다.

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

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

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

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

    지시어가 이미지 CDN의 사용을 강제하지는 않지만, 지시어 및 내장 로더와 함께 사용하는 것이 좋습니다. 올바른 구성 옵션이 사용되도록 합니다.

영향

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

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

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

슬라이드 비교: 네이티브 이미지 태그가 있는 웹사이트 1과 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 속성을 수동으로 제공해야 합니다. 향후 지시문을 통해 srcset 속성과 sizes 속성이 자동으로 생성될 수 있습니다.

  • 리소스 힌트 자동 삽입

    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을(를) 사용해 보고 의견을 남겨주세요.

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