Оптимизация производительности приложения Vue.js: часть 3 — Отложенная загрузка Vuex и отдельных компонент.

Spread the love

В предыдущей частях мы изучили очень эффективный способ увеличение производительности – разделения кода по маршрутам. Хотя само по себе разделение кода может быть очень полезным, в в самих модулях все еще остается много кода, который не всегда нужен сразу после посещения пользователем нашего сайта. В этой части серии мы сосредоточимся на разделении кода в Vuex модулях.

Эта серия основана на уроках процесса оптимизации Vue Storefront . Используя приведенные ниже методы, мы смогли сократить размер нашего конечного файла сборки на 70% и сделать его загрузку в мгновение ока.

Часть 1  —  Введение в оптимизацию производительности и отложенную загрузку.

Часть 2  —  Отложенная загрузка маршрутов и анти-паттерн использования vendors.js.

Часть 3 — Отложенная загрузка Vuex и отдельных компонент

Часть 4 — Отложенная загрузка библиотек

Часть 5  —  Использования кеша Service Worker

Часть 6 — Предзагрузка

Два типа Vuex модулей

Есть одна важная вещь, о которой вы должны знать, прежде чем мы пойдем дальше и расскажем, как отложено загружать модули Vuex. Вы должны знать, какие существуют возможные способы регистрации модуля Vuex и каковы их плюсы и минусы.

Статические модули Vuex объявляются во время инициализации хранилища Store. Пример явно созданного статического модуля:

// store.js
import { userAccountModule } from './modules/userAccount'
const store = new Vuex.Store({
  modules: {
    user: userAccountModule
  }
})

Код создаст новое хранилище Vuex со статическим модулем userAccountModule. Статические модули не могут быть незарегистрированными (также их регистрация не может быть отложена), а их структура (не состояние (not state)!) Не может быть изменена после инициализации Store.

Хотя эти ограничения не являются проблемой для большинства модулей, и объявление их всех в одном месте действительно полезно для хранения всего в одном месте, у этого подхода есть некоторые недостатки.

Допустим, в нашем приложении есть панель администратора с выделенным модулем Vuex.

// store.js
import { userAccountModule } from './modules/userAccount'
import { adminModule } from './modules/admin'

const store = new Vuex.Store({
  modules: {
    user: userAccountModule, 
    admin: adminModule
  }
})

Обычно, что такой модуль может быть довольно большим. Несмотря на то, что панель мониторинга будет использоваться только небольшой частью пользователей и в ограниченной области приложения (скажем, по специальному маршруту /admin) из-за централизованной регистрации статических модулей Vuex, весь ее код окажется в основной сборке проекта.

Это, конечно, не та ситуация, в которой мы хотим оказаться. Нам нужен способ загрузить этот модуль только по маршруту /admin . Как вы уже догадались, статические модули не могут решить подобную задачу. Все статические модули должны быть зарегистрированы в момент создания хранилища Vuex.

Тут нам могут помочь динамические модули!

Динамические модули в отличие от статических могут быть зарегистрированы после создания хранилища Vuex. Эта удобная возможность подразумевает, что нам не нужно загружать динамический модуль при инициализации приложения, и мы можем связывать модуль в другой частью кода или отложено загружать, когда это необходимо.

Сначала давайте посмотрим, как будет выглядеть предыдущий код с динамически зарегистрированным модулем admin.

// store.js
import { userAccountModule } from './modules/userAccount'
import { adminModule } from './modules/admin'

const store = new Vuex.Store({
  modules: {
    user: userAccountModule, 
  }
})

store.registerModule('admin', adminModule)

Вместо того, чтобы передавать объект adminModule непосредственно в свойство модулей нашего store, мы зарегистрировали его после создания store методом registerModule.

Динамическая регистрация не требует каких-либо изменений внутри самого модуля, поэтому любой модуль Vuex может быть зарегистрирован статически или динамически.

Конечно, в текущей форме этот динамически зарегистрированный (но все еще статически загруженный) модуль не дает нам никаких преимуществ.

Правильное разделение по коду модулей Vuex

Давайте вернемся к нашей проблеме. Теперь, когда мы знаем, как динамически зарегистрировать модуль admin, мы, безусловно, можем попытаться поместить его код в сборку маршрутов /admin.

Давайте на минутку остановимся, чтобы кратко понять приложение, с которым мы работаем.

// router.js
import VueRouter from 'vue-router'

const Home = () => import('./Home.vue')
const Admin = () => import('./Admin.vue')

const routes = [
  { path: '/', component: Home },
  { path: '/admin', component: Admin }
]

export const router = new VueRouter({ routes }) 

В router.js у нас есть два маршрута с разделением кода, которые загружаются отложено. С кодом, который мы видели выше, наш модуль admin все еще находится в основной сборке app.js из-за его статического импорта в store.js.

Давайте исправим это и загрузим этот модуль только пользователям, находящихся в /admin.

// store.js
import { userAccountModule } from './modules/userAccount'
export const store = new Vuex.Store({
  modules: {
    user: userAccountModule, 
  }
})

// Admin.vue
import adminModule from './admin.js'

export default { 
  // other component logic
  mounted () { 
    this.$store.registerModule('admin', adminModule)
  },
  beforeDestroy () {
   this.$store.unregisterModule('admin')
  }
}

Давайте посмотрим на то, что случилось!

Мы импортируем и регистрируем admin Store внутри Admin.vue (маршрут /admin) сразу после его монтирования. Позже в коде мы отменяем регистрацию модуля, как только пользователь выходит из панели администратора, чтобы предотвратить многократную регистрацию одного и того же модуля.

Теперь, поскольку модуль admin импортирован из Admin.vue вместо store.js, он будет находится в сборке с Admin.vue!

Важное примечание: если вы используете режим SSR, убедитесь, что вы регистрируете модуль в хуке mounted. В противном случае это может привести к утечке памяти, поскольку хук beforeDestroy не отрабатывает на стороне сервера.

Теперь мы знаем, как использовать динамическую регистрацию модулей Vuex для распределения наших модулей по надлежащие пакетам. Давайте рассмотрим немного более сложный вариант использования.

Отложенная загрузка модулей Vuex

Допустим, у нас есть раздел отзывов на нашем сайте в модуле Home.vue, где мы хотим показать положительные отзывы о наших услугах. Их много, поэтому мы не хотим показывать их сразу после того, как пользователь заходит на наш сайт. Гораздо лучше отображать их, только если пользователь этого хочет. Мы можем добавить кнопку «Show Testimonials», которая будет загружать и отображать отзывы под ней после нажатия.

Для хранения данных отзывов нам нужен еще один модуль Vuex. Давайте назовем его testimonials. Модуль будет отвечать за показ ранее добавленных и новых отзывов. Нам не будем рассматривать детали реализации.

Мы хотим, чтобы модуль testimonials загружался ТОЛЬКО в том случае, если пользователь нажимает кнопку. Давайте посмотрим, как мы можем использовать динамическую регистрацию модуля и динамический импорт для достижения этой функциональности. Testimonials.vue является компонентом внутри Home.vue.

Когда пользователь нажимает кнопку Show Testimonials, вызывается метод getTestimonials(). Он отвечает за вызов getTestimonialsModule(), который импортируется из testimonials.js. Как только промисис будет выполнен (что означает, что модуль загружен), мы динамически регистрируем его и выполняем действие, отвечающее за выборку отзывов.

Благодаря динамическому импорту содержимое testimonials.js будет находиться в отдельном файле, который загружается только при вызове метода getTestimonialsModule.

Когда нам нужно выйти из панели администратора, мы просто отменяем регистрацию ранее зарегистрированного модуля в хуке жизненного цикла beforeDestroy, чтобы модуль не дублировался, если мы снова зайдем по этому маршруту.

Завершение

Несмотря на то, что статической регистрации модулей Vuex достаточно для большинства случаев использования, есть некоторые определенные ситуации, когда мы можем захотеть использовать динамическую регистрацию.

  • Если модуль нужен только на определенном маршруте, мы можем динамически зарегистрировать его в соответствующих компонентах маршрута, чтобы он не попал в основной комплект сборки.
  • Если модуль нужен только после некоторого взаимодействия, то нам нужно совместить динамическую регистрацию модуля с динамическим импортом и отложено загрузить модуль подходящим способом.

Возможность использования разделенных модулей Vuex является мощным инструментом. Чем больше операций, связанных с данными, вы выполняете в своем приложении, тем больше вы получаете экономии с точки зрения размера пакета сборки.

В следующей части серии мы узнаем, как отложено загружать отдельные библиотеки и, что более важно, узнаете какие именно библиотеки следует загружать отложено.

Оригинал: Vue.js App Performance Optimization: part 3— Lazy loading Vuex modules


Spread the love

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *