Codelab: 중요한 애셋을 미리 로드하여 로드 속도 개선

이 Codelab에서는 몇 가지 리소스를 미리 로드하고 미리 가져와 다음 웹페이지의 성능을 개선합니다.

앱 스크린샷

측정

최적화를 추가하기 전에 먼저 웹사이트의 실적을 측정하세요.

  • 사이트를 미리 보려면 앱 보기를 누른 다음 전체 화면 전체 화면을 누릅니다.

Glitch의 실시간 버전에서 Lighthouse 실적 감사 (Lighthouse > 옵션 > 성능)를 실행합니다 (Lighthouse로 실적 기회 찾기 참고).

Lighthouse는 늦게 가져온 리소스에 대해 다음과 같이 감사 실패를 표시합니다.

Lighthouse: 키 요청 미리 로드 감사
  • `Control+Shift+J` (Mac의 경우 `Command+Option+J`)를 눌러 DevTools를 엽니다.
  • 네트워크 탭을 클릭합니다.
늦게 발견된 리소스가 있는 네트워크 패널

main.css 파일은 HTML 문서에 배치된 Link 요소 (<link>)에 의해 가져오지 않으며 별도의 JavaScript 파일인 fetch-css.jswindow.onLoad 이벤트 후 Link 요소를 DOM에 연결합니다. 즉, 브라우저에서 JS 파일의 파싱 및 실행을 완료한 후에만 파일이 가져옵니다. 마찬가지로 main.css 내에 지정된 웹 글꼴 (K2D.woff2)은 CSS 파일의 다운로드가 완료된 후에만 가져옵니다.

주요 요청 체인은 브라우저에서 우선순위를 지정하고 가져오는 리소스의 순서를 나타냅니다. 이 웹페이지의 경우 현재 다음과 같이 표시됩니다.

├─┬ / (initial HTML file)
  └── fetch-css.js
    └── main.css
      └── K2D.woff2

CSS 파일이 요청 체인의 세 번째 수준에 있으므로 Lighthouse에서 이를 늦게 발견된 리소스로 식별했습니다.

중요한 리소스 미리 로드

main.css 파일은 페이지가 로드되는 즉시 필요한 중요한 애셋입니다. 애플리케이션에서 늦게 가져오는 이 리소스와 같은 중요한 파일의 경우 링크 미리 로드 태그를 사용하여 문서 헤더에 Link 요소를 추가하여 브라우저에 더 빨리 다운로드하도록 알립니다.

이 애플리케이션의 미리 로드 태그를 추가합니다.

<head>
  <!-- ... -->
  <link rel="preload" href="main.css" as="style">
</head>

as 속성은 가져오는 리소스 유형을 식별하는 데 사용되며 as="style"는 스타일시트 파일을 미리 로드하는 데 사용됩니다.

애플리케이션을 새로고침하고 DevTools의 네트워크 패널을 살펴봅니다.

미리 로드된 리소스가 있는 네트워크 패널

CSS 파일 가져오기를 담당하는 JavaScript가 파싱을 완료하기도 전에 브라우저가 CSS 파일을 가져오는 방식을 확인해 보세요. 미리 로드하면 브라우저는 리소스가 웹페이지에 중요하다고 가정하고 선제적으로 가져와야 한다는 것을 알 수 있습니다.

미리 로드가 올바르게 사용되지 않으면 사용되지 않는 리소스에 대한 불필요한 요청을 실행하여 성능에 악영향을 미칠 수 있습니다. 이 애플리케이션에서 details.css는 프로젝트 루트에 있는 다른 CSS 파일이지만 별도의 /details route에 사용됩니다. 미리 로드가 잘못 사용될 수 있는 예를 보여주기 위해 이 리소스에 미리 로드 힌트도 추가합니다.

<head>
  <!-- ... -->
  <link rel="preload" href="main.css" as="style">
  <link rel="preload" href="details.css" as="style">
</head>

애플리케이션을 새로고침하고 네트워크 패널을 살펴봅니다. 웹페이지에서 사용하지 않더라도 details.css를 검색하도록 요청이 이루어집니다.

불필요한 미리 로드가 포함된 네트워크 패널

미리 로드된 리소스가 로드된 후 몇 초 이내에 페이지에서 사용되지 않으면 Chrome은 Console 패널에 경고를 표시합니다.

콘솔의 미리 로드 경고

이 경고를 지표로 사용하여 웹페이지에서 즉시 사용되지 않는 미리 로드된 리소스가 있는지 확인합니다. 이제 이 페이지의 불필요한 미리 로드 링크를 삭제할 수 있습니다.

<head>
  <!-- ... -->
  <link rel="preload" href="main.css" as="style">
  <link rel="preload" href="details.css" as="style">
</head>

가져올 수 있는 모든 리소스 유형과 as 속성에 사용해야 하는 올바른 값의 목록은 미리 로드에 관한 MDN 도움말을 참고하세요.

향후 리소스 미리 가져오기

미리 가져오기는 다른 탐색 경로에 사용되지만 현재 페이지에 필요한 다른 중요한 애셋보다 우선순위가 낮은 애셋을 요청하는 데 사용할 수 있는 또 다른 브라우저 힌트입니다.

이 웹사이트에서 이미지를 클릭하면 별도의 details/ 경로로 이동합니다.

경로 세부정보

별도의 CSS 파일인 details.css에는 이 간단한 페이지에 필요한 모든 스타일이 포함되어 있습니다. 이 리소스를 미리 로드하려면 index.html에 링크 요소를 추가합니다.

<head>
  <!-- ... -->
  <link rel="prefetch" href="details.css">
</head>

이로 인해 파일 요청이 트리거되는 방식을 알아보려면 DevTools에서 Network 패널을 열고 Disable cache(캐시 사용 중지) 옵션을 선택 해제합니다.

Chrome DevTools에서 캐시 사용 중지

애플리케이션을 새로고침하고 다른 모든 파일이 가져온 후 details.css에 매우 낮은 우선순위 요청이 어떻게 이루어지는지 확인합니다.

미리 가져온 리소스가 있는 네트워크 패널

DevTools가 열려 있는 상태에서 웹사이트의 이미지를 클릭하여 details 페이지로 이동합니다. details.html에서 details.css를 가져오는 데 링크 요소가 사용되므로 예상대로 리소스에 대한 요청이 이루어집니다.

세부정보 페이지 네트워크 요청

DevTools에서 details.css 네트워크 요청을 클릭하여 세부정보를 확인합니다. 파일이 브라우저의 디스크 캐시에서 검색되는 것을 볼 수 있습니다.

디스크 캐시에서 가져온 세부정보 요청

프리캐시는 브라우저 유휴 시간을 활용하여 다른 페이지에 필요한 리소스를 조기에 요청합니다. 이렇게 하면 브라우저가 애셋을 더 빨리 캐시하고 필요할 때 캐시에서 애셋을 제공할 수 있으므로 향후 탐색 요청 속도가 빨라집니다.

Webpack을 사용한 미리 로드 및 미리 가져오기

코드 분할로 JavaScript 페이로드 줄이기 게시물에서는 동적 가져오기를 사용하여 번들을 여러 청크로 분할하는 방법을 살펴봅니다. 이는 양식이 제출될 때 Lodash에서 모듈을 동적으로 가져오는 간단한 애플리케이션으로 보여줍니다.

코드 분할을 보여주는 Magic Sorter 앱

여기에서 이 애플리케이션의 글리치에 액세스할 수 있습니다.

src/index.js,에 있는 다음 코드 블록은 버튼을 클릭할 때 메서드를 동적으로 가져옵니다.

form.addEventListener("submit", e => {
  e.preventDefault()
  import('lodash.sortby')
    .then(module => module.default)
    .then(sortInput())
    .catch(err => { alert(err) });
});

번들을 분할하면 초기 크기가 줄어 페이지 로드 시간이 개선됩니다. webpack 버전 4.6.0은 동적으로 가져온 청크를 미리 로드하거나 미리 가져오는 기능을 지원합니다. 이 애플리케이션을 예로 들어 lodash 메서드를 브라우저 유휴 시간에 미리 가져올 수 있습니다. 사용자가 버튼을 누르면 리소스가 가져오는 데 지연이 없습니다.

동적 가져오기 내에서 특정 webpackPrefetch 주석 매개변수를 사용하여 특정 청크를 미리 가져옵니다. 이 특정 애플리케이션에서 표시되는 방식은 다음과 같습니다.

form.addEventListener("submit", e => {
  e.preventDefault()
  import(/* webpackPrefetch: true */ 'lodash.sortby')
    .then(module => module.default)
    .then(sortInput())
    .catch(err => { alert(err) });
});

애플리케이션이 다시 로드되면 webpack은 문서 헤더에 리소스의 미리 로드 태그를 삽입합니다. 이는 DevTools의 요소 패널에서 확인할 수 있습니다.

미리 로드 태그가 있는 요소 패널

네트워크 패널에서 요청을 관찰하면 이 청크가 다른 모든 리소스가 요청된 후에 낮은 우선순위로 가져온다는 것도 알 수 있습니다.

미리 가져온 요청이 있는 Network 패널

이 사용 사례에는 미리 가져오기가 더 적합하지만 webpack은 동적으로 가져온 청크의 미리 로드도 지원합니다.

import(/* webpackPreload: true */ 'module')

결론

이 Codelab을 통해 특정 애셋을 미리 로드하거나 미리 가져와 사이트의 사용자 환경을 개선하는 방법을 확실히 이해할 수 있습니다. 이러한 기법은 모든 리소스에 사용해서는 안 되며 잘못 사용하면 성능이 저하될 수 있습니다. 선택적으로 미리 로드하거나 미리 가져오기만 하면 최상의 결과를 얻을 수 있습니다.

요약

  • 나중에 발견되었지만 현재 페이지에 중요한 리소스에 미리 로드를 사용합니다.
  • 향후 탐색 경로나 사용자 작업에 필요한 리소스에 미리 가져오기를 사용합니다.

현재 일부 브라우저에서는 미리 로드와 미리 가져오기를 모두 지원하지 않습니다. 즉, 애플리케이션의 일부 사용자에게는 성능 개선이 눈에 띄지 않을 수 있습니다.

미리 로드 및 미리 가져오기가 웹페이지에 미치는 영향의 특정 측면에 대해 자세히 알아보려면 다음 도움말을 참고하세요.