Skip to content

Продуктивність

Огляд

Vue розроблений таким чином, щоб бути ефективним для більшості поширених випадків використання, без особливої потреби в ручній оптимізації. Однак, завжди є складні сценарії, де потрібне додаткове, тонке налаштування. У цьому розділі ми обговоримо, на що слід звернути увагу, коли йдеться про продуктивність Vue додатку.

Спочатку обговоримо два основні аспекти вебпродуктивності:

  • Швидкість завантаження сторінки: наскільки швидко програма показує вміст і стає інтерактивною під час першого відвідування. Зазвичай це вимірюється за допомогою таких життєво важливих вебметрик, як Largest Contentful Paint (LCP) і First Input Delay (FID).

  • Швидкість оновлення: як швидко програма оновлюється у відповідь на введення даних користувачем. Наприклад, як швидко оновлюється список, коли користувач вводить текст у полі пошуку, або як швидко сторінка перемикається, коли користувач натискає навігаційне посилання в одно-сторінковому додатку (SPA).

Хоча було б ідеально максимізувати обидва, різні фронтенд архітектури, як правило, впливають на те, наскільки легко досягти бажаної продуктивності в цих аспектах. Крім того, тип додатка, який ви створюєте, значною мірою впливає на те, що повинно бути в пріоритеті з точки зору продуктивності. Тому першим кроком для забезпечення оптимальної продуктивності є вибір правильної архітектури для типу додатка, який ви створюєте:

Параметри профілювання

Щоб підвищити продуктивність, нам спочатку потрібно знати, як її виміряти. Є кілька чудових інструментів, які можуть допомогти в цьому відношенні:

Для профілювання навантаження продуктивності розгортання продакшну:

Для профілювання ефективності під час локальної розробки:

Оптимізація завантаження сторінки

Існує багато аспектів, що не залежать від фреймворку, для оптимізації продуктивності завантаження сторінки – перегляньте цей гід web.dev, щоб отримати вичерпну інформацію. Тут ми в першу чергу зосередимося на техніках, які є специфічними для Vue.

Вибір правильної архітектури

Якщо ваш варіант використання чутливий до продуктивності завантаження сторінки, уникайте доставлення його, як чистого SPA на сторону клієнта. Ви хочете, щоб ваш сервер безпосередньо надсилав HTML із вмістом, який хочуть бачити користувачі. Чистий рендеринг на стороні клієнта страждає від повільного завантаження вмісту. Це можна покращити за допомогою Рендерингу на стороні сервера (SSR) або Генерації статичного додатка (SSG). Перегляньте Гід по SSR, щоб дізнатися про виконання SSR за допомогою Vue. Якщо ваша програма не має розширених вимог до інтерактивності, ви також можете використовувати традиційний бекенд сервер для рендерингу HTML і вдосконалити його за допомогою Vue на клієнті.

Якщо ваш основний додаток має бути SPA, але має маркетингові сторінки (цільова сторінка, інформація, блог), відправляйте їх окремо! В ідеалі ваші маркетингові сторінки мають бути розгорнуті як статичний HTML із мінімумом JS за допомогою SSG.

Розмір комплекту та струшування дерева

Один із найефективніших способів покращити продуктивність завантаження сторінки – це надсилання менших комплектів JavaScript. Ось кілька способів зменшити розмір комплекту за допомогою Vue:

  • Якщо можливо, використовуйте етап збірки.

    • Багато API Vue підтримують "струшування дерева", якщо зібрані за допомогою сучасного інструменту збірки. Наприклад, якщо ви не використовуєте вбудований компонент <Transition>, його не буде включено до остаточного комплекту продакшну. Струшування дерева може також видалити інші невикористовувані модулі у вашому вихідному коді.

    • Під час використання етапу збірки шаблони попередньо скомпільовані, тому нам не потрібно доставляти компілятор Vue у браузер. Це заощаджує 14 Кб min+gzipped JavaScript і дозволяє уникнути витрат на компіляцію під час виконання.

  • Будьте обережні з розміром, коли додаєте нові залежності! У реальних додатках роздуті комплекти найчастіше є результатом додавання важких залежностей, не усвідомлюючи цього.

    • Якщо ви використовуєте етап збірки, віддавайте перевагу залежностям, які пропонують формати модулів ES і є дружніми до струшування дерева. Наприклад, віддайте перевагу lodash-es над lodash.

    • Перевірте розмір залежності та оцініть, чи варта вона функціональності, яку вона надає. Зверніть увагу, якщо залежність підтримує струшування дерева, фактичне збільшення розміру залежатиме від API, які ви фактично імпортуєте з неї. Такі інструменти, як bundlejs.com, можна використовувати для швидкої перевірки, але вимірювання за допомогою фактичних налаштувань збірки завжди буде найточнішим.

  • Якщо ви використовуєте Vue переважно для прогресивного вдосконалення та бажаєте уникати етапу збірки, подумайте про використання petite-vue (лише 6kb).

Розбиття коду

Розбиття коду — це коли інструмент збірки розбиває додаток на кілька менших фрагментів, які потім можна завантажувати на вимогу або паралельно. При належному розподілі коду функції, необхідні під час завантаження сторінки, можна завантажити негайно, а додаткові фрагменти завантажуються відкладено лише за потреби, що покращує продуктивність.

Комплектувальники, такі як Rollup (на якому базується Vite) або webpack, можуть автоматично створювати окремі фрагменти, шляхом виявлення синтаксису динамічного імпорту ESM:

js
// lazy.js і його залежності будут виділені в окремий фрагмент
// і завантажуватися лише під час виклику `loadLazy()`.
function loadLazy() {
  return import('./lazy.js')
}

Відкладене завантаження найкраще використовувати для функцій, які не потрібні одразу після початкового завантаження сторінки. У програмах Vue це можна використовувати в поєднанні з функцією Async Component для створення окремих фрагментів для дерев компонентів:

js
import { defineAsyncComponent } from 'vue'

// створюється окремий фрагмент для Foo.vue і його залежностей.
// він завантажується лише на вимогу, якщо є асинхронний компонент
// рендеринг на сторінці.
const Foo = defineAsyncComponent(() => import('./Foo.vue'))

Для додатків, які використовують Vue Router, настійно рекомендується використовувати відкладене завантаження для компонентів маршруту. Vue Router має явну підтримку відкладеного завантаження, окремо від defineAsyncComponent. Дивіться Маршрути відкладеного завантаження для більш детальної інформації.

Оптимізація оновлення

Постійність реквізитів

У Vue дочірній компонент оновлюється лише тоді, коли принаймні один з отриманих атрибутів змінюється. Розглянемо такий приклад:

template
<ListItem
  v-for="item in list"
  :id="item.id"
  :active-id="activeId" />

Усередині компонента <ListItem> він використовує його атрибути id і activeId, щоб визначити, чи є він поточним активним елементом. Хоча це працює, проблема полягає в тому, що щоразу, коли activeId змінюється, кожен <ListItem> у списку буде оновлюватися!

В ідеалі слід оновлювати лише елементи, активний статус яких змінився. Ми можемо досягти цього, перемістивши обчислення активного статусу в батьківський елемент і змусивши <ListItem> безпосередньо приймати реквізит active замість цього:

template
<ListItem
  v-for="item in list"
  :id="item.id"
  :active="item.id === activeId" />

Тепер для більшості компонентів властивість active залишатиметься незмінною, коли activeId змінюється, тому їх більше не потрібно оновлювати. Загалом, ідея полягає в тому, щоб реквізити, передані дочірнім компонентам, були якомога постійнішими.

v-once

v-once — це вбудована директива, яку можна використовувати для рендерингу вмісту, який покладається на дані під час виконання, але ніколи не потребує оновлення. Усе піддерево, у якому вона використовується, буде пропущено для всіх майбутніх оновлень. Перегляньте довідник по API, для більш детальної інформації.

v-memo

v-memo — це вбудована директива, яку можна використовувати для умовного пропуску оновлення великих піддерев або списків v-for. Перегляньте довідник по API для більш детальної інформації.

Загальні оптимізації

Наступні поради впливають як на завантаження сторінки, так і на продуктивність оновлення.

Віртуалізація великих списків

Однією з найпоширеніших проблем продуктивності в усіх фронтенд додатках є рендеринг великих списків. Незалежно від того, наскільки продуктивним є фреймворк, рендеринг списку з тисячами елементів буде повільним, через величезну кількість вузлів DOM, які потрібно обробляти браузеру.

Однак ми не обов'язково візуалізуємо всі ці вузли заздалегідь. У більшості випадків розмір екрана користувача може показувати лише невелику частину нашого великого списку. Ми можемо значно покращити продуктивність за допомогою віртуалізації списків, техніки рендерингу у великому списку лише тих елементів, які зараз знаходяться у вікні перегляду або поблизу нього.

Впровадити віртуалізацію списків нелегко, на щастя, існують бібліотеки спільноти, якими можна безпосередньо скористатися:

Зменшення витрат на реактивність для великих незмінних структур

Система реактивності за замовчуванням у Vue досить глибока. Хоча це робить керування станом інтуїтивно зрозумілим, вона створює певний рівень накладних витрат, коли розмір даних великий, оскільки кожен доступ до властивості запускає проксі-пастки, які виконують відстеження залежностей. Зазвичай це стає помітним під час роботи з великими масивами глибоко вкладених об'єктів, де одному рендерингу потрібен доступ до 100 000+ властивостей, тому це має впливати лише на дуже конкретні випадки використання.

Vue надає вихід, щоб відмовитися від глибокої реактивності за допомогою shallowRef() і shallowReactive(). Неглибокі API створюють стан, який є реактивним лише на кореневому рівні та відкриває всі вкладені об'єкти недоторканими. Це забезпечує швидкий доступ до вкладених властивостей, але компроміс полягає в тому, що тепер ми повинні розглядати всі вкладені об'єкти як незмінні, а оновлення можна запускати лише шляхом заміни кореневого стану:

js
const shallowArray = shallowRef([
  /* великий список глибинних об'єктів */
])

// це не запускатиме оновлення...
shallowArray.value.push(newObject)
// це робить:
shallowArray.value = [...shallowArr.value, newObject]

// це не запускатиме оновлення...
shallowArray.value[0].foo = 1
// це робить:
shallowArray.value = [
  {
    ...shallowArray.value[0],
    foo: 1
  },
  ...shallowArray.value.slice(1)
]

Уникайте непотрібних абстракцій компонентів

Іноді ми можемо створювати компоненти без рендерингу або компоненти вищого порядку (тобто компоненти, які рендерять інші компоненти за допомогою додаткових атрибутів) для кращої абстракції чи організації коду. Хоча в цьому немає нічого поганого, майте на увазі, що екземпляри компонентів набагато дорожчі, ніж звичайні вузли DOM, і створення їх занадто великої кількості, через шаблони абстракції, спричинить витрати на продуктивність.

Зауважте, що зменшення лише кількох екземплярів не матиме помітного ефекту, тому не хвилюйтеся, якщо компонент рендериться лише кілька разів у програмі. Найкращий сценарій для розгляду цієї оптимізації знову ж таки у великих списках. Уявіть собі список зі 100 елементів, де кожен компонент містить багато дочірніх компонентів. Видалення тут однієї непотрібної абстракції компонента може призвести до скорочення сотень екземплярів компонента.

Продуктивність has loaded