QU

универсальный загрузчик
ассетов для 1С-Битрикс

Описание модуля

Модуль Qu (devnseo.qu) — это инструмент для расширенного управления загрузкой JavaScript, CSS и link в проектах на платформе 1С-Битрикс.

  • Управляйте атрибутами async, defer, media и т.д. для каждого ресурса.
  • Используйте адаптеры для BX.ready с определением композитного режима.
  • Регистрируйте ассеты в едином реестре без вмешательства в стандартный Bitrix\Main\Page\Asset.

Модуль изначально был разработан как ядро для загрузки Qu.js (https://github.com/qujs-dev/core), но может использоваться независимо.

Установка

Стандартная установка через Маркетплейс:

  • Перейдите в раздел «Marketplace» → «Каталог решений».
  • Найдите модуль Qu расширенная загрузка ассетов async/defer/media (devnseo.qu) и нажмите «Установить».

Настройка

Перейдите в «Настройки» → «Настройки продукта» → «Настройки модулей» → вкладка «Qu».

Доступные опции (для каждого сайта отдельно):

Qu
autoload_inline_loader Всегда подключать inline-загрузчик Que.js (необходим для работы адаптера Qu).
autoload_core_qu Автоматически подключать основной qu.js.
Адаптеры инициализации BX
bx_ready_que Адаптер для Que (bx:ready и bx:composite).
bx_ready_on Адаптер onBxReady (bx:ready + bx:composite + window.onBxComposite).
bx_ready_min Минимальный адаптер – только BX.ready.
Подключение ассетов
custom_assets Всегда подключать ассеты на страницу, имена файлов, через запятую или с новой строки.
asset_source_cdn Использовать CDN для ассетов.
css_preload_fallback Использовать link preload + onerror вместо link stylesheet для CSS.
asset_use_bitrix_asset Подключать ассеты через стандартный Bitrix\Main\Page\Asset.
asset_collect_only Только регистрировать ассеты в реестре модуля, не подключать.
Группировка и минификация
enable_group_build Объединять файлы групп в бандлы (минификация). Включает сборку групп в один минифицированный CSS и JS файл (только локальные файлы).
enable_group_minify Минифицировать бандлы (CSS/JS). Если выключено, бандлы будут объединены, но без сжатия.
Дебаг
bx_ready_tests Включить тестовые скрипты для отладки адаптеров.
enable_head_debug_log Записывать отладочные логи в AddMessage2Log.
Капча
captcha_enabled Включить капчу (Y/N).
captcha_provider Провайдер: yandex или google.
captcha_selector Селектор для определения формы (по умолчанию data-qu-captcha).
captcha_token_input Имя поля для токена (по умолчанию qu-captcha-token).
Yandex SmartCaptcha
yandex_smartcaptcha_site_key Site Key из консоли Yandex Cloud.
yandex_smartcaptcha_secret_key Secret Key (приватный ключ).
Google reCAPTCHA v3
google_recaptcha_site_key Site Key из админки Google.
google_recaptcha_secret_key Secret Key.
google_recaptcha_min_score Минимальный балл (0.0–1.0), по умолчанию 0.5.

API

Как работает модуль с ассетами:

Модуль использует стандартный механизм Bitrix\Main\Page\Asset (D7) для подключения ресурсов, но поверх него надстраивает собственный реестр и систему конфигурации.

  • Все файлы описываются в PHP-конфигах.
  • Модуль регистрирует ресурсы с указанием атрибутов (async, defer, media и т.д.).
  • При подключении через Assets::include() он решает, откуда брать файл (локально или CDN), применяет fallback (если включён) и добавляет в DOM через стандартный Asset.
  • Если включена опция asset_use_bitrix_asset, добавление идёт через Bitrix\Main\Page\Asset. В противном случае (или для link и inline-кода) используется добавление через $APPLICATION‑>AddHeadString(), что даёт больше гибкости и позволяет вставлять ресурсы в любое место head.
  • Режим asset_collect_only добавляет ресурсы только во внутренний реестр модуля, не выводя их в DOM.

\devNseo\Qu\Assets

Подключает набор ресурсов по имени (из конфигурации).

Assets::include(string $name, string $version = 'latest'): bool

\devNseo\Qu\Assets::include('qu');
\devNseo\Qu\Assets::include('qu', '1.0.7');

Возвращает конфигурацию ассета.

Assets::get(string $name, string $version = 'latest'): array

$config = \devNseo\Qu\Assets::get('qu');
print_r($config);

\devNseo\Qu\Head

Head::script

Добавляет внешний скрипт в <head>.

Head::script(string $id, string $src, array $attrs = []): bool

Head::script('my-script', '/local/js/my.js', ['async' => true]);

Head::style

Добавляет CSS-файл.

Head::style(string $id, string $href, array $attrs = []): bool

\devNseo\Qu\Head::style(
    'main-style',
    '/local/css/main.css',
    [
        'media' => 'print',
        'onload' => "this.media='all'"
    ]
);

Head::link

Добавляет произвольный link с возможностью указать место вставки.

Head::link(string $id, string $href, array $attrs = [], ?string $location = null): bool
// preconnect
\devNseo\Qu\Head::link(
    'preconnect-google',
    'https://fonts.googleapis.com',
    ['rel' => 'preconnect', 'crossorigin' => ''],
    \Bitrix\Main\Page\AssetLocation::BEFORE_CSS
);

// прелоад картинок
\devNseo\Qu\Head::link(
    'hero-image-desktop',
    '/local/images/hero-desktop.webp',
    [
        'rel' => 'preload',
        'as' => 'image',
        'fetchpriority' => 'high',
        'media' => '(min-width: 768px)',
    ],
    \Bitrix\Main\Page\AssetLocation::BEFORE_CSS
);

\devNseo\Qu\Head::link(
    'hero-image-preload',
    '/local/images/hero-1200.webp',
    [
        'rel' => 'preload',
        'as' => 'image',
        'fetchpriority' => 'high',
        'imagesrcset' => '/local/images/hero-400.webp 400w, /local/images/hero-800.webp 800w, /local/images/hero-1200.webp 1200w',
        'imagesizes' => '(max-width: 600px) 100vw, 50vw',
        'type' => 'image/webp',
    ],
    \Bitrix\Main\Page\AssetLocation::BEFORE_CSS
);

Head::inline

Добавляет inline-код (script или style).

Пример для JS:

Head::inline(string $id, string $content, string $type = 'js', array $attrs = [], ?string $location = null, bool $force = false): bool

\devNseo\Qu\Head::inline(
    'my-inline-script',
    'console.log("Hello");',
    'js',
    ['data-skip-moving' => 'true'],
    \Bitrix\Main\Page\AssetLocation::BEFORE_CSS
);

Пример для CSS:

\devNseo\Qu\Head::inline(
    'my-inline-style',
    'body { background: #f0f0f0; }',
    'css'
);

Head::has

Проверяет, зарегистрирован ли ресурс с таким ID.

Head::has(string $id): bool

if (\devNseo\Qu\Head::has('my-script')) {
    // уже зарегистрирован
} else {
    // можно добавить
}

Head::all

Возвращает все зарегистрированные ресурсы.

Head::all(): array
    
$assets = \devNseo\Qu\Head::all();
foreach ($assets as $id => $data) {
    echo "ID: { $id}\n";
}

\devNseo\Qu\Assets

Assets::getRequestedAssets()

Возвращает массив ассетов, запрошенных через Assets::include() за время выполнения страницы. Ключ – имя ассета, значение – запрошенная версия.

Assets::getRequestedAssets(): array

$requested = \devNseo\Qu\Assets::getRequestedAssets();
// ['qu' => 'latest', 'my-lib' => '1.2']

Assets::files()

Возвращает список файлов для указанного ассета с учётом источника (CDN/local) и текущих настроек. Полезно для ручной обработки, когда включён режим asset_collect_only.

Assets::files(string $name, string $version = 'latest'): array

$files = \devNseo\Qu\Assets::files('qu', '1.0.7');
foreach ($files as $file) {
    // $file содержит: type, local, cdn, attrs, location, order и др.
}

Пример: кастомный вывод на Epilog при asset_collect_only = Y

Если в настройках включена опция asset_collect_only, модуль не выводит ассеты автоматически. Вы можете получить все запрошенные файлы и вывести их самостоятельно, например, в OnEpilog:

use devNseo\Qu\Assets;

// В обработчике OnEpilog
$requested = Assets::getRequestedAssets();
foreach ($requested as $name => $version) {
    $files = Assets::files($name, $version);
    foreach ($files as $file) {
        if ($file['type'] === 'style') {
            echo '';
        } elseif ($file['type'] === 'script') {
            echo '';
        } elseif ($file['type'] === 'inline') {
            echo '';
        } elseif ($file['type'] === 'link') {
            echo '';
        }
    }
}

Такой подход даёт полный контроль над выводом, сохраняя всю логику выбора источника и fallback, заложенную в конфигурации ассетов.


\devNseo\Qu\Captcha

Класс для проверки токенов капчи с учётом выбранного провайдера (Yandex SmartCaptcha или Google reCAPTCHA v3). Все методы статические.

Captcha::verify

Проверяет токен, переданный из формы. Возвращает массив с ключами:

  • success – bool, результат проверки.
  • score – float|null, балл (только для Google).
  • error – string|null, описание ошибки.
Captcha::verify(string $token, ?string $action = null): array

// Пример в обработчике формы
$token = $_POST['qu-captcha-token'] ?? '';
$result = \devNseo\Qu\Captcha::verify($token);

if ($result['success']) {
    // капча пройдена
} else {
    // ошибка: $result['error']
}

Для Google reCAPTCHA можно передать ожидаемое действие ($action) для дополнительной проверки.

Captcha::isEnabled

Проверяет, включена ли капча и настроены ли ключи для текущего провайдера.

Captcha::isEnabled(): bool

if (\devNseo\Qu\Captcha::isEnabled()) {
    // капча активна
}

Captcha::getSiteKey

Возвращает Site Key (публичный ключ) для текущего провайдера. Используется для инициализации на клиентской стороне (например, если вы подключаете капчу вручную).

Captcha::getSiteKey(): string

$siteKey = \devNseo\Qu\Captcha::getSiteKey();

Важно: Ассет captcha-init подключается автоматически, если в настройках включена опция captcha_enabled = Y. Ручной вызов Assets::include('captcha-init') не требуется, если вы используете автоматическую инициализацию.

Конфигурация ассетов

Стандартные ассеты описываются в PHP-файлах в папке /config/ внутри модуля. Каждый файл возвращает массив с конфигурацией.

Структура конфига:

  • aliases — псевдонимы версий (например, latest → 1.0.7)
  • versions — список версий с описанием файлов и зависимостей

Для объединения файлов в бандлы в конфиге ассета можно указать следующие параметры (подробнее – в разделе «Группы и бандлы»):

  • group – имя группы (файлы с одинаковым именем собираются в один бандл).
  • group_location – место вставки бандла (например, AssetLocation::BEFORE_CSS).
  • group_attrs – атрибуты для тегов бандла (отдельно для CSS и JS).
  • bundle_name – кастомное имя файла бандла (строка, массив или true).
  • order – порядок загрузки (меньше – раньше), по умолчанию у всех 100.

Параметры файла в версии:

Ключ является свойством id у элемента в DOM.

  • type — тип ресурса: script, style, link, inline
  • local — путь к локальному файлу
  • cdn — путь к файлу на CDN
  • fallback — включить подгрузку локальной копии при недоступности CDN. Эксперементально, есть смысл в основном для js, css фалбек возможен только для link preload.
  • attrs — дополнительные HTML-атрибуты
  • location — место вставки (для link и inline)
  • deps — список зависимостей (имена файлов конфигурации других ассетов)
  • cache_buster — включить/выключить добавление версии (?v=filemtime) к URL файла. Может быть true/false или null (наследуется от ассета). По умолчанию false.
  • order — порядок загрузки (меньше – раньше). Если не указан, наследуется от ассета или группы. По умолчанию 100.

Кеш-бустер (cache_buster)

Для локальных файлов модуль может автоматически добавлять к URL параметр ?v=filemtime, чтобы обновлять кеш браузера при изменении файла. Это поведение управляется параметром cache_buster.

Параметр может быть указан на двух уровнях:

  • На уровне файла — в конфигурации конкретного файла: 'cache_buster' => true или false.
  • На уровне ассета — в корне конфига: 'cache_buster' => true (тогда он применяется ко всем файлам ассета, если у них не задан свой параметр).

Если cache_buster не указан нигде, считается false (кеш-бустер отключён).

// Пример: включение cache_buster для всего ассета
return [
    'cache_buster' => true,
    'aliases' => [...],
    'versions' => [
        '1.0' => [
            'files' => [
                'my-css' => [
                    'type' => 'style',
                    'local' => '/local/css/main.css',
                    // cache_buster унаследуется от ассета (true)
                ],
                'my-js' => [
                    'type' => 'script',
                    'local' => '/local/js/main.js',
                    'cache_buster' => false, // отключаем для этого файла
                ],
            ],
        ],
    ],
];

Для бандлов (групп) с кастомным bundle_name кеш-бустер добавляется автоматически через ?v=filemtime.


Пример конфига qu.php:

<?php
return [
    'aliases' => [
        'latest' => '1.2.8',
        '1' => '1.2.8',
    ],
    'versions' => [
        '1.2.8' => [
            'deps' => [
                'qu.inline.loader:latest'
            ],
            'files' => [
                'qu-css' => [
                    'type' => 'style',
                    'local' => '/bitrix/js/devnseo/qu/core/1.2.8/css/qu.min.css',
                    'cdn' => 'https://cdn.jsdelivr.net/gh/qujs-dev/core@1.2.8/css/qu.min.css',
                    'fallback' => true,
                    'attrs' => [
                        'media' => 'print',
                        'onload' => "this.media='all'; this.onload=null;",
                    ],
                ],
                'qu-js' => [
                    'type' => 'script',
                    'local' => '/bitrix/js/devnseo/qu/core/1.2.8/qu.min.js',
                    'cdn' => 'https://cdn.jsdelivr.net/gh/qujs-dev/core@1.2.8/qu.min.js',
                    'fallback' => true,
                    'attrs' => ['async' => true],
                ],
            ],
        ],
    ],
];

Для объединения файлов в бандлы смотрите раздел «Группы и бандлы».

Для переопределения конфигураций создавайте файлы в директории:

  • /local/php_interface/qu/common/ — для всех сайтов
  • /local/php_interface/qu/SITE_ID/ — для конкретного сайта

После создания файла ассет будет доступен через \devNseo\Qu\Assets::include('file_name').

⚠️ Внимание!

Ключ в массиве 'files' (например, 'qu-css') — это ID, который получит тег в DOM. Убедитесь, что ID уникальны в рамках проекта. Наименование файла не гарантирует уникальность ID — всегда задавайте его явно.

Регистрация из другого модуля

OnQuAssetsBuild

Зарегистрировать ассет из другого модуля.

RegisterModuleDependences(
    'devnseo.qu',
    'OnQuAssetsBuild',
    'my.module',
    '\\MyNamespace\\Handler',
    'onQuAssetsBuild'
);

Класс обработчик

<?php
namespace MyNamespace;

class Handler
{
    public static function onQuAssetsBuild(): array
    {
        return [
            'name' => [
                'aliases' => [
                    'latest' => '1.0',
                    '1' => '1.0',
                ],
                'versions' => [
                    '1.0' => [
                        'deps' => ['qu:1'],
                        'files' => [
                            'name-inline-css' => [
                                'type' => 'inline',
                                'inlineType' => 'css',
                                'content' => '.qu-test{display:block}',
                                'attrs' => [],
                            ],
                        ],
                    ],
                ],
            ],
        ];
    }
}

Приоритеты конфигурации ассетов (полная замена)

При загрузке ассета через Assets::include('name') конфигурация собирается из трёх источников в порядке возрастания приоритета:

  1. Базовый конфиг

    • Файл: /config/{name}.php внутри модуля Qu.
    • Загружается первым, если существует.
  2. Событие OnQuAssetsBuild

    • Задаётся другими модулями через событие OnQuAssetsBuild.
    • Если обработчик события возвращает массив с ключом {name}, этот массив полностью заменяет базовый конфиг для данного ассета.
    • Базовый конфиг игнорируется.
  3. Оверрайд

    • Файлы:

      • /local/php_interface/qu/common/{name}.php – общий для всех сайтов.
      • /local/php_interface/qu/{SITE_ID}/{name}.php – для конкретного сайта.
    • Если оверрайд существует, он полностью заменяет всю конфигурацию (базовый конфиг и событие игнорируются).
    • Приоритет: сайтовый оверрайд имеет более высокий приоритет, чем общий.

Слияние конфигураций (merge_original)

По умолчанию оверрайд полностью заменяет конфигурацию ассета. Если вы хотите объединить оверрайд с базовым конфигом и данными от событий, добавьте в оверрайд-файл ключ 'merge_original' => true:

// /local/php_interface/qu/common/my-lib.php
return [
    'merge_original' => true,  // включить слияние
    // остальные параметры будут объединены рекурсивно
    'group' => 'libs-group',
    'group_location' => \Bitrix\Main\Page\AssetLocation::BEFORE_CSS,
    //'order' => 400,
    'group_attrs' => [
        'css' => [
            'media' => 'print', 'onload' => "this.media='all';"
        ],
        'js' => ['async' => true],
    ],
    'bundle_name' => 'common',
    
    'versions' => [
        '1.0' => [
            'files' => [
                'my-lib-js' => [
                    'attrs' => ['async' => true, 'defer' => true],
                ],
            ],
        ],
    ],
];

При merge_original = true оверрайд будет рекурсивно объединён с базовым конфигом и данными от события OnQuAssetsBuild (если они есть). Если ключ merge_original отсутствует или равен false, оверрайд полностью заменяет всю конфигурацию (поведение по умолчанию).

Группы и бандлы

Чтобы уменьшить количество HTTP-запросов и сгруппировать редко-обновляемые файлы, вы можете объединить несколько CSS и/или JS файлов в один бандл. Для этого в конфигурации ассета используется ключ group.

Как настроить

  1. В конфиге ассета укажите имя группы (group). Все файлы с одинаковым именем группы будут собраны вместе.
  2. При загрузке страницы модуль собирает все файлы из каждой группы.
  3. Если в настройках модуля включена опция enable_group_build (см. таблицу настроек), для каждой группы создаётся:
    • один .css бандл (из всех CSS-файлов группы),
    • один .js бандл (из всех JS-файлов группы).
  4. Если дополнительно включена enable_group_minify, бандлы минифицируются (через библиотеку matthiasmullie/minify).
  5. Бандлы сохраняются в /upload/qu/. Пересборка происходит автоматически при изменении любого исходного файла (по filemtime). Если страницы сайта закешированы, кеш необходимо очистить, чтобы новая версия бандла отображалась корректно.

Параметры группы (указываются на уровне конфига ассета)

Параметр Тип Описание
group string Имя группы. Файлы из разных ассетов с одинаковым group попадут в один бандл.
group_location string Место вставки бандла (по умолчанию: \Bitrix\Main\Page\AssetLocation::BODY_END).
group_attrs array Атрибуты для тегов бандла. Может содержать два ключа: css и js. Пример: ['css' => ['media' => 'print'], 'js' => ['async' => true]].
bundle_name mixed Кастомное имя файла бандла. Возможные варианты:
- строка – будет добавлено расширение (.css, .js);
- массив с ключами css и js – для раздельных имён;
- true – использовать имя группы как основу ({group}.css / {group}.js);
- не указан – имя генерируется автоматически на основе хеша содержимого (например: group-libs-9c5568214f723bb4f269179319d721fe.js)
order integer Порядок загрузки (меньше – раньше). Влияет на порядок вывода групп и отдельных файлов. По умолчанию у всех 100.

Пример конфига с группой

<?php
return [
    'group' => 'my-lib', // имя группы используется в наименовании бандла
    'group_location' => \Bitrix\Main\Page\AssetLocation::BEFORE_CSS,
    'order' => 1000, // как можно ниже в group_location... по умолчанию 100
    'group_attrs' => [
        'css' => [
            'media' => 'print', 'onload' => "this.media='all';"
        ],
        'js' => ['async' => true],
    ],
    
    // если НЕ указать bundle_name на каждый хеш (сумма filemtime всех файлов) будет создаваться отдельный файл типа group-my-lib-{hash}.css и group-my-lib-{hash}.js
    'bundle_name' => true, // получится my-lib.css?v={hash} и my-lib.js?v={hash}
    'bundle_name' => 'my-lib-bundle', // получится my-lib-bundle.css?v={hash} и my-lib-bundle.js?v={hash}
    'bundle_name' => [
        'css' => 'styles',
        'js' => 'scripts'
    ],  // получится styles.css?v={hash} и scripts.js?v={hash}
    
    'aliases' => ['latest' => '1.0'],
    'versions' => [
        '1.0' => [
            'deps' => [
                // чтобы ассеты добавлись в бандл они тоже должны иметь 'group' => 'my-lib'
                // ассеты будут подключаться в порядке как указано здесь, а далее файлы внутри ассета сортироваться между собой и другими ассетами по order
                'asset_1',
                'asset_2'
            ],
            
            // дополнительные файлы к ассетам, но можно и без них
            'files' => [
                'my-lib-css' => [
                    'type' => 'style',
                    'local' => '/local/css/lib.css',
                ],
                'my-lib-js' => [
                    'type' => 'script',
                    'local' => '/local/js/lib.js',
                ],
            ],
        ],
    ],
];

При включённой опции enable_group_build файлы lib-css и lib-js, а также файлы ассетов из deps с атрибутом 'group' => 'my-lib' будут объединены в бандлы и подключены единым тегом.

Параметры: group_location, order, group_attrs, bundle_name достаточно указать один раз в одном из ассетов группы. При повторном указании, будет использоваться первый загруженный без перезаписи.

⚠️ Рекомендация!

Создайте отдельно файл ассет-бандла, например по наименованию группы my-lib.php, а в нем подключите через deps один раз необходимые в группе ассеты. Внутри каждого ассета для корректного добавления в бандл, необходим параметр 'group' => 'my-lib'.

На странице подключайте только ассет-группы, например \devNseo\Qu\Assets::include('my-lib');, все внутренности подтянутся в бандл через deps.

Обьеденение уже подключенных ассетов

Например вы используете модуль Liker, и еще какие-то стандартные ассеты qu.js из папки /config/ или подключенные через другие модули с помощью: OnQuAssetsBuild. И хотите добавить их в свою группу.

Расширяем подключаемый ассет /local/php_interface/qu/common/liker.php

<?php

return [
    'group' => 'my-lib',
    'merge_original' => true,
];

Настройки модуля

В административной панели (вкладка «Qu») доступны две опции, влияющие на группировку (см. таблицу настроек):

  • Объединять файлы групп в бандлы – включает/выключает сборку.
  • Минифицировать бандлы – включает/выключает сжатие CSS/JS внутри бандлов.

Важные замечания

  • Группировка работает только для локальных файлов (указанных в local). Файлы с CDN в бандлы не включаются.
  • Если какой-то файл из группы не удалось включить в бандл (например, из-за ошибки), он будет подключён отдельно.
  • При использовании кастомного bundle_name в URL бандла добавляется ?v=filemtime для обновления кеша браузера после пересборки.
  • Порядок вывода групп и отдельных файлов определяется параметром order (меньше – раньше).

Адаптеры BX.ready

Модуль предоставляет адаптеры для использования BX.ready в асинхронных сценариях (например, в скриптах с async или до загрузки ядра). Адаптеры подключаются в <head> с атрибутом data-skip-moving="true" и location="BEFORE_CSS", что гарантирует их выполнение до загрузки основных скриптов. Футер-адаптеры подписываются на события композита (onFrameDataReceived, onFrameDataRequestFail) и при получении ответа (или ошибке) устанавливают глобальный флаг window._QuBXCompositeReady и ответ композита кладут в window._QuBXCompositeData. Основной скрипт следит за этим флагом через интервал и генерирует событие/функцию. Расширенные адаптеры так же корректно определяют текущего пользователя в композитном режиме.

Глобальные переменные

Помимо флага композита, адаптеры также устанавливают глобальные переменные с данными. Эти переменные доступны после срабатывания события bx:composite.

Переменная Описание
window._QuBXCompositeReady Статус композита (возможные значения: undefined, 'disabled', 'error', 'ready').
window._QuBXCompositeData Данные ответа композита (объект JSON, полученный от сервера).
window._QuBXUserId ID текущего пользователя (из BX.message('USER_ID')).
window._QuBXUserIdOld ID предыдущего пользователя, если сменился на этом хите.
window._QuBXUserChange Флаг был ли изменен пользователь.
window._QuBXFirstVisit Флаг первое ли это посещение в этом браузере.
window._QuBXSessid Сессионный ключ (из BX.bitrix_sessid()).
window._QuBXSiteId ID сайта (из BX.message('SITE_ID')).

Расширенные адаптеры (основные)

Адаптер Событие API Описание
bitrix-ready-que bx:ready
bx:composite
Que(..., 'bx:ready')
Que(..., 'bx:composite')
для Que (qu.js)
bitrix-ready-on bx:ready
bx:composite
BX.ready
window.onBxComposite
без зависимостей
bitrix-ready-min - BX.ready минимальный адаптер

Упрощённые адаптеры (без ожидания ответа композита)

Проверяют только наличие window.frameCacheVars (включён ли композит), не дожидаясь ответа. Срабатывают сразу после BX.ready. Упрощенные адаптеры не отслеживают _QuBXUserId, _QuBXUserIdOld, _QuBXUserChange, _QuBXFirstVisit, _QuBXSessid, _QuBXSiteId. Вообщем смотрите исходники. Все адаптеры при необходимости можно переопределить.

Адаптер Событие API Описание
bitrix-ready-que-simple bx:ready Que(..., 'bx:ready') для Que (qu.js)
bitrix-ready-on-simple bx:ready window.onBxReady без зависимостей

Рекомендуется использовать только один адаптер (полный или упрощённый) в зависимости от ваших задач. Включение нескольких адаптеров одновременно может привести к дублированию событий и избыточной логике. Например, если вам достаточно знать, что BX.ready сработал и композит включён – используйте упрощённый адаптер. Если нужно дождаться вставки композитных блоков – используйте полный адаптер.

Возможные состояния window._QuBXCompositeReady

Состояние Событие
undefined Статус ещё не определён (адаптеры не отработали или композит ещё не обработан).
'disabled' Первый хит. Или композитный режим выключен на сайте
(frameCacheVars === undefined).
'error' Произошла ошибка при запросе к композиту (onFrameDataRequestFail).
'ready' Композит успешно отработал: блоки вставлены (или получен пустой ответ).

Примеры использования

bx-ready-que

Адаптер для Que + определение композита. Генерирует событие bx:ready и bx:composite.

Que(() => {
    console.log('BX.ready + some:event TODO');
}, ['bx:ready', 'some:event']);

Que(function(Qu, payload) {
    console.log(payload) // данные дублируются в глобальные переменные как в остальных адаптерах
    composite = window._QuBXCompositeReady;
    console.log('Композит режим', composite);
    console.log('Данные', window._QuBXCompositeData);
    
    if(window._QuBXUserChange) {
        console.log('Пользватель сменился', window._QuBXUserId, window._QuBXUserIdOld);
    }
}, 'bx:composite');

bx-ready-on

Независимый адаптер для BX.ready + определение композита. Генерирует событие bx:onready и добавляет onBxComposite(function(composite) { ... });.

// например гдето в async файле
BX.ready(function() {
    console.log('BX.ready минимальный');
});

onBxComposite(function(composite) { // composite видно только тем кто уже подписан, лучше смотреть глобал переменную для async
    composite = window._QuBXCompositeReady;
    console.log('Композитный режим:', composite);
    console.log('Данные', window._QuBXCompositeData);
});

bx-ready-min

Минимальный адаптер – только BX.ready, создает простую заглушку для использования в async.

BX.ready(function() {
    console.log('BX.ready минимальный');
});

Так как API битрикса меняется, не могу дать гарантии что работать будет на каждой версии. Я тестировал на 24.0.500 +. Сначала проверяем что есть dynamicBlocks вообще, потом интервал, на поздних версиях, например логика немного другая и core скрипт не учитывает кол-во элементов в dynamicBlocks.

Чтобы сделать bx-ready-on-simple.php по умолчанию достаточно указать его имя в настройках модуля в подключении ассетов custom_assets.

⚠️ Внимание!

Вложенность приводит к гонкам, из-за чего обычные адаптеры корректно не обрабатывают события, происходящие до их инициализации. А при использовании qu.js - есть кеширование событий.

CDN и fallback

Если вы используете внешние CDN, модуль позволит гибко управлять источником загрузки css/js. Опции добавлены в основном для удобства массового переключения.

Включение CDN-режима

CDN-режим включается в настройках модуля через параметр asset_source_cdn.

  • Если параметр установлен в Y – ассеты загружаются с CDN (если для них указан cdn-путь).
  • Если параметр установлен в N – используются локальные файлы (local-путь).

Параметры файла в конфигурации

Для каждого файла в конфигурации ассета можно указать:

  • local – путь к локальному файлу (относительно корня сайта).
  • cdn – путь к файлу на CDN (полный URL).
  • fallback – флаг (true/false), который определяет, нужно ли подгружать локальную копию, если CDN недоступен.

Как определяется выбор источника файла

При подключении ассета логика выбора источника следующая:

  1. Если CDN-режим включён (asset_source_cdn = Y):

    • используется путь из cdn, если он указан;
    • если cdn не указан, используется local.
  2. Если CDN-режим выключен:

    • используется local (если указан), иначе cdn.

Механизм fallback

Если для файла установлен флаг fallback = true и CDN-режим включён, то при загрузке ресурса с CDN добавляется обработчик ошибок (onerror):

Если CDN-файл не загрузился (например, сетевой сбой, CORS, 404), браузер автоматически подгружает локальную копию (local).

Это гарантирует, что даже при временных проблемах с CDN сайт останется работоспособным.

Особенности для CSS

Так как для CSS-файлов стандартный onerror у <link> не срабатывает, fallback реализован в зависимости от настройки css_preload_fallback:

  • Если включён (Y): используется техника preload + onerror. Браузер начинает загрузку CSS через <link rel="preload">, а в случае ошибки подгружает локальный файл. Указанный в конфиге как 'type' => 'style' становится 'preload'.
  • Если выключен (N): используется стандартный подход. Все атрибуты (media, onload и др.) вы указываете самостоятельно в секции attrs.

preload предпочтительнее для критических файлов рендеринга. На практике эти атрибуты можно и лучше задать прямо в конфиге.

Капча

Модуль поддерживает интеграцию с Yandex SmartCaptcha и Google reCAPTCHA v3. Капча подключается на стороне клиента через механизм ассетов и автоматически добавляет токен в указанное поле формы при отправке.

Настройка

В административной панели модуля (вкладка «Qu», секция «Настройки капчи») доступны следующие параметры (применяются для каждого сайта отдельно):

Параметр Описание
captcha_enabled Включить/выключить капчу (Y / N).
captcha_provider Провайдер: yandex или google.
captcha_selector Селектор (CSS или data-атрибут), по которому определяется форма с капчей. По умолчанию data-qu-captcha.
captcha_token_input Имя POST-поля, в которое будет помещён токен. По умолчанию qu-captcha-token.
Yandex SmartCaptcha
yandex_smartcaptcha_site_key Site Key (публичный ключ) из консоли Yandex Cloud.
yandex_smartcaptcha_secret_key Secret Key (приватный ключ) для проверки токена на сервере.
Google reCAPTCHA v3
google_recaptcha_site_key Site Key из админки Google reCAPTCHA.
google_recaptcha_secret_key Secret Key для проверки токена.
google_recaptcha_min_score Минимальный балл (от 0.0 до 1.0), по умолчанию 0.5. Рекомендуется 0.5.

Автоматическое подключение

Если captcha_enabled = Y, модуль автоматически подключает ассет captcha-init на всех страницах. Вам не нужно вызывать Assets::include() вручную – это происходит внутри обработчика OnBeforeProlog при условии, что капча включена.

Ассет captcha-init инициализирует выбранного провайдера на всех формах, соответствующих селектору captcha_selector (по умолчанию data-qu-captcha). Для инициализации используется библиотека Qu.libs (адаптеры для капчи поставляются отдельным пакетом). На страницу добавляется inline-скрипт, который подгружает необходимый провайдер (Yandex или Google) и привязывает его к формам.

Если по какой-то причине вам нужно отключить автоматическое подключение на конкретной странице, вы можете проверить условие в своём коде или использовать настройки модуля для конкретного сайта.

Проверка токена на сервере

Для проверки токена в обработчике формы используйте метод \devNseo\Qu\Captcha::verify($token, $action = null):

use devNseo\Qu\Captcha;

$token = $_POST['qu-captcha-token'] ?? '';
$result = Captcha::verify($token);

if ($result['success']) {
    // капча пройдена
} else {
    // ошибка: $result['error']
}

Для Google reCAPTCHA можно передать ожидаемое действие ($action), чтобы дополнительно проверить соответствие.

Важные замечания

  • Для корректной работы необходимо, чтобы на странице был подключён Que (qu.js) или inline-загрузчик (настройка autoload_inline_loader).
  • Автоматическая инициализация не добавляет обработчик на событие submit формы. Расширьте ассет капчи - чтобы включить по умолчанию выключено.
  • Для Yandex SmartCaptcha используется API https://smartcaptcha.yandexcloud.net/validate, для Google – https://www.google.com/recaptcha/api/siteverify.

Совместимость

  • PHP: версия 7.4 и выше
  • 1С-Битрикс: тестировал на 24.0.500 и выше
  • Композитный режим: +

Задать вопрос

Техническая поддержка бесплатных решений (а также помощь в установке/настройке) осуществляется на платной основе.

Поддержка платных решений:

  • Базовые консультации по работе модуля — бесплатно.
  • Любые доработки, кастомизация, помощь в настройке и интеграции — на платной основе.

Поддержка осуществляется: Пн-Пт с 18:00 до 21:00 по московскому времени (суббота, воскресенье и праздничные дни - выходные).

Время реагирования: в порядке живой очереди.

Обращаться по e-mail: info@devnseo.ru.

При обращении укажите:

  • Название модуля
  • Опишите проблему максимально подробно: шаги для воспроизведения, ожидаемый и фактический результат. Приложите скриншоты.
  • Адрес сайта
  • Доступы к админке (логин и пароль)
  • FTP или SFTP доступ (хост, логин, пароль и порт)