구글은 웹에서 사용자 경험을 측정하기 위한 지침으로 Web Vitals
를 만들었다.
Core Web Vitals
는 Web Vitals
의 하위 집합으로 loading, interactivity, visual stability를 측정하는 3가지 항목으로 구성되어있다. 이 항목들은 Largest Contentful Paint (LCP)
, First Input Delay (FID)
, Cumulative Layout Shift (CLS)
이다.
이 세가지 항목들에서 좋은 점수를 달성함으로 부드러운 사용자 경혐을 만들어 줄 수 있다.
Core Web Vitals
에서 좋지 않은 점수를 받는 것은 검색엔진 순위에도 영향을 미치고 이는 웹사이트 트래픽에도 영향을 미치므로 비즈니스에도 영향이 있다.
Core Web Vitals
를 측정 할 때, Good
, Needs Imporvement
, Poor
세가지 값이있다.
두가지 활용 방안
1. 각각의 항목에 최대한 좋은 점수를 달성하기. 하지만 만약 크고 의존성이 많은 웹사이트들은 이것이 쉽지 않을 것이다.
2. 업계의 경쟁업체를 벤치마킹. 타켓 키워드 순위에 올라와있는 다른 웹사이트와 경쟁한다.
LCP 항목은 페이지의 로딩 성능을 본다. 페이지에서 가장 큰 요소가 뷰포트 안에서 보여지는데 걸리는 시간을 측정한다. 커다란 블록, 비디오, 이미지가 될 수 있다.
DOM이 렌더링되며 페이지에서 가장 큰 요소는 바뀔 수 있다. LCP는 가장 큰 이미지, 요소가 화면에 보여지기 까지 측정을 멈추지 않는다.
LCP는 First Contentful Paint (FCP) 와는 다르다. FCP는 화면에 보여지는 첫번째 요소가 렌더링에 걸리는 시간을 측정한다.
FID 항목은 웹페이지와 인터렉션 할 때 유저 경험에 대한 인식이다. 큰 입력 지연으로 인해 사이트의 응답성에 불만이 생길 수 있다.
FID는 실제 유저 데이터가 필요하고 구글 라이트하우스 같은 것으로 측정 할 수 없다. 하지만 Total Blocking Time (TBT)
항목은 측정가능하고 이것은 상호작용에 영향을 미치는 문제를 캡쳐한다.
CLS는 사이트의 전체적인 레이아웃 안정성을 측정한다. 페이지가 로드되면서 레이아웃이 변경하는 경우 유저 에러와 혼란을 야기 할 수 있다.
CLS는 요소가 DOM에 의해 처음 렌더링 된 후 바뀌었을 때 발생한다. 각 요소의 개별 레이아웃 이동 점수는 예상되지 않은 이동이 발생하는 경우에만 CLS 에 측정된다. 새로운 요소가 DOM에 추가되거나 기존 요소가 크기를 바꾸었을 때, 만약 요소가 위치를 유지한다면 레이아웃 변경으로 측정되지 않는다.
구글 검색 엔진의 주요 목표는 현지화 및 맞춤법 오류를 고려하면서 최상의 결과를 제공하는 것이다. 구글은 항상 사용자에게 뛰어난 웹사이트 경험, 빠르고 원활한 결과 제공에 신경 쓴다.
모바일 디바이스의 웹페이지 속도는 2018년부터 순위 결정 요인이었다. 하지만 정확하게 어떤 성능 요인인지 아직 명확하지 않았었다. 2021년 구글은 특정 측정 항복과 분석 범위를 제공했다.
세가지 측정 항목은 값어치가 동등하지 않다. 라이트하우스에서는 Core Web Vitals들의 각각 다른 비중으로 할당하였다.
Core Web Vitals에 관한 대부분의 것은 SEO에 중점을 둔다. Core Web Vitals가 페이지 경험 및 검색 순위의 개선을 측정하고 추진하기 위해 만들어 졌지만 궁극적으로 혜택을 받게 된 것은 사용자이다. 페이지 경험을 향상 시키는데 많은 도움을 주었다.
라이트하우스는 시뮬레이션 환경을 사용하여 Core Web Vitals를 측정한다.
크롬 개발자 도구로도 라이트하우스를 실행시킬 수 있다.
라이트하우스는 제공된 URL에 대한 일련의 감사를 통해 작동한다. 감사를 기반으로 페이지 성능을 리포트로 만들어낸다. 만약 보완해야 할 점이 있다면 리포트가 인사이트를 줄 것이다.
일반 HTML을 사용하면 아래처럼 이미지를 추가했다.
<img src="large-image.jpg" alt="Large Image" />
이렇게 하면 수동적으로 몇가지를 최적화해야한다.
Next는 최적화를 즉시 처리 할 수 있는 Image 컴포넌트를 제공한다.
빌드타임에 이미지들을 최적화하지 않고 유저 request 타임에 최적화 한다. 많은 양의 이미지가 있어도 정적 사이트 생성 처럼 빌드타임이 증가하지 않는다.
기본적으로 lazy loaded 된다. 페이지 속도는 뷰포트 바깥 이미지들에 의해 영향받지 않는다. 뷰에 보일 때 로딩된다.
이미지들은 항상 CLS를 피하며 렌더링된다.
// Before
<img src="large-image.jpg" alt="Large Image" />
// After
<Image src="/large-image.jpg" alt="Large Image" width={3048} height={2024} />
Next.js는 ES2020 dynamic import()를 지원한다. First Input Delay (FID), Time to Interactive (TTI)를 개선 할 수 있다.
예시
<input
type="text"
placeholder="Country search..."
className={styles.input}
onChange={async e => {
const { value } = e.currentTarget
// Dynamically load libraries
const Fuse = (await import('fuse.js')).default
const _ = (await import('lodash')).default
const fuse = new Fuse(countries, {
keys: ['name'],
threshold: 0.3
})
const searchResult = fuse.search(value).map(result => result.item)
const updatedResults = searchResult.length ? searchResult : countries
setResults(updatedResults)
// Fake analytics hit
console.info({
searchedAt: _.now()
})
}}
/>
initial page에 필요하지 않은 리액트 컴포넌트들 또한 dynamic import 할 수 있다.
const CodeSampleModal = dynamic(() => import('../components/CodeSampleModal'), {
ssr: false
})
대부분의 데스크톱 웹페이지는 web font를 사용하지만 성능적으로 단점이 있을 수 있다. Next.js는 Automatic Webfont Optimization을 제공한다. 기본적으로 빌드 시 폰트 CSS를 자동적으로 inline하여 글꼴 선언을 가져오기 위한 추가 왕복을 없애준다. First Contentful Pain (FCP)와 Largest Contentful Paint (LCP) 향상을 가져온다.
최적화 전에는 아래처럼 추가적인 네트워크 요청이 필요하다.
<link href="https://fonts.googleapis.com/css2?family=Inter" rel="stylesheet" />
Next.js 최적화
<style data-href="https://fonts.googleapis.com/css2?family=Inter">
@font-face{font-family:'Inter';font-style:normal.....
</style>
많은 앱들이 analytics, ads, support widgets 등 다양한 자바스크립트들을 사용한다. 하지만 third-party 코드를 포함시키면 페이지 컨텐츠가 너무 일찍 로드 될 경우 렌더링이 지연되고 사용자 성능에 영향을 미친다.
Next.js는 Third-party 스크립트 로드를 최적화하는 내장 스크립트 컴포넌트를 제공하고 개발자에게 언제 가져와 실행 할 것인지 결정할 수 있는 옵션을 제공한다.
import Script from 'next/script'
function IndexPage() {
return (
<div>
<Script
strategy="afterInteractive"
src="https://www.googletagmanager.com/gtag/js?id=123"
/>
</div>
)
}
로딩을 최적화하기 위해 strategy
항목은 언제 스크립트를 가져올지 결정한다. LCP를 위해서 스크립트들은 defer 되거나 interactive 된 후에 실행되거나 브라우저 가능 시간에 lazy하게 실행해야 한다.
웹사이트를 최적화한 후에 지속적으로 이것이 이어지도록 개발 중에 모니터링하는 것도 중요하다. Core Web Vitals를 모니터링 할 때 일회성 랩 테스트에 의존하는 것보다 시간 경과에 따른 추적이 핵심이다.
Next.js Analytics는 Core Web Vitals를 사용하여 페이지들의 성능을 측정하고 분석하게 해준다. Vercel 배포에서 환경설정 없이 실제 경험 점수 수집을 시작 할 수 있다. 자체 호스팅하는 경우에도 분석을 지원한다.
Next.js Analytics가 사용하는 빌트인 중계기를 사용해 구글 아날리틱스나 다른 서비스로 데이터를 전달 할 수 있다.
reportWebVitals
함수를 사용한 예시
// pages/_app.js
export function reportWebVitals(metric) {
console.log(metric)
}
Chrome User Experience Report 데이터를 사용하는 방법도 있다. Google Data Studio를 사용 할 수 있다. 성능을 측적하는 데이터보드 또한 있다.
CrUX 리포트에 웹사이트를 등록하려면 충분한 방문자가 있어야 가능하다. 그리고 데이터가 달마다 업데이트 되기 때문에 데이터를 보기 위한 딜레이가 있다.
아래 도구들을 통해서도 데이터 수집을 할 수 있다.
라이트하우스 크롬개발자도구의 경우에는 Total Blocking Time을 First Input Delay 를 대신하여 사용하여야 할 것이다.
강연 제목: 프론트엔드에서 TDD가 가능하다는 것을 보여드립니다
TDD (Test Driven Development)는 Test 코드를 먼저 작성하는 개발 방식이다. TDD는 탐지하는 역할을 한다. 개발방법론까지는 아니라고 한다. 강연에서 라이브 코딩을 통해 TDD를 시연했는데 따라가기가 어려웠다. Jest를 공부한 후 다시 돌아와서 이해하면 좋을 것 같다.
강연에서는 TDD를 도입하면 어려울 수 있기 때문에 E2E 테스트부터 시작해보는 것을 추천했다.
TDD의 장점
미래의 고통을 지금으로 가져오는 기술이라고 한다. 꽤 많은 사람들이 TDD를 도입하고 있는 것을 고려하면 TDD는 좋은 방법일 것 같다. 하지만 아직 내가 그 장점들을 체감하지 못했기 때문에 조금 더 TDD에 대해서 공부하고 알아보아야겠다.
npm에서 여러 패키지를 설치 할 때, 패키지가 완전히 설치 될 때까지 기다린 후 다른 패키지를 순차적으로 설치한다. Yarn은 패키지를 병렬적으로 설치해서 속도가 더 빠르다.
패키지들의 버전을 자동으로 변경하지 않으려면 잠금 파일을 생성하여 특정 버전만 설치되도록 할 수 있다. yarn은 의존성이 추가되면 yarn.lock 파일을 자동으로 추가, 업데이트 한다. npm은 이를 수동적으로 해야 한다.