Async Vue.js Components

업데이트: Link

Async Vue.js Components

애플리케이션이 성장함에 따라 더 빠르게 만들기 위해 성능 패턴을 찾기 시작합니다. 도중에 필요할 때까지 코드 청크의 로딩을 연기함으로써 초기 번들을 더 작게 만드는 코드 분할과 지연 로딩을 발견하게 될 것입니다.

지연 로딩은 앱 경로에 적용하는 것이 매우 합리적이며 각 경로가 앱의 다른 섹션이기 때문에 큰 영향을 미칩니다.

지연 로딩이 의미가 있는 또 다른 경우는 렌더링이 지연되는 구성 요소가 있는 경우입니다. 이러한 구성 요소는 도구 설명, 팝오버, 모달 등이 될 수 있으며 async components 로 사용할 수 있습니다.

Vue에서 이러한 비동기 구성 요소를 빌드하고 지연 로드하는 방법을 살펴보겠습니다.

Lazy Loading a Component

구성 요소를 지연 로드하는 것으로 시작하기 전에 먼저 일반적으로 구성 요소를 로드하는 방법을 기억합시다. 이를 위해 Tooltip.vue 구성 요소를 생성해 보겠습니다.

<!-- Tooltip.vue -->
<template>
  <h2>Hi from Tooltip!</h2>
</template>

특별한 것은 없으며 단순한 구성 요소입니다. 로컬 등록을 수행하고 Tooltip 구성 요소를 가져오고 components 구성 요소 옵션에 추가하여 다른 구성 요소에서 사용할 수 있습니다. 예를 들어 App.vue 구성 요소에서:

<!-- App.vue -->
<template>
  <div>
    <tooltip></tooltip>
  </div>
</template>

<script>
import Tooltip from "./Tooltip";

export default {
  components: {
    Tooltip
  }
};
</script>

Tooltip 구성 요소는 앱을 가져오는 동안(아마도 초기 로드 시) 가져오고 사용하고 로드합니다. 하지만 생각해보세요: 우리가 그것을 사용할 때만 그 컴포넌트를 로드하는 것이 말이 되지 않습니까? 사용자는 툴팁 없이 전체 시트를 탐색할 수 있습니다.

애플리케이션 시작 시 구성 요소를 로드하는 데 귀중한 리소스를 사용해야 하는 이유는 무엇입니까? 이를 개선하기 위해 지연 로딩과 코드 분할의 조합을 적용할 수 있습니다. Lazy loading은 나중에 사용하려고 할 때 무언가를 로드하는 기술입니다.

코드 분할은 청크라고 하는 별도의 파일에서 코드 조각을 분리하여 애플리케이션의 초기 번들이 줄어들고 초기 로드가 증가하도록 하는 것입니다.

Vue는 런타임에 모듈을 로드할 수 있는 언어의 ES2018 버전에 상륙할 포함될 있는 JavaScript 기능인 언어 표준 ‘동적 가져오기’ 를 사용하여 이러한 기술을 쉽게 적용할 수 있습니다. 이러한 개념에 대해 자세히 설명하는 별도의 기사가 있지만 실용적이고 간단한 관점에서 살펴보겠습니다.

Webpack (버전 2 이후), RollupParcel 과 같은 최신 번들러는 이 구문을 이해하고 필요할 때 로드될 해당 모듈에 대한 별도의 파일을 자동으로 생성합니다.

나는 당신이 이미 일반적인 정적 방법으로 모듈을 가져오는 것에 익숙하다고 상상할 수 있습니다. 그러나 동적 가져오기는 모듈을 페이로드로 포함하는 약속을 반환하는 함수입니다. 다음 예제에서는 정적 및 지연 로드 동적 방식으로 utils 모듈을 가져오는 방법을 보여줍니다.

// static import
import utils from "./utils";

// dynamic import
import("./utils").then(utils => {
  // utils module is available here...
});

Vue에서 구성 요소를 지연 로드하는 것은 함수에 래핑된 동적 가져오기를 사용하여 구성 요소를 가져오는 것만큼 쉽습니다. 이전 예에서 다음과 같이 Tooltip 구성 요소를 지연 로드할 수 있습니다.

export default {
  components: {
    Tooltip: () => import("./Tooltip")
  }
};

그게 전부입니다. 이전 import Tooltip from "./tooltip" 대신 () => import("./tooltip")을 전달하면 Vue.js는 렌더링이 요청되는 즉시 해당 구성 요소를 지연 로드합니다.

뿐만 아니라 코드 분할도 적용됩니다. 언급된 번들러를 사용하여 해당 코드를 실행하여 테스트할 수 있습니다. 쉬운 방법은 vue-cli 를 사용하는 것이지만 기사 끝에서 이미 빌드된 데모를 찾을 수 있습니다. 실행 후 개발 도구를 열면 1.chunk.js와 같은 이름의 JavaScript 파일이 표시됩니다.

img

비동기 구성 요소를 조건부로 로드

이전 예제에서 Tooltip 구성 요소를 느리게 로드하더라도 렌더링이 필요한 즉시 로드되며, 이는 App 구성 요소가 마운트되는 즉시 발생합니다.

그러나 실제로는 필요할 때까지 Tooltip 구성 요소 로드를 연기하고 싶습니다. 이는 일반적으로 버튼이나 텍스트를 가리킬 때와 같이 특정 이벤트가 트리거된 후 조건부로 발생합니다.

단순화를 위해 이전 App 구성 요소를 사용하고 v-if 조건을 사용하여 조건부로 도구 설명을 렌더링하는 버튼을 추가해 보겠습니다.

<!-- App.vue -->
<template>
  <div>
    <button @click="show = true">Load Tooltip</button>
    <div v-if="show">
      <tooltip></tooltip>
    </div>
  </div>
</template>

<script>
export default {
  data: () => ({ show: false }),
  components: {
    Tooltip: () => import("./Tooltip")
  }
};
</script>

Vue는 렌더링이 필요할 때까지 구성 요소를 사용하지 않습니다. 그 시점까지 구성 요소가 필요하지 않으며 구성 요소가 지연 로드될 때를 의미합니다.

Codesandbox 에서 실행되는 이 예제의 데모를 볼 수 있습니다. Codesandbox는 코드 분할을 수행하지 않으므로 개발 도구에서 확인하려면 데모를 다운로드하여 컴퓨터에서 로컬로 실행할 수 있습니다.

비동기 구성 요소에 대한 사용자 경험

대부분의 경우 비동기 구성 요소는 기본 번들에서 제거된 작은 코드 조각이기 때문에 매우 빠르게 로드됩니다. 그러나 매우 느린 연결에서 큰 모달 구성 요소를 lazy loading 한다고 상상해보십시오. 로드하고 렌더링하는 데 몇 초가 걸릴 수 있습니다.

물론 HTTP 캐싱 또는 리소스 힌트와 같은 일부 최적화를 사용하여 우선 순위가 낮은 메모리에 미리 로드할 수 있습니다. 사실 새로운 vue-cli는 지연 로드된 청크에 프리페치를 적용합니다. 그러나 몇 가지 경우에는 로드하는 데 시간이 걸릴 수 있습니다.

UX 관점에서 작업이 발생하는 데 1초 이상 걸리면 사용자의 주의를 잃기 시작합니다.

그러나 사용자에게 피드백을 제공함으로써 주의를 유지할 수 있습니다. 사용자의 주의를 끌기 위해 로드하는 동안 사용할 수 있는 몇 가지 진행률 표시기 구성 요소가 있지만 비동기 구성 요소가 로드되는 동안 어떻게 멋진 스피너 또는 진행률 표시줄을 사용할 수 있습니까?

Loading Component

비동기 구성 요소를 지연 로드하기 위해 동적 가져오기와 함께 함수를 사용한 것을 기억하십니까?

export default {
  components: {
    Tooltip: () => import("./Tooltip")
  }
};

동적 가져오기의 결과 대신 개체를 반환하여 비동기 구성 요소를 정의하는 장기적인 방법이 있습니다. 해당 객체에서 로딩 컴포넌트를 정의할 수 있습니다:

const Tooltip = () => ({
  component: import("./Tooltip"),
  loading: AwesomeSpinner
});

그런 식으로 기본 지연 200ms 후에 AwesomeSpinner 구성 요소가 표시됩니다. delay를 사용자 정의할 수 있습니다.

const Tooltip = () => ({
  component: import("./Tooltip"),
  loading: AwesomeSpinner,
  delay: 500
});

로딩 컴포넌트로 사용해야 하는 컴포넌트는 가능한 한 작아야 거의 즉시 로드됩니다.

Error Component

같은 방식으로 지연 로드된 구성 요소의 긴 형식으로 오류 구성 요소를 정의할 수 있습니다.

const Tooltip = () => ({
  component: import("./Tooltip"),
  loading: AwesomeSpinner,
  error: SadFaceComponent
});

SadFaceComponent./Tooltip 구성 요소를 로드하는 중에 오류가 발생하면 표시됩니다. 다음과 같은 경우에 발생할 수 있습니다.

  • 인터넷이 다운됐다
  • 해당 구성 요소가 존재하지 않습니다(이는 의도적으로 직접 삭제하여 시도해 볼 수 있는 좋은 방법입니다)
  • 시간 초과가 충족됨

기본적으로 시간 초과는 없지만 직접 구성할 수 있습니다.

const Tooltip = () => ({
  component: import("./Tooltip"),
  loading: AwesomeSpinner,
  error: SadFaceComponent,
  timeout: 5000
});

이제 5000밀리초 후에 구성 요소가 로드되지 않으면 오류 구성 요소가 표시됩니다.

마무리

구성 요소가 자체 청크 파일에서 분할되는 방식과 동적 가져오기를 사용하여 지연 로드되는 방식을 확인했습니다. 또한 조건부로 렌더링하여 청크 로딩을 연기했습니다.

비동기 구성 요소는 청크의 로드를 분할하고 지연하여 앱 로드 시간을 개선할 수 있지만 특히 크면 UX에 영향을 줄 수 있습니다. 로딩 상태를 제어하면 속도 저하가 눈에 띄는 경우 피드백을 제공하고 사용자를 참여시킬 수 있습니다.

댓글남기기