Фабрика виджетов — способ организации клиентского кода, который отлично вписывается в архитектуру multi-page application (MPA).
В статье будет рассмотрено архитектурное решение, которое позволит оптимизировать загрузку скриптов, разделить код на виджеты и упростит передачу данных на клиент со страницы (при серверном рендеринге).
Виджетами будут называться компоненты (или контейнеры компонентов), точкой инициализации которых будет DOM. И в которые можно будет передать данные из шаблона.А сейчас обо всем последовательно.
Концепция
На странице размещаются информация о вызываемых виджетах (имя виджета, данные для него).
Логика реализации будет в основном и единственном подключаемом бандле, состоящем из:
- Скриптов которые выполняются на большинстве страниц нашего приложения
- Код для всех common-виджетов
Здесь и далее под common-виджетами будут пониматься те виджеты, которые чаще всего необходимы в приложении, например: навигация, поиск.
- Хеш-список всех lazy-виджетов*, содержащий их имена и пути к реализации
Здесь и далее под lazy-виджетами будут пониматься те виджеты, которые нужны в редких случаях. Забегая вперёд, такие виджеты будут загружаться динамически, например: галерея, маркетинговые окна.
- Непосредственно код фабрики виджетов
Чтобы лучше понять концепцию, разберем пример реализации.
Реализация
Сама реализация архитектуры довольно проста, с ее вариантом можно ознакомиться на гитхабе. В ее основу лег Webpack и его динамический импорт.
Далее пробежимся по основным логическим пунктам:
- На странице размещаются тег script, содержащий имя виджета, данные в виде JSON
<script type="application/widget+json"> { "widget": "TesLazyWidget", "data": { "1": 1 } } </script>
- Подключается entry.js
- Выполняются корнер-скрипты
- Фабрика виджетов находит все теги script
initWidgets($('script[type="application/widget+json"]'));
- Разбор JSON
data = $.parseJSON(script.innerHTML);
- Если это common-виджет, то инициализирует и запоминает его
widget = new Widget(data);
- Если это lazy-виджет то загружает его
loaderWidget().then(createWidget);
- Стартует все запомненные common-виджеты
for (let i = 0; i < this.widgets.length; i++) { this.widgets[i].start(); }
- Инициализирует и стартует загруженные lazy-виджеты
const widget = new Widget(data); widget.start();
Реализация схематично.
Основные преимущества данной архитектуры
Увеличение скорости загрузки страниц
Основной бандл содержит только критические скрипты, основная функциональность. Дополнительная логика будет загружена динамически. В таком бандле будет высокий процент покрытия кода (code coverage). Это уменьшает его размер страницы, и как следствие повышает производительность.
Например, сразу загрузится меню и информация о пользователе, а динамически загрузится рекламное предложение, галерея картинок и дополнительные визуальные эффекты.
Это хорошая альтернатива роутингу
Нет необходимости создавать и настраивать роуты и загружать нужные скрипты в зависимости от урлов или шаблонов. Не нужно поддерживать сложные зависимости, а следовательно уменьшается риск ошибки.
Упрощенный способ передачи данных на клиент
Просто отрендерив JSON на странице, уже на этапе разбора данные попадают на клиент, без необходимости дополнительных AJAX-запросов.
<script type="application/widget+json">
{ "widget": "ActionBar"
, "data": {
"isPublic": true,
"id": "{{ id }}",
"items" : [{
"title": "Edit",
"iconLeft": "edit"
}]
}
}
</script>
Уменьшение дублирования кода
Переиспользовать виджет? Легко! Например, на странице нужно реализовать несколько списков новостей с фильтрами, подгрузкой и прочей интерактивной логикой. За реализацию этого функционала будет отвечать виджет NewsList. Аналогично html-тегам, достаточно просто вставить в шаблон вызов этого виджета столько, сколько нужно списков, и везде требуется.
<script type="application/widget+json">
{
"widget": "NewsList",
"data": {
"contentId": "business"
}
}
</script>
<script type="application/widget+json">
{
"widget": "NewsList",
"data": {
"contentId": "policy"
}
}
</script>
Код становится читабельнее и понятнее
Фабрика виджетов формализует правила написания кода, что в свою очередь создает четкую структуру инициализации и выполнения скриптов. В этом подходе цепочка вызова виджетов линейна. Логика каждого из них инкапсулирована, и, как результат, — меньше непредвиденных последствий от изменения кода, меньше сумбура в проекте, большая гибкость системы.
Отличный способ организации кода, для “старых” проектов
Когда в приложении все уже написано, но без особой идеи. Постоянное ощущение бардака не покидает. И в проекте сплошь и рядом инлайн скрипты
<script>
require(['jquery', 'selectBoxIt'], function ($) {
$('#itemId_selector').selectBoxIt();
var $form = $('#savepost');
……..
$('#skip').click(function () {
$form.submit();
});
});
</script>
то нужно лишь создать виджет и перенести этот код в него. Таким образом фабрика виджетов — это отличный способ перейти на компонентный подход.
Плюс ко всему можно сделать автоматическую генерацию списка виджетов, как, например, тут. Это упростит создание виджета до создания каталога с его именем и файла с его реализацией, что, собственно, тоже можно автоматизировать.
Вместо заключения
В итоге в архитектуру MPA фабрика виджетов отлично вписывается. Формализует код, оптимизирует загрузку и дает четкие и удобные правила по использованию.
Комментарии (2)
novoxudonoser
07.10.2017 02:19Хм, это всё классно. Расово одобряю, особенно за такой мелкий нюанс как чёрные рабочие на заводе на пикче.
geleont
Мы использовали подобный подход на одном из проектов. На самом деле показывает очень хорошие результаты. Нам удалось снизить объем загружаемого кода более чем на 30%, а на некоторых страницах даже больше. И это без больших вложений в рефакторинг.