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

Kara Erickson
Kara Erickson
Leena Sohoni
Leena Sohoni

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

배경

이미지는 웹 사용자 환경에서 일반적이고 중요한 구성요소이며 99.9%의 웹페이지에서 하나 이상의 이미지 요청을 생성합니다. 또한 이미지는 페이지 크기에 가장 큰 영향을 미치며 페이지당 평균 982KB를 차지합니다.

이미지의 수와 크기가 증가함에 따라 웹페이지의 성능이 저하되고 Core Web Vitals 측정항목에 영향을 줄 수 있습니다. 2021년 데스크톱 페이지의 79.4%에서 이미지가 최대 콘텐츠 렌더링 시간 (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년 웹 연감에 따르면 모바일 페이지의 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">
    

    image 디렉티브는 가장 인기 있는 이미지 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을 사용합니다.

image 디렉티브는 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: 모든 이미지에 image 디렉티브를 사용합니다. 또한 지시어에서 발생한 경고나 오류에 의해 직접 권장되는 최적화도 포함됩니다.

필름 스트립 비교: 네이티브 이미지 태그가 있는 웹사이트 1과 Angular 이미지 디렉티브가 있는 웹사이트 2

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

Land's End도 이러한 파트너 중 하나였습니다. 이 사이트는 실제 애플리케이션에서 볼 수 있는 결과에 대한 좋은 테스트 사례가 될 것으로 예상되었습니다.

이미지 디렉티브를 사용하기 전후에 QA 환경에서 Lighthouse 실험실 테스트를 실행했습니다. 데스크톱의 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을 사용해 보고 의견을 남겨 주세요.

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