웹 개발을 하다 보면 웹의 디자인이나 컨텐츠 등을 구성하기 위해 다양한 리소스를 사용하게 된다. 주로 이러한 리소스엔 이미지
, 스타일시트
, 폰트
, 아이콘
, 문서
등의 파일이 주로 포함된다.
이와 같은 웹 상에서의 리소스를 효율적으로 관리하고 최적화 하는 것은 페이지 로딩 속도 감소나 사용자 경험 개선 부분에 있어 많은 도움이 될 수 있다.
최근, 모바일 기기에서 웹 페이지를 열었는데 불편함을 느낀 경험이 있다. Popper UI를 열었는데 아이콘을 불러오는 시간이 있어서 그런지, 잠깐 빈 화면이 표시(*)된 후에야 아이콘이 정상적으로 표시되던 일이다.
이 경험으로 웹에서 사용되는 여러 애셋을 미리 다운로드 받아 놓는 전략에 대해 찾아보다가 preload
와 prefetch
개념에 대해 짚고 넘어가보는 계기가 되었다.
*이와 관련된 현상으로는 FOUC(Flash Of Unstyled Content), FOIT(Flash of Invisible Text)가 있다.
preload
와 prefetch
둘 다 HTML <link> 태그의 rel
속성 값으로 올 수 있는 옵션이다.
리소스의 경로를 지정하는 href
속성과 "relationship"을 뜻하는 rel
속성을 통해, 리소스 항목이 웹 문서와 어떻게 연관되어 있는지를 나타낼 수 있다.
preload 와 prefetch는 모두 웹 페이지에서 필요한 리소스를 사용자가 요청하기 전에, 사전에 로드해 두어 사용자가 추후 해당 리소스를 요청할 때 더 빠르게 제공할 수 있도록 한다는 공통점을 가지는 설정이다.
이 값이 "preload"
일 때와 "prefetch"
일 때 각각 어떻게 동작하는지에 대해서는 아래에서 상세히 알아 보자.
프리로드는 웹에서 필요한 리소스를 사용자가 실제로 필요로 하는 순간에 불러오는 것이 아닌, 사전에 미리 로드하는 기술이다. 이에 따라 사용자가 페이지 방문 시, 필요한 리소스가 이미 브라우저에 다운 받아져 있기 때문에 빠르게 렌더링이 되는 효과가 있다.
preload
는 특정 리소스를 미리 다운로드 받도록 브라우저에 지시한다.또한 이렇게 미리 다운로드 된 애셋은 캐시되기 때문에, 후에 사용자가 해당 페이지에 재방문 시 더욱 빠르게 제공할 수 있을 뿐만 아니라 서버 측 부하도 감소되는 효과가 있다.
프리로딩은 웹 페이지 성능을 향상시키고 사용자 경험을 개선하는 중요한 역할을 하여, 해당 기술을 적절히 활용해 최적의 경험을 제공하는 데 기여할 수 있다.
가장 중요한 것은, 사용자가 '필요로 할 것으로 예상'되는 리소스만을 선별해서 프리로드 하도록 해야 한다는 것이다.
무분별하게 아무 것이나 모두 사전에 불러오게 되면 네트워크 대역폭과 자원을 낭비하게 될 뿐만 아니라, 오히려 초기 로딩 시간이 증가하고 브라우저 캐시를 오버로드 할 수도 있게 된다.
이렇듯 경우에 따라선 사용자 경험에 오히려 부정적인 영향을 미칠 수 있기 때문에, 적절한 프리로드 전략을 고려하는 것이 바람직하다.
<link> 요소에 rel
속성을 "preload"
로 설정하면, 브라우저에서 폰트나 스타일 시트, 이미지 등 리소스를 미리 로드해야 한다고 지정할 수 있다.
참고로 "preload" 옵션이 지정된 경우에는 as
속성 값 설정이 필수이다. 링크 요소에 로드되는 컨텐츠 유형을 지정하기 위함이며, 리소스 별 유효한 속성값 중 일부는 다음과 같다.
Value | Applies To (* 전체 목록은 여기서 확인) |
---|---|
audio | <audio> 요소 |
font | CSS @font-face |
image | srcset 또는 imageset 속성을 가진<img> 및 <picture> 요소, SVG <image> 요소, CSS *-image 규칙 |
style | <link rel=stylesheet> 요소, CSS @import |
video | <video> 요소 |
덧붙여 폰트 타입의 리소스를 가져올 때는, <link> 요소에 crossorigin
속성을 설정해 주어야 한다.
<head>
<link rel="preload" href="/letters.png" as="image" />
<link
rel="preload"
href="/fonts/GalmuriMono11.woff2"
as="font"
type="font/woff2"
crossorigin
/>
</head>
만약 프리로드 한 애셋이 브라우저에서 로드되고 나서 몇 초간 사용되지 않았다면, 위와 같이 콘솔 창에 경고가 표시된다. 아까 언급한 주의 사항과 연관지어서, 페이지를 요청했을 때 바로 사용 되어야 하는 리소스에 적용시킨다면 이러한 경고는 표시되지 않을 것이다.
프리페치는 현재 사용자가 있는 페이지와는 관련이 없지만, 이후에 방문할 수 있는 다음 페이지에서 필요한 리소스를 우선적으로(preemptively) 다운로드 할 수 있는 기술이다. 이를 통해 사용자가 페이지를 이동했을 때 신규 페이지의 로딩 속도를 개선하고 부드럽게 전환하는 효과를 제공할 수 있다.
prefetch
는 향후 탐색에서 특정 리소스가 필요할 가능성이 높다는 힌트를 브라우저에 제공한다.사용자가 다음 페이지로 이동할 때 필요한 리소스 혹은 다음 문서에 대해 프리페치 할 수 있으며, 이를 통해 추후 이동될 페이지의 로딩 시간을 단축하고 부드럽게 페이지가 전환될 수 있는 효과를 제공할 수 있다.
참고로, 일반적으로 브라우저는 prefetch
리소스에 preload
리소스 보다 낮은 우선순위를 부여한다. (즉 현재 페이지가 다음 페이지보다 중요하다를 의미)
프리페치도 마찬가지로 사용자가 실제로 필요로 할 것 같은 리소스를 선별해서 적용하는 것이 중요하다.
거기에 더불어 프리페치는 프리로드에 비해 상대적으로 브라우저 지원이 안되는 케이스가 더러 있기 때문에 좀 더 호환성을 고려해서 사용해야 한다. (확인: https://caniuse.com/?search=prefetch)
또한 HTTP Header에 대해서도 주의해야 한다. 만약 Cache-Control 헤더가 no-cache
나 no-store
인 경우 프리페치가 차단될 수 있기 때문이다. 이 제약 때문에 프리페치에는 Speculation Rules API(Experimental)를 함께 사용하는 것이 도움이 될 수 있다고 언급하고 있다.
<!-- index.html -->
<head>
<link rel="prefetch" href="./sub.html" />
</head>
<body>
<a href="./sub.html">Go To Sub Page</a>
</body>
<!-- sub.html -->
<body>
<h1>Hello It's Sub Page</h1>
<img src="./images/test.png" />
</body>