Использование WebAssetsManager Joomla 4 и добавление собственных пресетов с помощью плагина

от автора

В мире фронтенда многие ресурсы (ассеты) связаны между собой. В Joomla никогда не было простого способа указать эту связь, но Joomla 4 изменила эту ситуацию, введя концепцию Web Assets. Управление JavaScript и CSS в Joomla значительно упростилось, благодаря классу WebAssetManager. Есть замечательная статья Как правильно подключать JavaScript и CSS в Joomla 4, в которой подробно и с примерами кода рассказывается об этой концепции и её применении. Рекомендую ознакомиться с ней для более полного понимания сути этой статьи.

Однако, в процессе разработки собственных решений я столкнулся с проблемой. Решение её в данной заметке будет небольшим дополнением к вышеупомянутой статье.

Задача

Задача заключается в том, чтобы подключить в общий реестр скриптов, стилей и пресетов js-библиотеку (в моём случае — Swiper.js) таким образом, чтобы она была доступна из самых разных мест Joomla 4 и её можно было использовать для разных расширений (возможно не только моих), автономно её обновлять.

Например: js-библиотеку подключает плагин, а использовать её может и модуль, и компонент, и контент-плагин, и плагин поля.

Образцом поведения является встроенный в Joomla 4 Bootstrap 5. Он поддерживает модульное подключение с автоматическим подключением всех зависимостей, которые описаны в файле media/vendor/joomla.asset.json.

Joomla 4 будет искать определение ассетов автоматически во время выполнения в следующем порядке:

А затем загрузит их в реестр известных JavaScript и CSS файлов.

Редактировать файлы ядра — нельзя (хотя, к сожалению, это распространено среди разработчиков, желающих быстро решить какую-нибудь задачу). Значит нам нужен плагин, которым можно «подлезть» на этапе формирования реестра ассетов и добавить в него нужные нам веб ассеты. Это решение было очевидно сразу.

Однако, все примеры создания и подключения скриптов, стилей и пресетов предполагали, что регистрируется и начинает использоваться ассет в одном и том же месте. Попытки вынести подключение ассета в плагин, а использовать ассет в модуле через $wa->usePreset, $wa->useScript приводили к ошибке "There is no "swiper-bundle" asset of a "script" type in the registry."

Для того, чтобы разобраться в работе системы я начал анализировать код «коробочных» расширений.

Пример из системного плагина jooally — плагина версии для слабовидящих

<?php /**  * @package     Joomla.Plugin  * @subpackage  System.jooa11y  *  * @copyright   (C) 2021 Open Source Matters, Inc. <https://www.joomla.org>  * @license     GNU General Public License version 2 or later; see LICENSE.txt  */  defined('_JEXEC') or die;  use Joomla\CMS\Application\CMSApplicationInterface; use Joomla\CMS\Factory; use Joomla\CMS\Language\Text; use Joomla\CMS\Plugin\CMSPlugin; use Joomla\Event\SubscriberInterface;  /**  * Jooa11y plugin to add an accessibility checker  *  * @since  4.1.0  */ class PlgSystemJooa11y extends CMSPlugin implements SubscriberInterface { /**  * Application object.  *  * @var    CMSApplicationInterface  * @since  4.1.0  */ protected $app;  /**  * Affects constructor behavior. If true, language files will be loaded automatically.  *  * @var    boolean  * @since  4.1.0  */ protected $autoloadLanguage = true;  /**  * Subscribe to certain events  *  * @return string[]  An array of event mappings  *  * @since 4.1.0  *  * @throws Exception  */ public static function getSubscribedEvents(): array { $mapping = [];  // Срабатываем только на фронте if (Factory::getApplication()->isClient('site')) {     /**      * Срабатываем на событие onBeforeCompileHead и вызываем функцию initJooa11y.      * Можно по старинке упростить и использовать public function onBeforeCompileHead()      */ $mapping['onBeforeCompileHead'] = 'initJooa11y'; }  return $mapping; }   }

Плагин срабатывает на событие onBeforeCompileHead. На этом событии возможно обработать всё, что составляет содержимое <head> страницы в Joomla 4: title, мета-теги и т.д.

В самой функции initJooa11y идут проверки на CLI, REST API — чтобы плагин срабатывал только при выводе HTML. В самом конце функции происходит регистрация и добавление скриптов и стилей для функционирования версии для слабовидящих:

// Get the document object. $document = $this->app->getDocument();      /** @var Joomla\CMS\WebAsset\WebAssetManager $wa*/ $wa = $document->getWebAssetManager();  $wa->getRegistry()->addRegistryFile('media/plg_system_jooa11y/joomla.asset.json');  $wa->useScript('plg_system_jooa11y.jooa11y') ->useStyle('plg_system_jooa11y.jooa11y');

В файле media/plg_system_jooa11y/joomla.asset.json описываются файлы и их зависимости для работы плагина. Обратите внимание на то, что сразу после регистрации ассета начинается его использование — useScript и useStyle.

Но такое поведение меня не устраивало, так как хотелось достичь большей универсальности и автономности элементов. Помогли собственные поиски и отклик Joomla-сообщества. Итак….

Как добавить собственные js и css в Joomla 4 и сделать их доступными глобально?

Создаём плагин группы system. Официальная документация для разработчиков Joomla 4 по созданию плагинов. Можно по старинке использовать методы вида public function onBeforeCompileHead(). В таком случае плагин можно будет использовать как в Joomla 3, так и в Joomla 4. А можно использовать новый способ, предложенный в Joomla 4.1.

defined('_JEXEC') or die; use Joomla\CMS\Factory; use Joomla\CMS\Plugin\CMSPlugin; use Joomla\Event\SubscriberInterface;  class PlgSystemWtjswiper extends CMSPlugin implements SubscriberInterface { /**  * Subscribe to certain events  *  * @return string[]  An array of event mappings  *  * @since 4.1.0  *  * @throws Exception  */ public static function getSubscribedEvents(): array { $mapping = [];  // Only trigger in frontend if (Factory::getApplication()->isClient('site')) { $mapping['onAfterInitialise'] = 'addSwiperPreset'; }  return $mapping; }   }

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

Самым важным оказалось найти правильное системное событие, на этапе которого есть возможность добавить свои веб-ассеты глобально в Joomla 4 Web Assets Manager. Таким событием оказалось onAfterInitialise. В моём случае попытки зарегистрировать веб-ассет на событии onBeforeCompileHead приводили к тому, что joomla.asset.json добавлялся в реестр ассетов, но не парсился. Что равносильно тому, что его не существует.

Следующий код позволяет зарегистрировать javascript-библиотеку

public function addSwiperPreset() { // Only trigger in frontend if (Factory::getApplication()->isClient('site')) { /** @var Joomla\CMS\WebAsset\WebAssetManager $wa*/ $wa = Factory::getDocument()->getWebAssetManager(); $wa->getRegistry()->addRegistryFile('media/plg_system_wtjswiper/joomla.asset.json'); return true; } }

Обратите внимание на метод addRegistryFile(), где указывается путь к файлу joomla.assets.json от корня сайта. Так же существует прокси-метод addExtensionRegistryFile(string $name), который принимает в качестве параметра системное имя расширения, по которому доступны его веб-ассеты в папке media: com_content, plg_system_jooally и т.д. Тогда подключаться будет файл ‘media/com_content/joomla.asset.json’ и ‘media/plg_system_jooally/joomla.asset.json’ соответственно.

Содержимое файла joomla.assets.json

{   "$schema": "https://developer.joomla.org/schemas/json-schema/web_assets.json",   "name": "swiper",   "version": "8.2.4",   "description": "Swiper js library",   "license": "GPL-2.0-or-later",   "assets": [     {       "name": "swiper-bundle",       "type": "script",       "uri": "plg_system_wtjswiper/swiper-bundle.min.js",       "attributes": {         "defer": true       },       "package": "swiper",       "version": "8.2.4"     },     {       "name": "swiper-bundle",       "type": "style",       "uri": "plg_system_wtjswiper/swiper-bundle.min.css",       "package": "swiper",       "version": "8.2.4"     },     {       "name": "swiper-bundle",       "type": "preset",       "uri": "",       "dependencies": [         "swiper-bundle#style",         "swiper-bundle#script"       ]     }   ] }

Uri в json в зависимости от типа ассета автоматически дополняется ‘js’ или ‘css’. Если вы подключаете файл media/plg_system_wtjswiper/css/swiper-bundle.min.css, то uri файла в joomla.assets.json будет plg_system_wtjswiper/swiper-bundle.min.css

Такой же принцип использовался раньше в Joomla 3 при подключении ресурсов с помощью HTMLHelper (ex. JHTML).

Так же полезные ресурсы

Ресурсы сообщества:

Telegram:


ссылка на оригинал статьи https://habr.com/ru/post/672020/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *