При размере 500 пикселей большая часть нашего клиентского кода написана с использованием Backbone и Marionette с шаблонами handlebars. Хотя до сих пор это хорошо служило нам, мы всегда ищем способы улучшить наш стек, архитектуру и передовые методы.

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

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

Инкрементальный DOM

Добавочная DOM - это библиотека для создания шаблонов и обновления DOM на месте по мере необходимости, вместо простой замены больших ее фрагментов. Шаблоны определяются в JavaScript с использованием нескольких методов для открытия и закрытия элементов и создания других узлов DOM.

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

patch(element, function() { render(data); });

Вот и все. Чтобы запустить его в нашем проекте, необходимо выполнить два шага:

  1. Обновите метод рендеринга Marionette, чтобы использовать метод инкрементального патча DOM.
  2. Скомпилируйте наши шаблоны в инкрементальную модель DOM

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

Рендеринг инкрементальной модели DOM с помощью Marionette

Можно переопределить метод рендеринга Marionette по умолчанию для реализации пользовательского рендеринга. Мы уже делали это для подключения шаблонов руля, поэтому добавление инкрементальной модели DOM не потребовало много работы. (Обратите внимание, что мы используем Marionette 2.4, поэтому, если вы используете версию 3, все может выглядеть немного иначе).

Нам нужно переопределить Marionette.Renderer.render с помощью нашего нового метода рендеринга, а также нам нужно обновить метод attachElContent представления, чтобы Марионетка использовала метод инкрементной DOM patch вместо простой замены узла DOM.

Давайте быстро разберемся, что там происходит. Во-первых, мы определяем функцию, которую мы будем использовать, чтобы переопределить стандартный метод нашего представления прикрепления визуализированного HTML к DOM. Обычно эта функция принимает в качестве параметра фрагмент HTML, сгенерированный вызовом рендеринга, но IncrementalDom.patch ожидает функцию.

Затем мы настраиваем нашу пользовательскую функцию рендеринга. Чтобы позволить нам иметь сочетание представлений с использованием наших стандартных шаблонов ручек, а также с использованием инкрементной DOM, мы используем флаг в представлении с именем renderer, чтобы определить, какой метод использовать. Если представление использует инкрементную DOM, мы переопределяем его метод attachElContent и возвращаем функцию, которая запускает наш инкрементальный шаблон DOM с текущим data. Как упоминалось выше, именно эта функция передается в patch. На данный момент наши функции-шаблоны прикреплены к window с префиксом tmpl_. Подробнее об этом позже.

Компиляция шаблонов в инкрементную DOM

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

Существует несколько библиотек и языков шаблонов для инкрементальной DOM, но ни одна из них не подходит для нашего конкретного случая использования. Поэтому мы решили написать быстрый парсер, который позаботится об этом за нас, и новый помощник для определения наших дополнительных шаблонов DOM. Мы пишем шаблоны на том, что по сути является «встроенным JavaScript». Давайте сразу перейдем к примеру.

Все в нашем шаблоне, окруженное <% ... %>, рассматривается как JavaScript, а все остальное обрабатывается как html. Мы также можем использовать <%= ... %>, чтобы вставить результат заключенного JavaScript в строку или как текстовый узел. Преобразование этого в шаблон инкрементной DOM, который является просто функцией JavaScript, - это всего лишь вопрос преобразования элементов html в вызовы инкрементной DOM и оставления всего остального, что оказалось довольно простым.

Чтобы завершить все, наш помощник incdom передает свой блок в синтаксический анализатор, назначает полученный JavaScript функции с соответствующим именем на window (в данном случае window.tmpl_todo_item) и помещает его в тег script. Вот и все! На этом этапе мы можем писать шаблоны в нашей форме «встроенного JavaScript» и в полной мере использовать инкрементную DOM в наших представлениях Marionette.

Заворачивать

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

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