원문: Leena Sohoni, Addy Osmani, https://web.dev/speculative-prerendering/
추론적인 프리렌더링(Speculative prerendering)과 크롬 체험판(Chrome origin trial)에 참여하는 방법에 대해 알아보자.
preconnect
, preload
, prefetch
, prerender
와 같은 리소스 힌트는 브라우저가 사용자에게 곧 어떤 리소스가 필요한지 알아내는 데 도움을 준다.
preconnect
와 preload
는 선언적인 힌트이다. 브라우저가 이에 따라 동작하므로 다음 작업에 꼭 필요한 리소스에만 사용해야 한다.
prefetch
와 prerender
는 추론적인 힌트이다. 브라우저에서 특정한 리소스가 필요할 가능성이 높기 때문에 이를 가져와야 한다고 권장할 때 사용한다.
이 글에서는 추론적인 프리페치(prefetch)과 프리렌더링을 중점적으로 다룬다. 어떻게 이를 사용하고, 현재 구현의 문제점, 수준 높은 추론을 구현한 유명한 외부 라이브러리에 대해 알아볼 것이다. 브라우저에 동일 출처(same-origin) 추론적인 프리렌더링을 제공하는 기능이 개발 중이며, 구현 방법과 설계에 대해 자세히 알아보고 크롬 체험판에 참여할 수 있다.
prefetch
와 prerender
: 현재 구현사용자는 자신이 관심 있는 링크 목록(예를 들어, 검색어나 사용자의 선호도에 맞는 상품 또는 글 목록) 중 상단에 있는 링크를 클릭할 가능성이 높다. 다시 목록 페이지로 돌아가면 그다음 링크를 클릭할 것이다. prefetch
와 prerender
는 이러한 사용자 행동과 관련된 지식을 바탕으로 한다. 개발자는 특정 페이지(A) 이후 어떤 페이지(B)가 요청될 가능성이 있는지 추론한다.
prefetch
힌트개발자가 브라우저에게 페이지 B 또는 페이지 B의 특정 리소스를 미리 가져올 수 있도록 알리기 위해 페이지 A에 prefetch
힌트를 넣는다면, 브라우저는 페이지 A 처리에 영향을 주지 않고 유휴 상태인 동안 해당 리소스를 가져올 수 있다.
원본 페이지(예시에서 페이지 A)에서 prefetch
를 사용하는 방법은 다음과 같다.
<link rel="prefetch" href="/results/" as="document">
위 코드에서 as
속성은 선택 사항이지만 이미 캐시에 리소스가 있는지 확인할 수 있도록 올바른 헤더를 설정하는 데 도움을 줄 수 있다.
prefetch
지원 및 구현 옵션은 지난 몇 년 동안 성숙해졌다.
prerender
힌트prerender
힌트를 넣으면 브라우저는 페이지 B를 미리 렌더링한다. 페이지를 미리 렌더링하면 사용자가 실제로 페이지 B 링크를 클릭할 때 즉각적인 탐색이 가능해진다.
원본 페이지에서 prerender
를 사용하는 방법은 다음과 같다.
<link rel="prerender" href="/next-page/">
그러나 prerender
는 아직 명확히 정의되거나 보편적으로 구현되지 않았다.
프리페치 동작에 대해 주의해야 할 몇 가지 중요한 사항이 있다. (특히 크롬에서)
크로미움에서 기존에 구현한 prerender
는 많은 메모리를 사용하고 있었다. 그래서 리소스를 미리 가져오지만 자바스크립트를 실행하거나 페이지의 어떤 부분도 미리 렌더링하지 않는 상태가 없는 프리페치가 더 낫다는 판단하에 사라지게 되었다. 기존의 프리렌더링은 약 100MiB의 메모리를 소모했고 미디어와 같은 특정 요소가 미리 렌더링될 때 UI를 방해할 가능성도 있었다.
상태가 없는 프리페치를 사용한 현재 구현 방식은 페이지 로드 시간을 줄이면서 약 45MiB의 메모리라는 상당히 적은 메모리를 소모한다. 가져오기는 prerender
리소스 힌트가 있는 링크 요소에 의해 실행된다. 가져오기가 없는 프리페치(no-fetch prefetch)는 보이는 탭에서 격리되고 UI를 방해할 수 없는 새로운 전용 렌더러에서 실행된다. 상태가 없는 프리페치 프로세스는 필요한 리소스를 캐시하지만 렌더링하지 않는다. 또한 DNS 캐시와 쿠키 저장소가 업데이트되었을 때를 제외하곤 브라우저의 상태를 수정하지 않는다. 새로운 렌더러는 모든 하위 리소스가 로드된 이후 종료된다. 새로운 렌더러는 사용자가 요청하여 페이지를 렌더링하기 위해 생성된다.
프리렌더링을 상태가 없는 프리페치로 구현했지만 우리의 목표인 즉각적인 페이지 로드는 여전히 이룰 수 없다. 즉각적인 페이지 로드를 달성하는 방법을 찾기 전에 프리렌더링 구현과 관련이 있을 수 있는 프리페치의 추론 로직을 구현하는 몇 가지 기본 옵션에 대해 살펴보자.
개발자는 사람들이 어떻게 자신의 사이트를 사용하는지에 대한 통찰력을 가지고 있고, 그 지식을 사용하여 어떤 것을 프리페치 또는 프리렌더링해야 하는지 결정한다. 이러한 사용 추세는 시간에 따라 발전하는 경향이 있으므로 개발자는 사이트에서 사용할 수 있는 최신 분석 데이터를 바탕으로 리소스 힌트를 업데이트해야 한다.
또한 휴리스틱을 사용하여 런타임에 미리 가져와야 하는 리소스를 결정하는 quicklink, guess.js와 같은 라이브러리도 있다. 이를 사용하면 개발자는 어떤 것을 미리 가져와야 하는지 추측할 필요가 없다. 라이브러리는 사용 가능한 데이터를 바탕으로 결정을 내린다.
Quicklink는 교차점 관찰자 API(Intersection Observer API)를 사용하여 뷰포트에 있는 링크를 확인하고 사용자의 연결 상태가 느리지 않은 경우 브라우저가 유휴 상태일 때 링크를 미리 가져온다. 네트워크 정보 API를 사용하여 연결 유형과 데이터 절약 모드가 활성화 여부를 확인한다. Quicklink는 멀티 페이지 앱과 단일 페이지 앱 모두에서 탐색 속도를 높이기 위해 사용할 수 있는 경량 라이브러리이다.
Guess.js는 구글 애널리틱스 또는 비슷한 분석 제공 업체에서 생성한 리포트를 바탕으로 예측 프리페치(predictive prefetching)을 구현한다. 이러한 분석 기반 예측은 사용자에게 필요할 가능성이 있는 리소스를 미리 가져오는 데 사용된다.
지금부터는 브라우저 내부에 비슷한 로직을 만들 수 있는 방법과 이를 지원하기 위해 필요한 추가 도구를 살펴보자.
현재 프리렌더링 구현은 여러 제약 조건을 처리하지 않는다. 다음은 논의된 몇 가지 제한 사항과 프리렌더링을 개선하기 위해 제안된 해결 방법이다.
<link rel="prerender">
는 브라우저에서 프리렌더링을 활성화할 수 있는 유일한 트리거이다. 미리 렌더링할 수 있는 페이지의 모든 링크에 대해 추가 리소스 힌트가 필요하다.
prerender
의 필수 사항이 변경될 수 있으므로 제안된 해결 방법은 사용자가 특정 기준에 맞는 링크에 대해 총괄 트리거를 지정할 수 있도록 해야 한다. 이는 뒤에서 자세히 설명할 추론 규칙 API(speculation rules API)를 사용해 구현할 수 있다.포탈(Portal): 포탈은 페이지 간 원활하고 즉각적인 탐색이 가능하도록 새롭게 제안된 HTML 요소이다. 다음과 같이 미리 렌더링된 콘텐츠를 표시할 수 있다.
<portal id="myPortal" src="https://example.com/"></portal>
해당 요소는 미리 렌더링된 브라우저 컨텍스트에서 미리 렌더링된 페이지의 미리 보기를 제공한다. 이는 페이지 미리 보기에 제한된 권한이 있다는 걸 의미한다. 개발자는 클릭 이벤트와 같은 코드로 컨텍스트를 활성화하여 애니메이션이 있는 포탈을 임베딩 창의 전체 페이지 보기로 확장할 수 있다.
prefetch
와 prerender
의 브라우저 내 추론 규칙이전 섹션에서 다룬 프리렌더링의 중요한 부분 중 하나는 제안된 추론 규칙 API를 통해 사용할 수 있는 프리렌더링 트리거이다. 추론 규칙 API는 특정한 기준에 맞는 페이지를 추측하고 미리 가져오거나 렌더링할 수 있는 전반적인 권한을 브라우저에 나타내기 위해 개발자가 사용할 수 있다.
규칙은 브라우저가 웹사이트에서 사용자가 관심을 가질만한 초기 페이지들을 알아내는 데 도움이 된다. 그런 다음 브라우저는 장치, 네트워크 특성, 페이지 구조, 뷰포트, 커서의 위치, 페이지의 과거 활동 등을 바탕으로 추가적인 휴리스틱을 적용하여 미리 렌더링하거나 가져올 페이지를 결정한다. 따라서 QuickLink 또는 Guess.js가 구현한 것과 같은 추측 로직은 브라우저 자체에서 구현될 수 있다.
추론 규칙은 인라인 스크립트 태그 또는 외부 리소스에서 JSON 객체로 명시할 수 있다. 예를 들어, prerender
에 대한 추론 규칙은 다음과 같이 정의할 수 있다.
<script type="speculationrules">
{
"prerender": [
{
"source": "list",
"urls": ["/page/2"],
"score": 0.5
},
{
"source": "document",
"if_href_matches": ["https://*.wikipedia.org/**"],
"if_not_selector_matches": [".restricted-section *"],
"score": 0.1
}
]
}
</script>
여기에는 prerender
리소스 힌트에 대해 두 가지 유형의 규칙이 정의되어 있다.
urls
목록에 적용된다. score
값은 사용자가 다음에 이 URL 중 하나를 탐색할 가능성이 얼마나 되는지를 나타내는 데 쓰인다. 점수 값은 0.0에서 1.0 사이 값이며 기본값은 0.5이다.if_href_matches
또는 if_not_href_matches
, if_selector_matches
또는 if_not_selector_matches
필터를 포함하여 링크 요소의 하위 집합을 선택할 수 있다.href_matches
는 링크 URL을 비교하는 데 사용되며,selector_matches
는 CSS 선택자를 비교하는 데 사용된다.
이전에 다룬 기능 중 일부를 포함하는 프리렌더링의 초기 구현은 크롬 94에서 98까지 실행되는 크롬 체험판에서 사용할 수 있다. 다음은 체험판에 포함된 주요 기능이다.
트리거: 동일 출처 URL을 미리 렌더링하는 트리거를 명시하는 데 추론 규칙 API의 특정 기능을 사용할 수 있다. 현재 "목록 규칙" 형식만 지원한다. 또한 동일 출처 페이지에 대해 페이지 당 하나의 프리렌더링만 허용한다.
<script type="speculationrules">
{
"prerender": [
{"source": "list", "urls": ["https://a.test/foo"]}
]
}
</script>
체험판을 사용하기 시작하면 페이지가 프리렌더링 되는지 확인할 수 있고 기존의 크롬 도구를 이용하여 성능 영향을 연구할 수 있다.
chrome://process-internals
페이지에서 미리 렌더링된 페이지가 있는지 확인할 수 있다.
추론 규칙을 통해 프리렌더링을 시작하는 페이지와 이미 프리렌더링된 페이지는 모두 같은 webcontents
블록 아래 있지만 prerender
키워드로 구분할 수 있다.
프리렌더링 후 다음 단계는 활성화이다. 탐색 시 활성화된 페이지가 프리렌더링된 페이지이고 새로운 페이지가 로드되지 않았다는 것을 확인하기 위해 탐색한 후 개발자 도구의 콘솔을 이용할 수 있다. 다음 스크립트를 실행하여 activationStart
값을 콘솔에서 확인해라.
let activationStart = performance.getEntriesByType('navigation')[0].activationStart;
console.log(activationStart);
activationStart
값이 0이 아니라면 미리 렌더링된 페이지가 활성화되었다는 것이다.
activationStart
값은 FP(First Paint) 값과 FCP(First Contentful Paint) 값을 비교하여 프리렌더링 페이지에 대한 사용자 중심 성능 메트릭을 결정할 수 있는 타임스탬프 값이다.
// 활성화 탐색이 시작 되었을 때
let activationStart = performance.getEntriesByType('navigation')[0].activationStart;
// FP가 발생했을 때
let firstPaint = performance.getEntriesByName('first-paint')[0].startTime;
// FCP가 발생했을 때
let firstContentfulPaint = performance.getEntriesByName('first-contentful-paint')[0].startTime;
console.log('time to first paint: ' + (firstPaint - activationStart));
console.log('time to first-contentful-paint: ' + (firstContentfulPaint - activationStart));
체험판을 사용하기 전 firstPaint
와 firstContentfulPaint
값을 비교하면 성능 영향을 측정하는 데 도움이 될 수 있다. 또한 체험판에서 성능을 측정할 때 실제 사용자 모니터링 방법(real user monitoring (RUM))을 이용하는 것을 권장한다.
프리렌더링 체험판에 대한 간단한 데모를 확인하려면 크롬에서 enable-prerender2
플래그를 활성화해라.
데모는 <link rel=prerender>
와 추론 규칙 API를 사용한 세 가지 다른 페이지 유형을 미리 렌더링하는 옵션을 제공한다. 사용 가능한 각 옵션을 클릭하여 프리렌더링이 일어나는지 확인할 수 있다.
또한 페이지 링크를 클릭해서 각 사례의 전환을 비교할 수 있다.
추론 규칙을 사용한 Timer.html | 추론 규칙을 사용하지 않은 Timer.html |
---|---|
이 체험판의 목적은 외부 라이브러리 의존 없이 브라우저를 통해 거의 즉각적인 페이지 로드를 제공하는 것이다. 동시에 사용자 경험을 방해하지 않고, 보다 정교한 프리렌더링 여정을 시작하는데 좋은 기회를 제공한다. 프리렌더링 체험판에 등록하고 특정 사용 사례에 얼마나 잘 동작하는지 확인해라. 체험판에 대한 피드백이 있다면 GitHub 레포지토리에 이슈를 등록해라.
프리페치를 위한 추론 규칙 사용에 대한 체험판도 현재 진행 중이다. 기존 prefetch
힌트를 브라우저에서 지원하는 추측 프리페치로 교체하려면 이 체험판에 등록해라.