Фабрика виджетов для MPA

    image

    Фабрика виджетов — способ организации клиентского кода, который отлично вписывается в архитектуру multi-page application (MPA).

    В статье будет рассмотрено архитектурное решение, которое позволит оптимизировать загрузку скриптов, разделить код на виджеты и упростит передачу данных на клиент со страницы (при серверном рендеринге).
    Виджетами будут называться компоненты (или контейнеры компонентов), точкой инициализации которых будет DOM. И в которые можно будет передать данные из шаблона.
    А сейчас обо всем последовательно.

    Концепция


    На странице размещаются информация о вызываемых виджетах (имя виджета, данные для него).

    Логика реализации будет в основном и единственном подключаемом бандле, состоящем из:

    1. Скриптов которые выполняются на большинстве страниц нашего приложения
    2. Код для всех common-виджетов
      Здесь и далее под common-виджетами будут пониматься те виджеты, которые чаще всего необходимы в приложении, например: навигация, поиск.
    3. Хеш-список всех lazy-виджетов*, содержащий их имена и пути к реализации
      Здесь и далее под lazy-виджетами будут пониматься те виджеты, которые нужны в редких случаях. Забегая вперёд, такие виджеты будут загружаться динамически, например: галерея, маркетинговые окна.
    4. Непосредственно код фабрики виджетов

    Чтобы лучше понять концепцию, разберем пример реализации.

    Реализация


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

    Далее пробежимся по основным логическим пунктам:

    1. На странице размещаются тег script, содержащий имя виджета, данные в виде JSON

      <script type="application/widget+json">
       {
           "widget": "TesLazyWidget",
            "data": {
                "1": 1
            }
         }
       </script>
      
    2. Подключается entry.js
    3. Выполняются корнер-скрипты
    4. Фабрика виджетов находит все теги script

      initWidgets($('script[type="application/widget+json"]'));
      
    5. Разбор JSON

      data = $.parseJSON(script.innerHTML);
      
    6. Если это common-виджет, то инициализирует и запоминает его

      widget = new Widget(data);
      
    7. Если это lazy-виджет то загружает его

      loaderWidget().then(createWidget);
      
    8. Стартует все запомненные common-виджеты

      for (let i = 0; i < this.widgets.length; i++) {
        this.widgets[i].start();
      }
      
    9. Инициализирует и стартует загруженные lazy-виджеты

      const widget = new Widget(data);
      widget.start();
      

    Реализация схематично.

    image

    Основные преимущества данной архитектуры


    Увеличение скорости загрузки страниц


    Основной бандл содержит только критические скрипты, основная функциональность. Дополнительная логика будет загружена динамически. В таком бандле будет высокий процент покрытия кода (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

      0
      Мы использовали подобный подход на одном из проектов. На самом деле показывает очень хорошие результаты. Нам удалось снизить объем загружаемого кода более чем на 30%, а на некоторых страницах даже больше. И это без больших вложений в рефакторинг.
        0
        Хм, это всё классно. Расово одобряю, особенно за такой мелкий нюанс как чёрные рабочие на заводе на пикче.

        Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

        Самое читаемое