10 лучших практик для создания и поддержки крупных проектов Vue.js

10 лучших практик для создания и поддержки крупных проектов Vue.js Сайтостроение

10 лучших практик для создания и поддержки крупных проектов Vue.js

От автора: вот рекомендации, которые я разработала, работая над проектами Vue с большой базой кода. Эти советы помогут вам разработать более эффективный код, который легче поддерживать.

Как фрилансер я имела в этом году возможность работать над некоторыми крупными приложениями Vue. Я говорю о проектах с более чем дюжиной хранилищ Vuex, большим количеством компонентов (иногда сотнями) и множеством представлений (страниц). Фактически, для меня это был довольно полезный опыт, так как я обнаружила много интересных шаблонов, позволяющих сделать код масштабируемым. Мне также пришлось исправить некоторые неоптимальные подходы, которые приводили к известной проблеме спагетти-кода.

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

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

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

Но какое это имеет отношение к крупным проектам Vue.js? Лучше один раз увидеть, чем сто раз услышать, поэтому я опишу вам реальную ситуацию, когда я впервые пожалел, что не использовала их.

Однажды мне просто пришлось создать всплывающее окно. С первого взгляда ничего сложного, оно включало заголовок, описание и несколько кнопок. Так что я сделала это так, чтобы передать все как свойство. В итоге у меня было три свойства, которые использовались для настройки компонентов, и когда люди нажимали на кнопки, генерировалось событие. Очень просто!

Но, поскольку проект со временем разрастался, команда попросила, чтобы мы отобразили в нем много нового: поля формы, разные кнопки в зависимости от того, на какой странице окно отображалось, карточки, футер и список желаний. Я подумала, что если я и дальше буду использовать свойство, чтобы этот компонент развивался, это будет хорошо. Но, Боже, как я ошибалась! Компонент быстро стал слишком сложным для понимания, поскольку включал в себя бесчисленное количество дочерних компонентов, использовал слишком много свойств и генерировал большое количество событий. Я столкнулся с той ужасной ситуацией, когда вы вносите изменения где-то в одном месте, и они ломают что-то в другом. Я создала монстра Франкенштейна вместо ремонтопригодного компонента!

Тем не менее, все могло бы быть лучше, если бы я полагалась на слоты с самого начала. Я закончила рефакторинг всего, чтобы придумать этот крошечный компонент. Легче в обслуживании, быстрее для понимания и более расширяемо!

1234567891011121314151617181920212223242526272829303132333435<template>  <div class=»c-base-popup»>    <div v-if=»$slot.header» class=»c-base-popup__header»>      <slot name=»header»>    </div>    <div v-if=»$slot.subheader» class=»c-base-popup__subheader»>      <slot name=»subheader»>    </div>    <div class=»c-base-popup__body»>      <h1>{{ title }}</h1>      <p v-if=»description»>{{ description }}</p>    </div>    <div v-if=»$slot.actions» class=»c-base-popup__actions»>      <slot name=»actions»>    </div>    <div v-if=»$slot.footer» class=»c-base-popup__footer»>      <slot name=»footer»>    </div>  </div></template> <script>export default {  props: {    description: {      type: String,      default: null    },    title: {      type: String,      required: true    }  }}</script>

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

Имейте в виду, что, как правило, когда вы в конечном итоге дублируете свойства дочерних компонентов внутри их родительского компонента, вы должны начать использовать слоты в этой точке.

2. Правильно организуйте хранилище Vuex

Обычно новички Vue.js начинают интересоваться Vuex, потому что они наткнулись на одну из следующих проблем:

Либо им нужен доступ к данным одного компонента из другого, который на самом деле слишком далеко в древовидной структуре, либо

Им нужны данные для сохранения после удаления компонента.

Именно тогда они создают свое первое хранилище Vuex, узнают о модулях и начинают организовывать их в приложении.

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

Авторизация.

Блог.

Входящие сообщения.

Настройки.

Мне же легче понять, когда они организованы в соответствии с моделями данных, которые выбирают из API. Например:

Пользователи

Команды

Сообщения

Виджеты

Статьи

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

3. Используйте действия для выполнения вызовов API и внесения данных

Большинство моих вызовов API (если не все) выполняются внутри действий Vuex. Вы можете спросить: почему это подходящее место?

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

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

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

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

4. Упростите кодовую базу с помощью mapState, mapGetters, mapMutations и mapActions

Обычно нет необходимости создавать несколько вычисляемых свойств или методов, когда вам просто нужен доступ к состоянию / геттерам или вызову действий / мутаций внутри компонентов. Используя mapState, mapGetters, mapMutations и mapActions и группируя то, что исходит от хранилища модулей в одном месте, вы можете сократить код и сделать вещи понятнее.

READ
Статистические показатели результативности борьбы Google со спамом

JavaScript

12345678910111213141516171819202122// NPMimport { mapState, mapGetters, mapActions, mapMutations } from «vuex»; export default {  computed: {    // Accessing root properties    …mapState(«my_module», [«property»]),    // Accessing getters    …mapGetters(«my_module», [«property»]),    // Accessing non-root properties    …mapState(«my_module», {      property: state => state.object.nested.property    })  },   methods: {    // Accessing actions    …mapActions(«my_module», [«myAction»]),    // Accessing mutations    …mapMutations(«my_module», [«myMutation»])  }};

5. Используйте API Фабрики

Обычно мне нравится создавать хелпер this.$api, который я могу вызывать где угодно, чтобы получить конечные точки API. В корне проекта у меня есть папка api, в которую входят все классы.

JavaScript

1234api├── auth.js├── notifications.js└── teams.js

Каждый группирует все конечные точки для своей категории. Вот как я инициализирую в приложениях Nuxt этот шаблон с помощью плагина (процесс довольно похожий в стандартном приложении Vue).

JavaScript

123456789101112131415161718192021// PROJECT: APIimport Auth from «@/api/auth»;import Teams from «@/api/teams»;import Notifications from «@/api/notifications»; export default (context, inject) => {  if (process.client) {    const token = localStorage.getItem(«token»);    // Set token when defined    if (token) {      context.$axios.setToken(token, «Bearer»);    }  }  // Initialize API repositories  const repositories = {    auth: Auth(context.$axios),    teams: Teams(context.$axios),    notifications: Notifications(context.$axios)  };  inject(«api», repositories);};

JavaScript

1234567891011121314151617export default $axios => ({  forgotPassword(email) {    return $axios.$post(«/auth/password/forgot», { email });  },   login(email, password) {    return $axios.$post(«/auth/login», { email, password });  },   logout() {    return $axios.$get(«/auth/logout»);  },   register(payload) {    return $axios.$post(«/auth/register», payload);  }});

Теперь я могу просто вызывать их в компонентах или действиях Vuex, например:

JavaScript

1234567891011export default {  methods: {    onSubmit() {      try {        this.$api.auth.login(this.email, this.password);      } catch (error) {        console.error(error);      }    }  }};

6. Используйте $config для доступа к переменным среды (особенно полезно в шаблонах)

Ваш проект, вероятно, содержит некоторые глобальные переменные конфигурации, определенные в некоторых файлах:

JavaScript

123config├── development.json└── production.json

Мне нравится быстро получать к ним доступ через хелпер this.$config, особенно когда я нахожусь внутри шаблона. Как всегда, расширить объект Vue довольно просто:

JavaScript

123456789101112// NPMimport Vue from «vue»; // PROJECT: COMMONSimport development from «@/config/development.json»;import production from «@/config/production.json»; if (process.env.NODE_ENV === «production») {  Vue.prototype.$config = Object.freeze(production);} else {  Vue.prototype.$config = Object.freeze(development);}

7. Следуйте единому соглашению именования коммитов

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

READ
Поисковую выдачу Google будет трясти из-за May 2020 Core Update

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

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

JavaScript

12345git commit -am «<type>(<scope>): <subject>» # Here are some samplesgit commit -am «docs(changelog): update changelog to beta.5″git commit -am «fix(release): need to depend on latest rxjs and zone.js»

8. Всегда замораживайте версии пакета, когда проект находится в производстве

Я знаю… Все пакеты должны следовать правилам семантического контроля версий. Но реальность такова, что для некоторых из них это не так.

Чтобы не просыпаться посреди ночи в холодном поту, потому что одна из ваших зависимостей сломала весь проект, блокировка всех версий пакета должна сделать ваше рабочее утро менее напряженным. Это означает следующее: избегайте версий с префиксом ^:

JavaScript

123456789101112131415161718192021222324{  «name»: «my project»,   «version»: «1.0.0»,   «private»: true,   «dependencies»: {    «axios»: «0.19.0»,    «imagemin-mozjpeg»: «8.0.0»,    «imagemin-pngquant»: «8.0.0»,    «imagemin-svgo»: «7.0.0»,    «nuxt»: «2.8.1»,  },   «devDependencies»: {    «autoprefixer»: «9.6.1»,    «babel-eslint»: «10.0.2»,    «eslint»: «6.1.0»,    «eslint-friendly-formatter»: «4.0.1»,    «eslint-loader»: «2.2.1»,    «eslint-plugin-vue»: «5.2.3»  }}

9. Используйте виртуальный скроллер Vue при отображении большого количества данных.

Когда вам приходится отображать много строк на заданной странице или перебирать большой объем данных, вы могли заметить, что страница может отображаться очень медленно. Чтобы это исправить, вы можете использовать vue-virtual-scoller.

JavaScript

1npm install vue-virtual-scroller

Он будет отображать только видимые элементы в списке и повторно использовать компоненты и элементы dom, чтобы быть максимально эффективным и производительным. Он действительно прост в использовании и работает как волшебный амулет!

12345678910111213<template>  <RecycleScroller    class=»scroller»    :items=»list»    :item-size=»32″    key-field=»id»    v-slot=»{ item }»  >    <div class=»user»>      {{ item.name }}    </div>  </RecycleScroller></template>

10. Отслеживайте размер сторонних пакетов

Когда в одном проекте работает много людей, количество установленных пакетов может быстро стать невероятно большим, если никто не обращает на них внимания. Чтобы приложение не работало медленно (особенно в медленных мобильных сетях), я использую в Visual Studio Code import cost package. Таким образом, я прямо из редактора вижу, насколько велика импортированная библиотека модулей, и могу проверить, что не так, когда она становится слишком большой.

Например, в недавнем проекте была импортирована вся библиотека lodash (которая имеет размер приблизительно 24 КБ в сжатом виде). В чем проблема? Из нее был использован только метод cloneDeep. Определив эту проблему, мы исправили ее с помощью:

JavaScript

12npm remove lodashnpm install lodash.clonedeep

Затем функцию clonedeep можно импортировать при необходимости:

JavaScript

1import cloneDeep from «lodash.clonedeep»;

Чтобы еще больше оптимизировать код, вы также можете использовать пакет Webpack Bundle Analyzer для визуализации размера выходных файлов веб-пакета с помощью интерактивной масштабируемой древовидной карты.

Автор: Nada Rifki

Редакция: Команда webformyself.

Оценить статью
Блог о самом интересном.