Фабрика виджетов — способ организации клиентского кода, который отлично вписывается в архитектуру 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 фабрика виджетов отлично вписывается. Формализует код, оптимизирует загрузку и дает четкие и удобные правила по использованию.
Автор: Дмитрий Кривега