02-VueJS Router Performance

업데이트: Link

VueJS Router Performance

Part 2 of 6 in our Vue.js Performance series.
Written by Filip Rakowski

vue-router 경로 및 일반적인 문제의 지연 로딩

이전 기사에서 우리는 지연 로딩의 개념에 대해 배웠고 웹팩 번들링이 내부에서 어떻게 작동하는지 간략하게 이해했습니다. 기본 사항을 잘 이해하면 이 지식을 실제 Vue 응용 프로그램에 적용하는 방법을 알 수 있습니다. 오늘 얻을 수 있는 트릭은 단 몇 분 만에 번들 크기를 크게 줄일 수 있습니다. 기분 좋죠? 그것이 무엇인지 봅시다!

성장하는 애플리케이션의 문제

Vue를 사용하여 매우 간단한 포트폴리오 웹사이트를 구축한다고 가정해 보겠습니다. 이러한 간단한 웹사이트도 일종의 라우팅이 필요하므로 vue-router를 사용하여 “Home”과 “About” 2개의 개별 페이지로 분할해야 합니다.

파일 구조와 라우팅은 다음과 같을 것 입니다.

// router.js
import Home from './Home.vue'
import About from './About.vue'

const routes = [
  { path: '/', component: Home },
  { path: '/about', component: About }
]

응용 프로그램을 인터넷에 게시하려면 먼저 응용 프로그램을 빌드하고 속도를 늦출 수 있는 모든 것을 제거해야 합니다. 이는 프로덕션 번들(최종 사용자가 다운로드할 단일 js 파일)의 가능한 가장 작은 크기를 보장하기 위해 모든 파일을 연결하고 순수 JavaScript로 변환하고 축소해야 함을 의미합니다. 프로덕션 번들이 클수록 사용자가 다운로드하고 브라우저에서 구문 분석하는 데 더 오래 걸립니다.

webpack이 기본 구성으로 이 모든 작업을 수행할 것이라는 점을 언급하는 것이 중요합니다!

사용자가 정신적 컨텍스트 전환을 수행하고 잠재적으로 웹사이트를 떠나는 데 1초면 충분합니다 그래서 webpack이 우리를 위해 이러한 모든 최적화를 해준다는 것이 좋습니다. 그렇지 않으면 방문자 중 일부를 잃을 수도 있습니다!

Slide from amazing talk about performance and human perception by Ilya Grigorik https://www.youtube.com/watch?v=7ubJzEi3HuA

이러한 모든 빌드 타임 마법에도 불구하고 우리는 여전히 최적화되지 않은 코드를 제공하고 있습니다. 왜 그런지 아시나요?

우리가 방문하는 경로에 따라 Home.vue 또는 About.vue (lodash 종속성 포함) 가 필요하지 않을 수 있지만 둘 다 동일한 app.js 번들에 있으며 사용자가 방문하는 경로에 관계없이 다운로드됩니다. 다운로드 및 구문 분석 시간의 낭비입니다!

하나의 추가 경로를 다운로드하는 경우 큰 문제가 아니지만 이 앱이 점점 더 커지고 새로 추가되면 사용자가 초기 방문 시 더 큰 번들을 다운로드하게 될 것이라고 상상할 수 있습니다. 사용자가 흰색 화면을 응시해야 하는 시간이 많을수록 재미있는 고양이 이미지가 포함된 Instagram 피드를 열고 (어쩌면) 다시는 돌아오지 않을 가능성이 커집니다!

This should be you when your bundle is too big.

vue-router를 사용한 경로 기반 코드 분할

이전 기사에서 배운 동적 가져오기 구문을 사용하여 실제로 더 나은 응용 프로그램을 만들고 새로운 기능(각 경로에 대해 별도의 번들을 만들기만 하면 됩니다)을 추가하여 응용 프로그램을 악화시키는 것을 방지합니다. 현재 사용자가 방문한 경로의 코드만 다운로드됩니다.

Vue.js의 다른 모든 것과 마찬가지로 — 매우 쉽습니다. 구성 요소를 경로 개체로 직접 가져오는 대신 동적 가져오기 기능을 전달해야 합니다. 경로 구성 요소는 주어진 경로가 확인될 때만 다운로드됩니다.

따라서 다음과 같이 정적으로 경로 구성 요소를 가져오는 대신:

// router.js
import Home from './Home.vue'
import About from './About.vue'

const routes = [
  { path: '/', component: Home },
  { path: '/about', component: About }
]

동적으로 가져와야 합니다. 동적 가져오기는 이 경로를 진입점으로 사용하여 새 번들을 생성합니다.

// router.js 
const routes = [
  { path: '/', component: () => import('./Home.vue') },
  { path: '/about', component: () => import('./About.vue') }
]

이것을 알면 단일 app.js 파일과 비교하여 동적 가져오기를 사용할 때 번들이 어떻게 보이는지 봅시다.

위의 설정으로 webpack은 3개의 번들을 생성합니다:

  • app.js - 모든 경로에 필요한 앱 진입점(main.js) 및 라이브러리/구성 요소가 있는 기본 번들(이 경우 vuevue-router)
  • home.js - / 경로가 있는 경로가 입력될 때만 다운로드되는 홈 페이지와 번들
  • about.js - /about 경로가 있는 경로가 입력될 때만 다운로드될 정보 페이지(그리고 종속성 - lodash)가 있는 번들입니다.

Side note: 여기에 있는 번들 이름은 단순함을 위해 webpack에서 생성한 실제 이름이 아닙니다. Webppack은 실제로 구성에 따라 _ 0.js, 1.js, etc _와 같은 것을 생성합니다.

이 간단한 기술은 거의 모든 응용 프로그램에 충분하며 매우 짧은 시간에 매우 좋은 결과를 얻을 수 있습니다. 모든 경로에 비슷한 수의 코드가 있다고 가정하면 단 2줄의 코드로 초기 번들 크기를 50% 줄였습니다! 더 많은 경로가 있는 애플리케이션의 경우 개선 사항이 훨씬 더 큽니다. 사실 이 기술은 매우 효과적이어서 많은 경우에 애플리케이션이 가질 수 있는 대부분의 성능 문제를 해결하기에 충분합니다.

Nuxt의 코드 분할

Nuxt를 사용하는 경우 위의 기술이 즉시 적용된다는 것을 알려드리게 되어 기쁩니다. Nuxt의 기본 디렉토리 기반 라우팅 시스템은 기본적으로 모든 경로를 코드 분할합니다!

공통 벤더 번들 anti-pattern

이제 경로 기반 코드 분할의 영향을 덜 강력하게 만들 수 있는 매우 인기 있고 일반적으로 사용되는 안티 패턴을 살펴보겠습니다.

때로는 node_modules의 모든 타사 종속성을 하나의 파일(보통 vendor.js라고 함)에 넣고 싶은 유혹이 있습니다. 모두 한 번만 다운로드하고 전체 애플리케이션에서 재사용하는 것이 성능 면에서 현명한 것 같지만 그렇지 않은 이유를 설명하겠습니다.

유익하게 들릴지 모르지만 이 접근 방식은 모든 경로를 함께 묶을 때와 동일한 문제를 야기합니다. 아래 다이어그램을 살펴보십시오.

문제가 보이나요? lodash는 단일 경로에서만 필요하지만 사용자가 어떤 경로에 있든 다른 종속성과 함께 다운로드됩니다. 이는 웹사이트를 보기 전에 lodash가 다운로드되고 구문 분석될 때까지 기다려야 함을 의미합니다.

모든 종속성을 하나의 파일로 묶으면 앱 로드가 느려집니다. 이것은 확실히 당신이 달성하고자 하는 것이 아닙니다!

모든 종속성을 하나의 파일로 묶지 않고 필요한 경로로 가져오는 대신 필요할 때만 다운로드되도록 합니다. 그러나 추가 최적화 없이는 오버헤드와 코드 중복이 발생합니다.

Home.vue에도 lodash가 필요하다고 가정해 보겠습니다.

이 경우 /about(About.vue)에서 /(Home.vue)로(또는 역순으로) 탐색하면 라이브러리가 두 번 다운로드됩니다.

사용자가 처음 방문할 때 모든 종속 항목이 다운로드될 때까지 기다리게 하는 대신 몇 가지 작은 종속성을 다시 다운로드하는 것이 훨씬 낫지만 개선의 여지가 있습니다. 우리가 이미 이 의존성을 가지고 있다면 그것을 재사용하지 않는 것은 어리석은 일입니다. 그렇죠?

이것이 webpack splitChunksPlugin이 우리를 도울 수 있는 곳입니다. webpack 설정에 이 몇 줄의 코드를 추가하기만 하면 webpack은 자동으로 다양한 번들에서 공유되는 모든 종속성을 별도의 번들로 그룹화합니다. 이 번들은 한 번만 다운로드한 다음 다시 사용합니다.

// webpack.config.js
optimization: {
  splitChunks: {
    chunks: 'all'
  }
}

chunks 속성에서 웹팩에 코드 중복을 위해 최적화해야 하는 코드 청크(출력 번들)를 알려줍니다. 아마 짐작하셨겠지만 이 속성을 all로 설정하면 모든 속성을 최적화해야 합니다.

webpack 문서에서 이 프로세스에 대한 자세한 내용을 읽을 수 있습니다.

요약

경로별로 코드를 분할하는 것은 의심할 여지 없이 애플리케이션에서 훨씬 더 나은 성능 결과를 얻을 수 있는 가장 좋은 방법이며 가능한 한 빨리 구현해야 합니다.

Vue Storefront에 이 기술을 도입하는 데 20분이 걸렸고 초기 번들의 크기를 거의 절반으로 줄였습니다!

시작부터 많은 최적화 기술을 적용하는 것은 불필요한 조기 최적화로 간주되지만 경로 코드 분할은 확실히 미뤄야 하는 것이 아닙니다.

처음부터 경로를 코드 분할하면 성능 앱을 바로 얻을 수 있습니다!

다음 단계

Vue 구성 요소를 지연 로드하는 것에 대해 이미 많이 알고 있습니다. 다음 부분에서는 어떤 구성 요소를 느리게 로드해야 하는지, 이러한 구성 요소가 다운로드될 때 사용자에게 원활한 대기 환경을 제공하는 방법을 이해하여 이 기술을 마스터할 것입니다.

댓글남기기