Работа с Vue: год спустя

Перевод How we do Vue: one year later, Jacob Schatz, 09.09.2017

Мы уже писали о Vue. Работаем с ним уже больше года и очень довольны результатами. 

Наша ситуация напомнила мне фразу одного человека на reddit в теме о Scala:

У людей, пишущих на скале нет времени на reddit и блоги, они решают чертовы проблемы.

Эта фраза очень точно описывает наш опыт с Vue. Как и Scala, Vue очень хорош, чертовски хорош. Vue не просто новое модное слово, это реальный инструмент. Мы решили множество проблем с помощью него, и не только мы. Проблемы еще остаются, но мы уже знаем, как их решать с помощью Vue. У нас было много идей, и не все из них были удачными. Мы расскажем о том, чему научились на своем опыте.

Мы опубликовали большой style guide по VueВдохновившись нашим опытом, команда Vue сделала свой. Мы часто обновляем наш style guide, потому что постоянно находим новые, более удачные, способы работать с Vue. Дальше поговорим о том, что нового мы узнали.

Используйте VueX

VueX делает жизнь проще при разработке средних или больших фич. Для небольших фич в нем нет необходимости. Мы писали много-файловый редактор в качестве замены текущего отображения файла. Мы не стали использовали VueX и это было ошибкой.

В начале разработки мы использовали состояния. В документации Vue сказано, что они хорошо работают при строгом соблюдении правил. Оказалось, что с VueX работать гораздо удобнее. Хоть в начале он кажется многословным, он более масштабируем. В перспективе это сэкономит много времени. Наши проблемы начинались, когда мы меняли состояние в нескольких местах. В VueX состояние меняется в одном месте. Это избавляет от множества неожиданных багов.

Пишите хороший код

VueJS и VueX – отличные инструменты. Но даже с помощью них можно писать плохой код. Если код работает, это не значит, что его просто поддерживать и масштабировать. Можно не заметить проблем с производительностью. На Vue очень просто писать код и кажется, что он чист и идеален. Но если вы тратите много времени на изменение этого кода, это не так. Код может работать на небольших данных хорошо, и начать тормозить на больших. Простота может быть обманчивой. От вашего кода может вонять, даже при использовании Vue.

Когда вы добавляете объект в data или store, Vue рекурсивно обходит ваш объект и следит за каждым элементом. Если объект с большой вложенностью или просто большой, если вы его часто обновляете (например, по mousemove), то создаете избыточность. Vue без проблем работает с большими массивами данных, но вы должны понимать, что вам действительно необходимо реактивное поведение от данного объекта. C Vue делать реактивным все – просто, но это нужно делать только когда требуется.

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

Весь наш код на Vue следует архитектуре Flux. VueX также ему следует, поэтому мы его тоже используем. Вы по-прежнему можете использовать состояния, но тогда вам самим придется следить за соблюдением правил. В сложной системе это будет вызывать трудности. Удобнее перенести эту ответственность VueX. Хороший пример Vue приложения – registry image list.

Я хочу использовать JQuery вместе с Vue

Во время разработки новых фич постоянно возникал вопрос:

Можно ли смешивать JQuery c VueJS?

Речь не идет о JQuery библиотеках, таких как Select2. Вопрос, в том, стоит ли использовать JQuery для запросов к DOM. После обсуждения, мы решили следующее:

JQuery можно использовать, но только для поиска элементов в DOM.

У нас было несколько обсуждений на эту тему. Некоторые члены команды поддержали это решение. Но после более глубокого изучения проблемы, мы поняли, что это плохая идея. Если вам необходимо искать элементы в DOM в приложении на Vue, значит вы что-то делаете не так. Должно быть другое решение.

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

Вместо запроса, можно использовать store c данными, пришедшими с сервера. Этим данным можно доверять, в отличие от клиентских. Мы считаем: чем меньше данные меняются на клиентской стороне, тем лучше. Это не означает, что мы полностью отказывается от этого, но обычно такие решения становятся не самыми прозрачными. В GitLab мы делаем запросы только к конечным элементам DOM, которые получаем из атрибута data главного элемента. Но мы используем el.dataset, а не JQuery. В GitLab frontend-разработчики тесно сотрудничают с backend-разработчиками для того, чтобы приложение получало необходимые данные. Таким образом мы контролируем разработку приложения.

Пример

Рассмотрим ситуацию:

Сейчас для отображения комментариев используется Vue. У нас стояла задача сделать редактирование последнего комментария, как в Slack’е. По кнопке up в форме, в конце страницы, появляется последний комментарий пользователя, который можно изменить. На рисунке этот комментарий отмечен красным. Сразу же приходит идея:

Давайте сделаем это по-быстрому, а потом что-нибудь придумаем.

Конечно, вы можете сделать это с помощью запроса к DOM, используя JQuery. Это будет быстро. Но в нашем случае лучше, чтобы backend отдавал данные, вместе с отмеченным последним комментарием пользователя. У разработчиков бекенда есть доступ к базе данных, поэтому у них не возникнет проблем. Во фронтенде эти данные будут доступны в store, останется лишь сделать редактирование в форме.

Если вы используете запросы к DOM, “ну только для этой задачи”, знайте, что всегда есть лучшее решение.

Правильное Vue приложение

Каждый Vue модуль должен иметь одно хранилище, одну бизнес задачу и всегда одну точку входа. Точка входа – это компонент, который является контейнером для всех остальных.

Можно начать с одного div.

<!--HAML-->
.js-vue-app{ data: { endpoint: 'foo' }}

<!--HTML-->
<div class="js-vue-app" data-endpoint="foo"></div>
<!--HAML-->

Точки доступа к API описываются в data-атрибутах. Затем Vue приложение вызывает API через выбранный HTTP клиент.

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

Улучшение производительности

Недавно мы переписали систему комментариев для тикетов на Vue. Они были написаны на Haml, JQuery и Rails. Недостатком этой системы было то, что комментарии загружались вместе со страницей. Лучше загружать комментарии через ajax асинхронно, после загрузки страницы. Это увеличит скорость загрузки страницы и время начальной отрисовки.

Мы включили новые комментарии и некоторые люди даже не заметили, что они изменились. Страница тикетов стала отображаться намного быстрее, а лагов на странице стало значительно меньше.

Скорость инициализации кода комментариев на некоторых страницах тикетов возросла многократно. Раньше страница могла иметь десятки тысяч обработчиков событий. Наш код плохо справлялся с таким количеством. Это создавало лаги при скроле большого количества комментариев. Мы удалили JQuery и стали использовать Vue, делая акцент на производительность. Вы сами могли почувствовать, насколько стало быстрее. И это только начало. Переписав код на Vue, его стало намного проще поддерживать. Весь код четко разделен на отдельные компоненты. Это большое преимущество над прошлой версией кода.

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

Рефакторинг – это то слово, которое приговаривают джуниоры, предлагая переписать все на Angular. В Gitlab такого не было. Наши фронтенд-разработчики достаточно консервативны и не поддаются популярным трендом. Но возникает вопрос, почему складывается ощущение, что все хотят рефакторить? Что они пытаются этим добиться? Расскажу, чего мы добились с помощью рефакторинга в GitLab.

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

  1. Затрат на сам рефакторинг.
  2. Затрат на тестирование изменений.
  3. Затрат на обновление тестов и документации.

И имеет свои риски:

  1. Риск сломать то, что работало.
  2. Риск увязнуть в процессе рефакторинга и не закончить его до конца.
  3. Риск не получить качественного улучшения, ради которого все затевалось.

У нас были следующие цели:

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

Цель #2. Хорошо сделанные вещи делают разработчиков счастливее. Это придает команде сил как ничто другое. Измотанный разработчик хочет перестать писать код; довольный разработчик не может перестать писать код. Довольные разработчики работают намного эффективнее.

Для достижения этих целей следующей задачей по рефакторингу стал блок комментариев к запросу на мерж. Он работал очень медленно при большом количестве комментариев. Если комментариев становилось больше 200, страница начинала лагать. Это связанно с множеством причин, одна из которых, это вызов большого количества reflow JavaScript’ом. Для “тяжелых” запросов на мерж, вызовы reflow могли занимать больше 8 секунд! Мы могли сразу это исправить, но это было бы не долгосрочное решение. Было очевидно, что предстояло много работы для того, чтобы добиться хорошей производительности. Но наш код был плохо сопровождаем, что потребовало бы много времени. Переписав на Vue, мы получили хорошую начальную прибавку по скорости, и заложили удобную архитектуру для дальнейших улучшений.

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