더욱 쉬워진 웹 성능 - Google I/O 2018 에디션

Google IO 2018에서 Google은 웹 성능을 보다 쉽게 개선할 수 있는 도구, 라이브러리 및 최적화 기술을 요약한 내용을 소개했습니다. 여기서는 The Oodles Theater 앱을 사용하는 방법을 설명합니다. 또한 예측 로드 실험과 새로운 Guess.js 이니셔티브에 대해서도 이야기합니다.

Addy Osmani
Addy Osmani
Ewa Gasperowicz

지난 한 해 동안 우리는 웹을 더 빠르고 효율적으로 만드는 방법을 찾기 위해 많은 노력을 기울였습니다. 이를 통해 이 문서에서 공유하고자 하는 새로운 도구, 접근 방식, 라이브러리를 개발했습니다. 첫 번째 부분에서는 Oodles Theater 앱을 개발할 때 실제로 사용한 몇 가지 최적화 기법을 보여줍니다. 두 번째 부분에서는 예측 로드 실험과 새로운 Guess.js 이니셔티브에 대해 설명합니다.

성능의 필요성

인터넷은 해마다 점점 더 무거워지고 있습니다. 웹 상태를 확인하면 모바일에서 페이지 중앙값의 가중치가 약 1.5MB이며 대부분은 자바스크립트와 이미지입니다.

네트워크 지연 시간, CPU 제한, 렌더링 차단 패턴, 불필요한 서드 파티 코드와 같은 기타 요인과 함께 웹사이트 규모가 커지면서 성능 문제가 더욱 복잡해졌습니다.

대부분의 사용자는 속도가 자신이 필요로 하는 UX 계층 구조의 최상위에 있다고 평가합니다. 페이지 로드가 완료될 때까지는 많은 작업을 할 수 없으므로 그리 놀랍지는 않습니다. 페이지에서 가치를 도출할 수 없으며 페이지의 미적 요소도 감상할 수 없습니다.

UX 계층 구조 피라미드
그림 1. 사용자에게 속도가 얼마나 중요한가요? (Speed Matters, 3권)

성능이 사용자에게 중요하다는 것도 알고 있지만 최적화가 필요한 부분을 찾는 비밀처럼 느껴질 수도 있습니다. 다행히 도움이 될 수 있는 도구가 있습니다.

Lighthouse - 성능 워크플로의 기반

Lighthouse는 Chrome DevTools의 일부로, 웹사이트를 감사하고 개선 방법에 관한 힌트를 제공합니다.

최근 Google은 일상적인 개발 워크플로에 매우 유용한 여러 가지 새로운 성능 감사를 출시했습니다.

새로운 Lighthouse 감사
그림 2. 새 Lighthouse 감사

실제 예를 통해 Oodles Theater 앱을 활용하는 방법을 살펴보겠습니다. Oodles Theater 앱은 짧은 데모 웹 앱으로서 인기 있는 Google 기념일 로고를 사용해 보고 게임도 한두 개 플레이할 수 있습니다.

앱을 빌드하는 동안 우리는 앱이 최대한 성능을 발휘하는지 확인하고 싶었습니다. Lighthouse 보고서부터 최적화가 시작되었습니다.

Oodles 앱의 Lighthouse 보고서
그림 3. Oodles 앱의 Lighthouse 보고서

Lighthouse 보고서에서 볼 수 있듯이 앱의 초기 성능은 매우 열악했습니다. 3G 네트워크에서 사용자는 의미 있는 첫 페인트가 나타나거나 앱이 상호작용하기까지 15초를 기다려야 했습니다. Lighthouse는 우리 사이트의 수많은 문제를 강조했으며, 전반적인 성능 점수 23도 정확히 반영되었습니다.

페이지 무게는 약 3.4MB였으며, 불필요한 부분을 줄였습니다.

이로 인해 첫 번째 성능 문제가 시작되었습니다. 전체 환경에 영향을 미치지 않고 쉽게 삭제할 수 있는 항목을 찾는 것입니다.

실적 최적화 기회

불필요한 리소스 삭제

공백과 주석은 안전하게 삭제할 수 있습니다.

축소를 통한 이점
그림 4. 자바스크립트 및 CSS 축소 및 압축

Lighthouse는 축소되지 않은 CSS 및 JavaScript 감사에서 이 기회를 강조합니다. 저희는 빌드 프로세스에 webpack을 사용하고 있었으므로, 축소를 위해 Uglify JS 플러그인을 사용하기만 하면 됩니다.

축소는 일반적인 작업이므로 사용하는 빌드 프로세스에 즉시 사용할 수 있는 솔루션을 찾을 수 있어야 합니다.

이 영역에서 또 다른 유용한 감사는 텍스트 압축 사용 설정입니다. 압축되지 않은 파일을 보낼 이유가 없으며, 대부분의 CDN은 요즘 대부분 이를 지원합니다.

지금까지 Firebase 호스팅을 사용하여 코드를 호스팅하고 있고 Firebase가 기본적으로 gzipping을 사용 설정했기 때문에 합리적인 CDN에 코드를 호스팅하여 무료로 이를 얻을 수 있었습니다.

gzip이 매우 흔히 사용되는 압축 방법이지만 ZopfliBrotli와 같은 다른 메커니즘도 주목을 받고 있습니다. Brotli는 대부분의 브라우저에서 지원을 받으며, 바이너리를 사용하여 애셋을 서버에 전송하기 전에 사전 압축할 수 있습니다.

효율적인 캐시 정책 사용

다음 단계는 불필요한 리소스를 두 번 전송하지 않도록 하는 것이었습니다.

Lighthouse의 비효율적인 캐시 정책 감사를 통해 정확히 이 목표를 달성하기 위해 캐싱 전략을 최적화할 수 있음을 알게 되었습니다. Google은 서버에 max-ageexpiration 헤더를 설정하여 사용자가 재방문 시 이전에 다운로드한 리소스를 재사용할 수 있도록 했습니다.

가장 긴 시간 동안 최대한 많은 리소스를 안전하게 캐시하고 업데이트된 리소스의 효율적인 재검증을 위해 유효성 검사 토큰을 제공하는 것이 이상적입니다.

사용하지 않는 코드 삭제

지금까지 우리는 불필요한 다운로드에서 명백한 부분을 삭제했지만, 불분명한 부분은 어떻게 해야 할까요? 사용하지 않는 코드를 예로 들 수 있습니다.

DevTools의 코드 적용 범위
그림 5. 코드 적용 범위 확인

가끔 필요하지 않은 앱 코드를 앱 코드에 포함할 때도 있습니다. 특히 앱에서 오랜 시간 동안 작업하거나 팀 또는 종속 항목이 변경되며 간혹 분리된 라이브러리가 뒤처질 때가 자주 발생합니다. 바로 이런 일이 저희에게 일어난 일입니다.

처음에는 머티리얼 구성요소 라이브러리를 사용하여 빠르게 앱의 프로토타입을 제작하고 있었습니다. 당시 우리는 맞춤 디자인과 분위기로 전환하면서 이 라이브러리에 관해 완전히 잊고 있었죠. 다행히 코드 적용 범위 확인 덕분에 번들에서 코드를 다시 찾을 수 있었습니다.

DevTools에서 런타임과 애플리케이션 로드 시간에 대한 코드 적용 범위 통계를 확인할 수 있습니다. 아래 스크린샷에서 커다란 빨간색 줄무늬 두 개를 볼 수 있습니다. CSS의 95% 이상이 사용되지 않았고, 많은 양의 JavaScript도 사용되고 있습니다.

Lighthouse는 사용되지 않는 CSS 규칙 감사에서도 이 문제를 발견했습니다. 400KB 이상을 절약할 수 있었습니다. 그래서 코드로 돌아와 이 라이브러리의 JavaScript 및 CSS 부분을 모두 삭제했습니다.

MVC 어댑터를 드롭하면 스타일이 10KB로 떨어집니다.
그림 6. MVC 어댑터를 드롭하면 스타일이 10KB로 떨어집니다.

이로 인해 CSS 번들이 20배 줄었습니다. 이는 두 줄 길이의 작은 커밋에 매우 적합합니다.

물론 성능 점수가 올라갔고 상호작용 시작 시간도 훨씬 개선되었습니다.

하지만 이와 같은 변화에서는 측정항목과 점수만 확인하는 것으로는 충분하지 않습니다. 실제 코드를 삭제하는 것은 리스크가 없으므로 항상 잠재적인 회귀에 주의해야 합니다.

코드가 사용되지 않는 비율은 95%인데, 이 5% 의 비율도 아직 있습니다. 구성 요소 중 하나가 여전히 낙서 슬라이더의 작은 화살표인 해당 라이브러리의 스타일을 사용하고 있었던 것 같습니다. 하지만 너무 작았기 때문에 이 스타일을 버튼에 수동으로 다시 통합할 수 있었습니다.

라이브러리가 누락되어 버튼이 손상됨
그림 7. 구성요소 1개가 여전히 삭제된 라이브러리를 사용 중이었음

따라서 코드를 삭제하는 경우 잠재적인 시각적 회귀를 방지하는 데 도움이 되는 적절한 테스트 워크플로가 있는지 확인하세요.

방대한 네트워크 페이로드 방지

Google에서는 리소스의 크기가 클 경우 웹페이지 로드 속도가 느려질 수 있습니다. 사용자에게 비용이 들고 데이터 요금제에 큰 영향을 미칠 수 있으므로 이 점에 유의해야 합니다.

Lighthouse는 방대한 네트워크 페이로드 감사를 통해 일부 네트워크 페이로드에 문제가 있음을 감지할 수 있었습니다.

방대한 네트워크 페이로드 탐지
그림 8. 대규모 네트워크 페이로드 감지

여기에서 3MB가 넘는 코드가 배포되고 있는 것을 확인할 수 있었습니다. 이는 특히 모바일에서 상당한 양입니다.

Lighthouse는 이 목록의 맨 위에 압축되지 않은 코드가 2MB인 JavaScript 공급업체 번들이 있음을 강조했습니다. 이 역시 웹팩에서 강조한 문제입니다.

말처럼 가장 빠른 요청은 이루어지지 않는 요청입니다.

사용자에게 제공하려는 모든 애셋의 가치를 측정하고 해당 애셋의 실적을 측정한 후 초기 경험에서 실제로 제공할 가치가 있는지 확인하는 것이 이상적입니다. 이러한 애셋은 유휴 시간에 지연, 지연 로드 또는 처리될 수 있기 때문입니다.

여기서는 많은 JavaScript 번들을 다루고 있기 때문에 다행히도 JavaScript 커뮤니티에 풍부한 JavaScript 번들 감사 도구가 있습니다.

JavaScript 번들 감사
그림 9. JavaScript 번들 감사

먼저 Webpack 번들 분석기에서 파싱된 JavaScript의 1.6MB인 유니코드라는 종속 항목이 포함되어 있음을 알 수 있었습니다.

그런 다음 편집기로 이동하여 시각적 코드용 비용 플러그인 가져오기를 사용하여 가져온 모든 모듈의 비용을 시각화할 수 있었습니다. 이를 통해 이 모듈을 참조하는 코드가 포함된 구성요소를 찾을 수 있었습니다.

그런 다음 다른 도구인 BundlePhobia로 전환했습니다. 이 도구를 사용하면 NPM 패키지의 이름을 입력하면 축소 및 gzip 패키지의 예상 크기를 실제로 확인할 수 있습니다. 사용 중이던 슬러그 모듈의 대안이 2.2KB에 불과하여 좋은 대안을 발견하여 이를 상향 조정했습니다.

이는 실적에 큰 영향을 미쳤습니다. 이러한 변화와 자바스크립트 번들 크기를 줄일 수 있는 다른 기회를 발견하기 전까지 Google은 2.1MB의 코드를 절약했습니다.

이러한 번들의 gzip 및 축소된 크기를 고려한 결과 전반적으로 65% 의 개선이 이루어졌습니다. 그리고 저희는 이러한 과정이 정말로 가치 있는 일이라는 것을 알게 되었습니다.

따라서 일반적으로 사이트와 앱에서 불필요한 다운로드를 제거하는 것이 좋습니다. 애셋 인벤토리를 작성하고 성능에 미치는 영향을 측정하면 큰 차이를 만들 수 있으므로 애셋을 공정하게 정기적으로 감사해야 합니다.

코드 분할로 자바스크립트 부팅 시간 단축

네트워크 페이로드가 커지면 앱에 큰 영향을 미칠 수 있지만 정말 큰 영향을 미칠 수 있는 또 다른 것이 있습니다. 바로 JavaScript입니다.

JavaScript는 가장 비싼 애셋입니다. 모바일에서 대량의 JavaScript 번들을 전송하는 경우 사용자가 사용자 인터페이스 구성요소와 상호작용할 수 있는 시간이 지연될 수 있습니다. 즉, 실제로 의미 있는 일이 발생하지 않고 UI를 탭할 수 있습니다. 따라서 JavaScript에 비용이 많이 드는 이유를 이해하는 것이 중요합니다.

브라우저가 자바스크립트를 처리하는 방식입니다.

JavaScript 처리
그림 10. JavaScript 처리

먼저 스크립트를 다운로드해야 합니다. 그런 다음 코드를 파싱하고 컴파일하여 실행해야 하는 JavaScript 엔진이 있습니다.

이제 이러한 단계는 데스크톱 컴퓨터나 노트북, 심지어 고급형 휴대전화와 같은 고급형 기기에서는 많은 시간이 걸리지 않습니다. 하지만 휴대전화의 중앙값에서는 이 과정이 5~10배 더 오래 걸릴 수 있습니다. 이로 인해 상호작용이 지연되므로 이 문제를 줄이는 것이 중요합니다.

앱에서 이러한 문제를 발견할 수 있도록 Lighthouse에 새로운 JavaScript 부팅 시간 감사가 도입되었습니다.

자바스크립트 부팅 시간
그림 11. JavaScript 부팅 시간 감사

Oodle 앱의 경우 JavaScript 부팅에 1.8초가 소요된다고 합니다. 모든 경로와 구성요소를 하나의 모놀리식 JavaScript 번들로 정적으로 가져오는 것이었습니다.

이 문제를 해결하기 위한 한 가지 기술은 코드 분할을 사용하는 것입니다.

피자와 비슷한 코드 분할

코드 분할은 사용자에게 전체 피자 분량의 JavaScript를 제공하는 것이 아니라, 사용자가 필요할 때 한 번에 한 조각만 제공한다면 어떻게 될까요?

코드 분할은 경로 수준 또는 구성요소 수준에서 적용할 수 있습니다. React 및 React Loadable, Vue.js, Angular, Polymer, Preact 및 기타 여러 라이브러리와 잘 호환됩니다.

코드 분할을 애플리케이션에 통합하고 정적 가져오기에서 동적 가져오기로 전환하여 필요할 때 코드를 비동기식으로 지연 로드할 수 있도록 했습니다.

동적 가져오기를 사용한 코드 분할
그림 13. 동적 가져오기를 사용한 코드 분할

이로 인해 번들의 크기가 줄어드는 동시에 자바스크립트 부팅 시간도 줄었습니다. 0.78초로 단축되어 앱 속도가 56% 빨라졌습니다.

일반적으로 자바스크립트 사용량이 많은 환경을 빌드하는 경우 필요한 코드만 사용자에게 전송해야 합니다.

코드 분할과 같은 개념을 활용하고 트리 쉐이킹과 같은 아이디어를 살펴보며 webpack-libs-optimizations 저장소에서 webpack을 사용하는 경우 라이브러리 크기를 줄이는 방법에 관한 아이디어를 확인하세요.

이미지 최적화

이미지 로드 성능 농담

Oodle 앱에서는 많은 이미지를 사용합니다. 안타깝게도 Lighthouse는 우리보다 훨씬 열정적이었지만 실제로 Google은 3건의 이미지 관련 감사를 모두 통과하지 못했습니다.

이미지를 최적화하는 것을 잊었고, 이미지의 크기를 올바르게 조정하지 않았으며, 다른 이미지 형식을 사용하여 이점을 얻을 수도 있었습니다.

이미지 감사
그림 14. Lighthouse 이미지 감사

이미지 최적화부터 시작했습니다.

일회성 최적화를 위해 ImageOptim 또는 XNConvert와 같은 시각적 도구를 사용할 수 있습니다.

보다 자동화된 접근 방식은 imagemin과 같은 라이브러리를 사용하여 빌드 프로세스에 이미지 최적화 단계를 추가하는 것입니다.

이렇게 하면 이후에 추가되는 이미지가 자동으로 최적화됩니다. Akamai와 같은 일부 CDN 또는 Cloudinary, Fastly, Uploadcare와 같은 타사 솔루션은 포괄적인 이미지 최적화 솔루션을 제공하므로 이러한 서비스에서 이미지를 간단하게 호스팅할 수도 있습니다.

비용 또는 지연 시간 문제로 인해 이 작업을 진행하지 않으려는 경우 ThumborImageflow와 같은 프로젝트에서 자체 호스팅 대안을 사용할 수 있습니다.

최적화 전후
그림 15. 최적화 전과 후

webpack에서 배경 PNG가 큰 것으로 플래그가 지정되었습니다. 표시 영역에 맞게 크기를 올바르게 조정하고 ImageOptim을 통해 실행한 후에는 100KB로 줄었습니다.

사이트의 여러 이미지에 이 과정을 반복함으로써 전체 페이지 크기를 현저하게 줄일 수 있었습니다.

애니메이션 콘텐츠에 올바른 형식 사용

GIF는 가격이 매우 비쌀 수 있습니다. 놀랍게도, GIF 형식은 애초에 애니메이션 플랫폼으로 의도되지 않았습니다. 따라서 더 적합한 동영상 형식으로 전환하면 파일 크기를 크게 절약할 수 있습니다.

Oodle 앱에서는 GIF를 홈페이지의 인트로 시퀀스로 사용했습니다. Lighthouse에 따르면 보다 효율적인 동영상 형식으로 전환하면 7MB 이상을 절약할 수 있습니다. 클립의 무게는 약 7.3MB로 어떤 합리적인 웹사이트에 비해 너무 많았기 때문에 보다 폭넓은 브라우저 지원을 위해 mp4와 WebM이라는 두 가지 소스 파일이 있는 동영상 요소로 변환했습니다.

애니메이션 GIF를 동영상으로 대체
그림 16. 애니메이션 GIF를 동영상으로 대체

FFmpeg 도구를 사용해 애니메이션 GIF를 mp4 파일로 변환했습니다. WebM 형식은 훨씬 더 큰 절감 효과를 제공합니다. ImageOptim API가 이러한 변환을 자동으로 수행할 수 있습니다.

ffmpeg -i animation.gif -b:v 0 -crf 40 -vf scale=600:-1 video.mp4

이러한 전환 덕분에 전체 무게의 80% 이상을 줄일 수 있었습니다. 이로 인해 약 1MB가 줄었습니다.

그래도 1mb는 특히 제한된 대역폭을 사용하는 사용자의 경우 유선을 아래로 밀어내는 큰 리소스입니다. 다행히 Effective Type API를 사용하여 대역폭이 느리다는 것을 인식하고 대신 훨씬 더 작은 JPEG를 제공할 수 있습니다.

이 인터페이스는 유효한 왕복 시간과 다운 값을 사용하여 사용자가 사용 중인 네트워크 유형을 추정합니다. 이 함수는 단순히 문자열(느린 2G, 2G, 3G, 4G)을 반환합니다. 따라서 이 값에 따라 사용자가 4G 미만을 사용 중인 경우 동영상 요소를 이미지로 대체할 수 있습니다.

if (navigator.connection.effectiveType) { ... }

이 경우 환경이 약간 사라지지만 적어도 연결 속도가 느릴 때도 사이트를 사용할 수 있습니다.

화면 밖 이미지 지연 로드

캐러셀, 슬라이더 또는 매우 긴 페이지의 경우 사용자가 페이지에서 바로 이미지를 볼 수 없더라도 이미지가 로드되는 경우가 많습니다.

Lighthouse는 화면 밖 이미지 감사에 이 동작을 표시하며, DevTools의 네트워크 패널에서 직접 확인할 수도 있습니다. 페이지에 몇 개만 보이는데 많은 이미지가 수신되는 경우 대신 지연 로드를 고려해 볼 수 있습니다.

지연 로드는 아직 브라우저에서 기본적으로 지원되지 않으므로 자바스크립트를 사용하여 이 기능을 추가해야 합니다. Lazysizes 라이브러리를 사용하여 Oodle 커버에 지연 로드 동작을 추가했습니다.

<!-- Import library -->
import lazysizes from 'lazysizes'  <!-- or -->
<script src="lazysizes.min.js"></script>

<!-- Use it -->

<img data-src="image.jpg" class="lazyload"/>
<img class="lazyload"
    data-sizes="auto"
    data-src="image2.jpg"
    data-srcset="image1.jpg 300w,
    image2.jpg 600w,
    image3.jpg 900w"/>

Lazysizes는 요소의 가시성 변경을 추적할 뿐만 아니라 최적의 사용자 환경을 위해 뷰 근처에 있는 요소를 사전에 미리 가져오므로 스마트합니다. 또한 IntersectionObserver 통합을 선택사항으로 제공하여 가시성을 매우 효율적으로 조회할 수 있습니다.

이 변경 이후에는 필요에 따라 이미지를 가져옵니다. 이 주제에 대해 더 자세히 알아보려면 매우 유용하고 포괄적인 리소스인 images.guide를 확인하세요.

브라우저가 중요한 리소스를 조기에 제공할 수 있도록 지원

브라우저에 전송되는 모든 바이트의 중요도가 동일한 것은 아니며, 브라우저도 이러한 사실을 인지하고 있습니다. 많은 브라우저에는 먼저 가져올 항목을 결정하기 위한 휴리스틱이 있습니다. 따라서 이미지나 스크립트보다 먼저 CSS를 가져오는 경우도 있습니다.

페이지의 작성자로서 우리에게 정말로 중요한 것이 무엇인지 브라우저에 알리는 것이 유용할 수 있습니다. 다행히 지난 몇 년 동안 브라우저 공급업체는 이러한 문제를 해결하는 데 도움이 되는 리소스 힌트, link rel=preconnect, preload, prefetch 등의 다양한 기능을 추가했습니다.

웹 플랫폼에 도입된 이러한 기능은 브라우저가 적시에 적절한 항목을 가져오는 데 도움이 되며, 대신 스크립트를 사용하여 실행되는 일부 맞춤 로드 로직 기반 접근 방식보다 조금 더 효율적일 수 있습니다.

Lighthouse가 이러한 기능 중 일부를 효과적으로 사용하는 방법을 실제로 어떻게 안내하는지 살펴보겠습니다.

Lighthouse에서 가장 먼저 해야 할 일은 한 출발지로 가는 값비싼 왕복을 여러 번 피하는 것입니다.

출발지로 가는 고비용의 왕복 이동을 여러 번 방지
그림 17. 특정 출발지로 비용이 많이 드는 여러 번의 왕복 방지

Oodle 앱의 경우 실제로 Google Fonts를 많이 사용하고 있습니다. 페이지에 Google 글꼴 스타일시트를 배치할 때마다 최대 2개의 하위 도메인이 연결됩니다. Lighthouse에서 말하는 내용은 이 연결을 준비할 수 있다면 초기 연결 시간에서 최대 300밀리초까지 절약할 수 있다는 것입니다.

링크 관련 사전 연결을 활용하면 이러한 연결 지연 시간을 효과적으로 마스크할 수 있습니다.

특히 글꼴 얼굴 CSS가 googleapis.com에서 호스팅되고 글꼴 리소스가 Gstatic에서 호스팅되는 Google Fonts와 같은 글꼴의 경우 큰 영향을 미칠 수 있습니다. 그래서 이 최적화를 적용하여 수백 밀리초를 단축했습니다.

그 다음으로 Lighthouse는 주요 요청을 미리 로드한다고 제안합니다.

주요 요청 미리 로드
그림 18. 주요 요청 미리 로드

<link rel=preload>는 매우 강력합니다. 현재 탐색의 일부로 리소스가 필요하다고 브라우저에 알리고 최대한 빨리 브라우저에서 리소스를 가져오려고 합니다.

이제 두 개의 웹 글꼴로 로드하기 때문에 Lighthouse는 주요 웹 글꼴 리소스를 미리 로드해야 한다고 알려줍니다.

웹 글꼴로 미리 로드하는 것은 다음과 같습니다. rel=preload를 지정하고 글꼴 유형과 함께 as를 전달한 다음 로드하려는 글꼴 유형(예: woff2)을 지정합니다.

이것이 페이지에 미칠 수 있는 영향은 매우 심각합니다.

리소스 미리 로드의 영향
그림 19. 리소스 미리 로드의 영향

일반적으로 링크 rel preload를 사용하지 않고 웹 글꼴이 페이지에 중요한 경우 브라우저는 먼저 HTML을 가져오고 CSS를 파싱해야 하며 나중에 훨씬 늦게 브라우저에서 웹 글꼴을 가져옵니다.

링크 rel 미리 로드를 사용하면 브라우저가 HTML을 파싱하는 즉시 웹 글꼴을 훨씬 일찍 가져올 수 있습니다. 저희 앱의 경우에는 웹 글꼴을 사용하여 텍스트를 렌더링하는 데 걸리는 시간을 1초도 줄일 수 있었습니다.

Google Fonts를 사용하여 글꼴을 미리 로드하려고 한다면 그렇게 간단하지 않습니다. 한 가지 주의사항이 있습니다.

스타일시트의 글꼴에 지정하는 Google 글꼴 URL은 글꼴팀에서 상당히 정기적으로 업데이트하는 것입니다. 이러한 URL은 만료되거나 정기적으로 업데이트될 수 있으므로 글꼴 로드 환경을 완벽하게 제어하려는 경우 웹 글꼴을 자체 호스팅하는 것이 좋습니다. 이 방법은 link rel preload와 같은 항목에 액세스할 수 있으므로 유용합니다

이 경우에는 Google 웹 글꼴 도우미 도구가 일부 웹 글꼴을 오프라인에서 설정하고 로컬에서 설정하는 데 매우 유용하므로 이 도구를 확인해 보세요.

웹 글꼴을 중요한 리소스의 일부로 사용하든 자바스크립트든 사용하든 가능한 한 빨리 브라우저에서 중요한 리소스를 제공할 수 있도록 하세요.

실험용: 우선순위 힌트

오늘은 여러분께 특별한 소식을 전해 드리고자 합니다. 리소스 힌트 및 미리 로드와 같은 기능 외에도 우선순위 힌트라고 부르는 새로운 실험용 브라우저 기능을 개발 중입니다.

처음에 표시되는 콘텐츠의 우선순위 설정
그림 20. 우선순위 힌트

리소스의 중요도를 브라우저에 알려줄 수 있는 새로운 기능입니다. 낮음, 높음 또는 자동 값으로 새 속성 중요도를 노출합니다.

이를 통해 중요하지 않은 스타일, 이미지 또는 가져오기 API 호출과 같이 덜 중요한 리소스의 우선순위를 낮춰 경합을 줄일 수 있습니다. 또한 히어로 이미지와 같이 중요한 항목의 우선순위를 높일 수 있습니다

Oodle 앱의 경우, 이는 실제로 최적화할 수 있는 한 가지 실용적인 단계로 이어졌습니다.

처음에 표시되는 콘텐츠의 우선순위 설정
그림 21. 처음에 표시되는 콘텐츠의 우선순위 설정

이미지에 지연 로드를 추가하기 전에는 브라우저가 하는 작업이었습니다. 모든 기념일 로고와 함께 이 이미지 캐러셀이 있었고 브라우저는 캐러셀 맨 처음에 모든 이미지를 높은 우선순위로 가져오고 있었습니다. 안타깝게도 사용자에게 가장 중요한 것은 캐러셀 중간에 있는 이미지였습니다. 그래서 우리는 배경 이미지의 중요도를 매우 낮게, 전경 이미지의 중요도를 매우 높게 설정했습니다. 그리고 이 결과는 느린 3G를 사용할 때 2초 동안 영향을 미치며 이러한 이미지를 얼마나 빠르게 가져오고 렌더링할 수 있는지 확인했습니다. 좋았어요.

몇 주 내에 이 기능을 Canary에 제공할 예정이니 계속 지켜봐 주세요.

웹 글꼴 로드 전략 수립

서체는 좋은 디자인의 기본입니다. 웹 글꼴을 사용하는 경우 이상적으로 텍스트의 렌더링을 차단하지 않고 보이지 않는 텍스트를 표시하고 싶지 않습니다.

이제 Lighthouse에서 웹 글꼴 로드 중에 표시되지 않는 텍스트 방지 감사를 통해 이 문제를 강조표시합니다.

웹 글꼴이 로드되는 동안 보이지 않는 텍스트 피하기
그림 22. 웹 글꼴을 로드하는 동안 표시되지 않는 텍스트 방지

글꼴 블록을 사용하여 웹 글꼴을 로드하면 해당 웹 글꼴을 가져오는 데 시간이 오래 걸리면 브라우저에서 무엇을 할지 결정하게 됩니다. 일부 브라우저는 시스템 글꼴로 대체하기 전에 최대 3초 동안 대기하다가 다운로드가 완료되면 글꼴로 바꿉니다.

보이지 않는 텍스트를 피하려고 하므로 웹 글꼴이 너무 오래 걸렸다면 이번 주의 클래식 기념일 로고도 볼 수 없었을 것입니다. 다행히 font-display라는 새로운 기능을 사용하면 이 프로세스를 훨씬 더 세밀하게 제어할 수 있습니다.

    @font-face {
      font-family: 'Montserrat';
      font-style: normal;
      font-display: swap;
      font-weight: 400;
      src: local('Montserrat Regular'), local('Montserrat-Regular'),
          /* Chrome 26+, Opera 23+, Firefox 39+ */
          url('montserrat-v12-latin-regular.woff2') format('woff2'),
            /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
          url('montserrat-v12-latin-regular.woff') format('woff');
    }

글꼴 표시를 사용하면 웹 글꼴이 교체되는 데 걸리는 시간에 따라 웹 글꼴이 렌더링되거나 대체되는 방식을 결정할 수 있습니다.

여기서는 글꼴 디스플레이 전환을 사용합니다. 스왑은 글꼴에 0초의 차단 기간과 무한 스왑 기간을 제공합니다. 즉, 글꼴을 로드하는 데 시간이 걸리면 브라우저에서 대체 글꼴을 사용하여 아주 즉시 텍스트를 그립니다. 그리고 글꼴이 제공되면 변경됩니다.

이 앱의 경우 이 기능이 큰 이유는 초기에 의미 있는 텍스트를 표시하고 준비가 완료되면 웹 글꼴로 전환할 수 있었기 때문입니다.

글꼴 표시 결과
그림 23. 글꼴 표시 결과

일반적으로 대부분의 웹이 그렇듯이 웹 글꼴을 사용한다면 좋은 웹 글꼴 로드 전략을 마련하는 것이 좋습니다.

글꼴 로드 환경을 최적화하는 데 사용할 수 있는 웹 플랫폼 기능이 많이 있습니다. 또한 Zach 레더맨의 웹 글꼴 레시피 저장소도 확인해 보세요. 정말 유용한 기능이기 때문입니다.

렌더링 차단 스크립트 줄이기

다운로드 체인의 초기에 푸시할 수 있는 애플리케이션의 다른 부분이 있습니다. 이 부분은 조금 더 일찍 기본적인 사용자 환경을 제공합니다.

Lighthouse 타임라인 스트립에서는 모든 리소스가 로드되는 처음 몇 초 동안 사용자가 실제로 어떤 콘텐츠도 볼 수 없음을 알 수 있습니다.

렌더링 차단 스타일시트 기회 줄이기
그림 24. 렌더링 차단 스타일시트 기회 줄이기

외부 스타일시트를 다운로드하고 처리하면 렌더링 프로세스가 진전되지 않습니다.

몇 가지 스타일을 조금 더 일찍 제공하여 주요 렌더링 경로를 최적화해 볼 수 있습니다.

초기 렌더링을 담당하는 스타일을 추출하여 HTML에 인라인으로 추가하면 브라우저가 외부 스타일시트가 도착할 때까지 기다리지 않고 곧바로 렌더링할 수 있습니다.

여기서는 중요라는 NPM 모듈을 사용하여 빌드 단계 중에 index.html에 중요한 콘텐츠를 인라인으로 추가했습니다.

이 모듈에서 대부분의 까다로운 작업을 처리했지만 여러 경로에서 원활하게 작동하도록 하기가 여전히 약간 어려웠습니다.

주의하지 않거나 사이트 구조가 매우 복잡한 경우 처음부터 앱 셸 아키텍처를 계획하지 않았다면 이러한 유형의 패턴을 도입하기가 매우 어려울 수 있습니다.

따라서 초기에 성능을 고려하는 것이 중요합니다. 처음부터 성능을 고려하여 설계하지 않으면 나중에 작업할 때 문제가 발생할 가능성이 높습니다.

결국 위험 부담을 푸는 데 성공했고, 앱을 훨씬 일찍 제공하기 시작했기 때문에 첫 번째 의미 있는 페인트 시간을 크게 단축할 수 있었습니다.

결과

이는 우리가 사이트에 적용한 성능 최적화의 목록이었습니다. 결과를 살펴보겠습니다. 이는 최적화 전후에 3G 네트워크의 중형 휴대기기에서 앱이 로드되는 방식입니다.

Lighthouse 성능 점수는 23에서 91로 올랐습니다. 속도 측면에서 꽤 발전한 것입니다. 모든 변경사항은 Lighthouse 보고서를 지속적으로 확인하고 따른 결과입니다. Google에서 모든 개선사항을 기술적으로 어떻게 구현했는지 알아보려면 언제든지 Google 저장소, 특히 해당 PR에 관해 알아보세요.

예측 성능 - 데이터 기반 사용자 환경

Google은 머신러닝이 여러 영역에서 미래에 흥미로운 기회를 제시할 것이라고 생각합니다. 향후 더 많은 실험을 촉발할 것으로 기대하는 아이디어 중 하나는 실제 데이터가 Google에서 만드는 사용자 환경을 진정으로 이끌어 줄 수 있다는 것입니다.

오늘날 Google은 사용자가 원하거나 필요로 하는 것, 즉 미리 가져오거나 미리 로드하거나 미리 캐시할 가치가 있는 것에 대해 수많은 임의 결정을 내립니다. 올바른 추측이 있다면 소량의 리소스를 우선시할 수 있지만 전체 웹사이트로 확장하기란 정말 어렵습니다.

우리는 현재 최적화에 더 나은 정보를 제공할 수 있는 데이터를 보유하고 있습니다. Google 애널리틱스 Reporting API를 사용하면 사이트의 모든 URL에서 다음 최상위 페이지 및 종료 비율을 볼 수 있으므로 어떤 리소스의 우선순위를 정해야 하는지를 결정할 수 있습니다.

이를 적절한 확률 모델과 결합하면 콘텐츠를 과도하게 미리 가져옴으로써 사용자의 데이터가 낭비되는 것을 방지할 수 있습니다. 이 Google 애널리틱스 데이터를 활용하고 머신러닝과 마르코프 연쇄 또는 신경망과 같은 모델을 사용하여 이러한 모델을 구현할 수 있습니다.

웹 앱을 위한 데이터 기반 번들
그림 25. 웹 앱용 데이터 기반 번들

이러한 실험을 용이하게 하기 위해 Guess.js라는 새로운 이니셔티브를 발표합니다.

Guess.js
그림 26. Guess.js

Guess.js는 웹을 위한 데이터 기반 사용자 환경에 중점을 둔 프로젝트입니다. 이를 통해 웹 성능을 개선하고 그 이상의 가치를 얻기 위해 데이터를 사용하는 방법을 탐구하는 계기가 되기를 바랍니다. 모두 오픈소스이며 현재 GitHub에서 사용할 수 있습니다. 이 개발은 Minko Gechev, Gatsby의 Kyle Matthews, Katie Hempenius 외 다수가 오픈소스 커뮤니티와 협력하여 빌드했습니다.

Guess.js를 사용해 보고 의견을 알려주세요.

요약

점수와 측정항목은 웹 속도를 높이는 데 유용하지만 목표 자체가 아닌 수단일 뿐입니다.

이동 중에 페이지 로드 속도가 느려지는 문제를 경험해 봤습니다. 이제 사용자는 매우 빠르게 로드되는 더욱 만족도 높은 환경을 제공할 수 있게 되었습니다.

실적을 개선하는 것은 하나의 여정입니다. 작은 변화가 큰 결과로 이어질 수 있습니다. 적절한 최적화 도구를 사용하고 Lighthouse 보고서를 모니터링하면 사용자에게 더 우수하고 포용적인 환경을 제공할 수 있습니다.

특별히 Ward Peeters, Minko Gechev, Kyle Mathews, Katie Hempenius, Dom Farolino, Yoav Weiss, Susie Lu, Yusuke Utsunomiya, Tom Ankers, Lighthouse, Google Doodles에게 감사의 말씀을 전합니다.