Перейти к содержанию

Менеджер ресурсов

В Grav 1.6 менеджер ресурсов был полностью переписан, чтобы предоставить более гибкий механизм управления ресурсами CSS и JavaScript в темах. Основное назначение менеджера ресурсов — упростить процесс добавления ресурсов из тем и плагинов, предоставляя расширенные возможности, такие как приоритет, а также сборку ресурсов, которую можно использовать для минификации, сжатия и встраивания ресурсов, чтобы уменьшить количество запросов браузера и общий размер ресурсов.

Он гораздо гибче и надёжнее, чем раньше. К тому же он заметно «чище» и проще для понимания, если начать разбираться в коде. Менеджер ресурсов доступен во всём Grav: к нему можно обращаться в хуках событий плагинов, а также напрямую в темах через вызовы Twig.

Предупреждение

Технические подробности: основной класс Assets был значительно упрощён и сокращён. Большая часть логики вынесена в 3 трейта. Тестовый трейт содержит функции, в основном используемые в нашем наборе тестов; трейт утилит содержит методы, общие для обычных типов ресурсов (js, inline_js, css, inline_css) и сборки ресурсов, которая умеет минифицировать и сжимать; и, наконец, трейт устаревшего кода содержит методы-сокращения или обходные пути, которые в дальнейшем обычно использовать не следует.

Примечание

Менеджер ресурсов полностью обратно совместим с синтаксисом версий до Grav 1.6, однако документация ниже описывает новый предпочтительный синтаксис.

Конфигурация

У менеджера ресурсов Grav есть простой набор параметров конфигурации. Значения по умолчанию находятся в системном файле system.yaml, но вы можете переопределить любые или все из них в user/config/system.yaml:

assets:                                        # Конфигурация менеджера ресурсов (JS, CSS)
  css_pipeline: false                          # CSS-сборка объединяет несколько CSS-ресурсов в один файл
  css_pipeline_include_externals: true         # Включать внешние URL в сборку по умолчанию
  css_pipeline_before_excludes: true           # Рендерить сборку перед любыми исключёнными файлами
  css_minify: true                             # Минифицировать CSS во время сборки
  css_minify_windows: false                    # Переопределение минификации для Windows, также применяется к js. По умолчанию false из-за ThreadStackSize
  css_rewrite: true                            # Переписывать относительные URL в CSS во время сборки
  js_pipeline: false                           # JS-сборка объединяет несколько JS-ресурсов в один файл
  js_pipeline_include_externals: true          # Включать внешние URL в сборку по умолчанию
  js_pipeline_before_excludes: true            # Рендерить сборку перед любыми исключёнными файлами
  js_module_pipeline: false                    # Сборка JS-модулей объединяет несколько ресурсов JS-модулей в один файл
  js_module_pipeline_include_externals: true   # Включать внешние URL в сборку по умолчанию
  js_module_pipeline_before_excludes: true     # Рендерить сборку перед любыми исключёнными файлами
  js_minify: true                              # Минифицировать JS во время сборки
  enable_asset_timestamp: false                # Включить временные метки ресурсов
  collections:
    jquery: system://assets/jquery/jquery-2.x.min.js

Структура

Существует несколько уровней управления позиционированием, как показано на схеме ниже. В порядке охвата это:

  • Группа — позволяет группировать ресурсы, например head (по умолчанию) и bottom.
  • Позиция — before, pipeline (по умолчанию) и after. По сути это позволяет указать, где в группе должен загружаться ресурс.
  • Приоритет — управляет порядком: большие числа (например, 100) выводятся раньше меньших. По умолчанию 10.
 CSS
┌───────────────────────┐
│ Group (head)          │
│┌─────────────────────┐│        ┌──────────────────┐
││ Position            ││        │   priority 100   │─────┐     ┌──────────────────┐
││┌───────────────────┐││        ├──────────────────┤     ├────▶│       CSS        │
│││                   │││        │   priority 99    │─────┤     └──────────────────┘
│││      before       │├┼──┬────▶├──────────────────┤     │
│││                   │││  │     │    priority 1    │─────┤     ┌──────────────────┐
││├───────────────────┤││  │     ├──────────────────┤     ├────▶│    inline CSS    │
│││                   │││  │     │    priority 0    │─────┘     └──────────────────┘
│││     pipeline      │├┼──┤     └──────────────────┘
│││                   │││  │
││├───────────────────┤││  │
│││                   │││  │
│││       after       │├┼──┘
│││                   │││
││└───────────────────┘││
│└─────────────────────┘│
└───────────────────────┘


JS
┌───────────────────────┐
│ Group (head)          │
│┌─────────────────────┐│        ┌──────────────────┐
││ Position            ││        │   priority 100   │─────┐     ┌──────────────────┐
││┌───────────────────┐││        ├──────────────────┤     ├────▶│        JS        │
│││                   │││        │   priority 99    │─────┤     └──────────────────┘
│││      before       │├┼──┬────▶├──────────────────┤     │
│││                   │││  │     │    priority 1    │─────┤     ┌──────────────────┐
││├───────────────────┤││  │     ├──────────────────┤     ├────▶│    inline JS     │
│││                   │││  │     │    priority 0    │─────┘     └──────────────────┘
│││     pipeline      │├┼──┤     └──────────────────┘
│││                   │││  │
││├───────────────────┤││  │
│││                   │││  │
│││       after       │├┼──┘
│││                   │││
││└───────────────────┘││
│└─────────────────────┘│
└───────────────────────┘



JS Module
┌───────────────────────┐
│ Group (head)          │
│┌─────────────────────┐│        ┌──────────────────┐
││ Position            ││        │   priority 100   │─────┐     ┌─────────────────────────┐
││┌───────────────────┐││        ├──────────────────┤     ├────▶│        JS Module        │
│││                   │││        │   priority 99    │─────┤     └─────────────────────────┘
│││      before       │├┼──┬────▶├──────────────────┤     │
│││                   │││  │     │    priority 1    │─────┤     ┌─────────────────────────┐
││├───────────────────┤││  │     ├──────────────────┤     ├────▶│    inline JS Module     │
│││                   │││  │     │    priority 0    │─────┘     └─────────────────────────┘
│││     pipeline      │├┼──┤     └──────────────────┘
│││                   │││  │
││├───────────────────┤││  │
│││                   │││  │
│││       after       │├┼──┘
│││                   │││
││└───────────────────┘││
│└─────────────────────┘│
└───────────────────────┘

По умолчанию CSS, JS и JS Module при выводе отображаются в позиции pipeline. А InlineCSS, InlineJS и Inline JS Module по умолчанию находятся в позиции after. Это настраивается: любой ресурс можно поместить в любую позицию.

Ресурсы в темах

Обзор

Обычно CSS-ресурсы добавляют по одному через вызовы assets.addCss() или assets.addInlineCss(), а затем рендерят их через assets.css(). Опции приоритета, сборки или встраивания можно указать для каждого ресурса при добавлении или при рендеринге группы ресурсов.

JS-ресурсы обрабатываются аналогично через assets.addJs() и assets.addInlineJs(). Есть также общий метод assets.add(), который пытается определить тип добавляемого ресурса, но рекомендуется использовать более конкретные методы.

Начиная с версии 1.7.27 менеджер ресурсов Grav также поддерживает JS-модули. Эти ресурсы работают точно так же, как JS-ресурсы, но имеют тип type="module" и обрабатываются вызовами assets.addJsModule() и assets.addInlineJsModule(). Общий метод assets.add() переключится на JS-модуль, только если обнаруженным расширением будет .mjs. В остальных случаях любой файл .js будет обрабатываться как обычный JS.

Предупреждение

Чтобы узнать больше о JS-модулях: * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules * https://v8.dev/features/modules * https://javascript.info/modules-intro

Менеджер ресурсов также поддерживает:

  • добавление ресурсов в именованные группы, чтобы рендерить такие группы в разных местах и/или с разными наборами опций;
  • настройку именованных коллекций ресурсов, которые можно добавить одним вызовом assets.add*().

Пример

Пример добавления CSS-файлов в теме можно найти в теме quark по умолчанию, поставляемой с Grav. Если посмотреть на фрагмент templates/partials/base.html.twig, вы увидите примерно следующее:

<!DOCTYPE html>
<html>
    <head>
    ...

    {% block stylesheets %}
        {% do assets.addCss('theme://css-compiled/spectre.css') %}
        {% do assets.addCss('theme://css-compiled/theme.css') %}
        {% do assets.addCss('theme://css/custom.css') %}
        {% do assets.addCss('theme://css/line-awesome.min.css') %}
    {% endblock %}

    {% block javascripts %}
        {% do assets.addJs('jquery', 101) %}
        {% do assets.addJs('theme://js/jquery.treemenu.js', { group: 'bottom' }) %}
        {% do assets.addJs('theme://js/site.js', { group: 'bottom' }) %}
        {% do assets.addJsModule('plugin://my_plugin/app/main.js', { group: 'bottom' }) %}
    {% endblock %}

    {% block assets deferred %}
        {{ assets.css()|raw }}
        {{ assets.js()|raw }}
    {% endblock %}
    </head>

    <body>
    ...

    {% block bottom %}
        {{ assets.js('bottom')|raw }}
    {% endblock %}
    </body>
</html>

Тег Twig block stylesheets просто определяет область, которую можно заменить или дополнить в шаблонах, расширяющих этот. Внутри блока вы увидите несколько вызовов do assets.addCss().

Тег {% do %} на самом деле встроен в Twig и позволяет манипулировать переменными, не генерируя вывода.

Метод addCss() добавляет CSS-ресурсы в менеджер ресурсов. Если указать второй числовой параметр, он задаёт приоритет таблицы стилей. Если приоритет не указан, порядок рендеринга определяется порядком добавления ресурсов. Обратите внимание на использование обёртки потока PHP theme://, которая даёт Grav простой способ определить относительный путь текущей темы.

Внимание

assets.addJs('jquery', 101) подключит коллекцию jquery, определённую в глобальной конфигурации ресурсов. Необязательный параметр 101 задаёт довольно высокий приоритет, чтобы ресурс отрендерился первым. Приоритет по умолчанию, если он не указан, равен 10. Более гибкий способ записать это — assets.addJs('jquery', {priority: 101}). Так можно добавлять другие параметры вместе с приоритетом.

Вызов assets.css()|raw рендерит CSS-ресурсы в виде HTML-тегов. Поскольку методу не передан параметр, группа по умолчанию — head. Обратите внимание, что вызов обёрнут в блок assets deferred. Это новая фича Grav 1.6, позволяющая добавлять ресурсы из других шаблонов Twig, включённых ниже на странице (или вообще где угодно), и при этом гарантировать их рендеринг в блоке head, если это нужно.

Блок bottom в самом конце вывода темы рендерит JavaScript, назначенный группе bottom.

Добавление ресурсов

add(asset, [options])

Метод add старается определить ресурс по расширению файла. Это удобный метод; лучше вызывать один из прямых методов для CSS, Link, JS и JS Module. Подробности см. в описании прямых методов.

Внимание

Массив опций — предпочтительный способ передачи нескольких опций. Однако, как в предыдущем примере с jquery, можно использовать сокращение и передать целое число вторым аргументом, если нужно задать только приоритет.

addCss(asset, [options])

Этот метод добавляет ресурсы в список CSS-ресурсов. Приоритет по умолчанию — 10, если не указан. Большее число означает, что ресурс отобразится раньше ресурсов с меньшим приоритетом. Опция pipeline управляет тем, включать ли этот ресурс в сборку/минификацию. Если ресурс не включён в сборку, опция loading определяет, рендерить его как ссылку на внешнюю таблицу стилей или встроить его содержимое в тег inline style.

Этот метод добавляет ресурсы в список ресурсов Link в виде тега <link>. Он полезен для добавления тегов link в head из любого места сайта, если это не CSS-файлы. Приоритет по умолчанию — 10, если не указан. Большее число означает, что ресурс отобразится раньше ресурсов с меньшим приоритетом.

В отличие от других методов добавления ресурсов, link() не поддерживает сборку и не поддерживает inline.

addInlineCss(css, [options])

Позволяет добавить строку CSS внутрь встроенного тега style. Полезно для инициализации или динамических данных. Чтобы встроить содержимое обычного файла ресурса, см. опцию { 'loading': 'inline' } методов addCss() и css().

addJs(asset, [options])

Этот метод добавляет ресурсы в список JavaScript-ресурсов. Приоритет по умолчанию — 10, если не указан. Большее число означает, что ресурс отобразится раньше ресурсов с меньшим приоритетом. Опция pipeline управляет тем, включать ли этот ресурс в сборку/минификацию. Если ресурс не включён в сборку, опция loading определяет, рендерить его как ссылку на внешний файл скрипта или встроить его содержимое в тег inline script.

addInlineJs(javascript, [options])

Позволяет добавить строку JavaScript внутрь встроенного тега script. Полезно для инициализации или динамических данных. Чтобы встроить содержимое обычного файла ресурса, см. опцию { 'loading': 'inline' } методов addJs() и js().

addJsModule(asset, [options])

Этот метод добавляет ресурсы в список ресурсов JavaScript-модулей. Приоритет по умолчанию — 10, если не указан. Большее число означает, что ресурс отобразится раньше ресурсов с меньшим приоритетом. Опция pipeline управляет тем, включать ли этот ресурс в сборку/минификацию. Если ресурс не включён в сборку, опция loading определяет, рендерить его как ссылку на внешний файл скрипта или встроить его содержимое в тег inline script.

addInlineJsModule(javascript, [options])

Позволяет добавить строку JavaScript внутрь встроенного тега module script. Чтобы встроить содержимое обычного файла ресурса, см. опцию { 'loading': 'inline' } методов addJsModule() и js().

registerCollection(name, array)

Позволяет зарегистрировать массив CSS- и JavaScript-ресурсов с именем для дальнейшего использования методом add(). Особенно полезно, если вы хотите зарегистрировать коллекцию, которую могут использовать несколько тем или плагинов, например jQuery или Bootstrap.

Опции

Где уместно, можно передать массив опций ресурса. Основные опции:

Для CSS

  • priority: целое значение (по умолчанию 10).

  • position: по умолчанию pipeline, но также может быть before или after относительно ресурсов в позиции pipeline.

  • loading: inline, если этот ресурс должен выводиться встроенным (по умолчанию: подключается ссылкой на таблицу стилей). Следует использовать вместе с position: before или position: after, поскольку при position: pipeline (по умолчанию) опция не действует.

  • group: строка, задающая уникальное имя группы для ресурса (по умолчанию head).

Для JS и JS Module

  • priority: целое значение (по умолчанию 10).

  • position: по умолчанию pipeline, но также может быть before или after относительно ресурсов в позиции pipeline.

  • loading: поддерживает любой тип загрузки, например async, defer, async defer или inline. Следует использовать вместе с position: before или position: after, поскольку при position: pipeline (по умолчанию) опция не действует.

  • group: строка, задающая уникальное имя группы для ресурса (по умолчанию head).

Другие атрибуты

Можно также передать в массив опций что угодно ещё; если это не стандартные типы, они просто отрендерятся как атрибуты: например, {id: 'custom-id'} отрендерится как id="custom-id" в HTML-теге. Это также можно использовать для вставки структурированных данных, например JSON-LD, через addInlineJs() с помощью {type: 'application/ld+json'}.

Примеры

Например:

{% do assets.addCss('page://01.blog/assets-test/example.css?foo=bar', { priority: 20, loading: 'inline', position: 'before'}) %}

Отрендерится так:

1
2
3
4
5
6
<style>
h1.blinking {
    text-decoration: underline;
}
</style>
<link.....

Другой пример:

{% do assets.addJs('page://01.blog/assets-test/example.js', {loading: 'async', id: 'custom-css'}) %}

Отрендерится так:

<script src="/grav/user/pages/01.blog/assets-test/example.js" async id="custom-css"></script>

Пример с Link:

{% do assets.addLink('theme://images/favicon.png', { rel: 'icon', type: 'image/png' }) %}
{% do assets.addLink('plugin://grav-plugin/build/js/vendor.js', { rel: 'modulepreload' }) %}

Отрендерится так:

<link rel="icon" type="image/png" href="/user/themes/quark/images/favicon.png">
<link href="/user/plugins/grav-plugin/build/js/vendor.js" rel="modulepreload">

Рендеринг ресурсов

Следующие методы позволяют рендерить текущее состояние CSS- и JavaScript-ресурсов.

Рендерит CSS-ресурсы, добавленные в группу менеджера ресурсов (по умолчанию head). Опции:

  • loading: inline, если все ресурсы этой группы должны быть встроены (по умолчанию: каждый ресурс рендерится согласно его опции position).

  • атрибуты link, см. ниже (по умолчанию: {'type': 'text/css', 'rel': 'stylesheet'}). Действует, только если inline не используется как опция рендеринга этой группы.

Когда include_link включён (а он включён по умолчанию), вызов css() также приводит к вызову link().

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

Если сборка ресурсов включена в конфигурации, ресурсы в позиции pipeline объединяются в порядке добавления, а затем обрабатываются согласно конфигурации сборки.

Каждый ресурс рендерится либо как ссылка на таблицу стилей, либо встроенным, в зависимости от опции loading ресурса и того, используется ли {'loading': 'inline'} для рендеринга этой группы. CSS, добавленный через addInlineCss(), по умолчанию рендерится в позиции after, но можно настроить его рендеринг до результата сборки с помощью position: before.

Рендерит ресурсы Link, добавленные в группу менеджера ресурсов (по умолчанию head). Не рекомендуется использовать группу, отличную от head: именно там браузер ожидает найти и обработать тег.

В отличие от других методов добавления ресурсов, link() не поддерживает сборку и не поддерживает inline.

js(group, [options], include_js_module = true)

Рендерит JavaScript-ресурсы, добавленные в группу менеджера ресурсов (по умолчанию head). Опции:

  • loading: inline, если все ресурсы этой группы должны быть встроены (по умолчанию: каждый ресурс рендерится согласно его опции position).

  • атрибуты script, см. ниже (по умолчанию: {'type': 'text/javascript'}). Действует, только если inline не используется как опция рендеринга этой группы.

Когда include_js_module включён (а он включён по умолчанию), вызов js() также приводит к вызову jsModule().

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

Если сборка ресурсов включена в конфигурации, ресурсы в позиции pipeline объединяются в порядке добавления, а затем обрабатываются согласно конфигурации сборки. Объединённый результат сборки затем рендерится до или после ресурсов вне сборки в зависимости от настройки js_pipeline_before_excludes.

Каждый ресурс рендерится либо как ссылка на скрипт, либо встроенным, в зависимости от опции loading ресурса и того, используется ли {'loading': 'inline'} для рендеринга этой группы. Обратите внимание: единственный способ встроить JS-сборку — использовать inline loading как опцию метода js(). JavaScript, добавленный через addInlineJs(), по умолчанию рендерится в позиции after, но можно настроить его рендеринг до результата сборки с помощью position: before.

jsModule(group, [options])

Работает точно так же, как рендерер js(), но для JavaScript-модулей. Атрибут типа скрипта по умолчанию — type="module", даже при рендеринге inline.

all(group, [options])

Рендерит все ресурсы выше в порядке: css(), link(), js(), jsModule().

Это рекомендуемый способ подключения отложенных ресурсов в основной файл Twig (обычно base.html.twig).

{% block assets deferred %}
  {{ assets.all()|raw }}
{% endblock %}

Именованные ресурсы и коллекции

Теперь в Grav есть мощная фича под названием именованные ресурсы, позволяющая зарегистрировать коллекцию CSS- и JavaScript-ресурсов под именем. Затем можно просто добавить эти ресурсы в менеджер ресурсов по зарегистрированному имени. Grav уже настроен с jQuery, но позволяет определять пользовательские коллекции в system.yaml для использования любой темой или плагином:

1
2
3
4
5
6
7
assets:
  collections:
    jquery: system://assets/jquery/jquery-2.1.3.min.js
    bootstrap:
        - https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css
        - https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap-theme.min.css
        - https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js

Также можно зарегистрировать коллекцию программно с помощью метода registerCollection().

1
2
3
4
5
6
$assets = $this->grav['assets'];
$bootstrapper_bits = [https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css,
                      https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap-theme.min.css,
                      https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js];
$assets->registerCollection('bootstrap', $bootstrap_bits);
$assets->add('bootstrap', 100);

Пример этого действия можно найти в плагине bootstrapper.

Коллекции с атрибутами

Иногда нужно задать пользовательские и/или разные атрибуты для отдельных элементов коллекции, например при загрузке ресурсов с удалённого CDN и желании добавить проверку целостности (SRI). Это возможно, если представить значение именованного ресурса как массив, где ключ — расположение ресурса, а значение — список дополнительных атрибутов. Например:

1
2
3
4
5
6
7
8
9
assets:
  collections:
    jquery_and_ui:
        https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js:
            integrity: 'sha512-894YE6QWD5I59HgZOGReFYm4dnWc1Qt5NtvYSaNcOP+u1T9qYdvdihz0PPSiiqn/+/3e7Jo4EaG7TubfWGUrMQ=='
            group: 'bottom'
        https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js:
            integrity: 'sha512-uto9mlQzrs59VwILcLiRYeLKPPbS/bT71da/OEBYEwcdNUk8jYIy+D176RYoop1Da+f9mvkYrmj5MCLZWEtQuA=='
            group: 'bottom'

Затем после добавления JS в Twig через {% do assets.addJs('jquery_and_ui', { defer: true }) %} ресурсы загрузятся так:

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js" defer="1" integrity="sha512-894YE6QWD5I59HgZOGReFYm4dnWc1Qt5NtvYSaNcOP+u1T9qYdvdihz0PPSiiqn/+/3e7Jo4EaG7TubfWGUrMQ=="></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js" defer="1" integrity="sha512-uto9mlQzrs59VwILcLiRYeLKPPbS/bT71da/OEBYEwcdNUk8jYIy+D176RYoop1Da+f9mvkYrmj5MCLZWEtQuA=="></script>

Обратите внимание: defer был определён на уровне Twig и применён ко всем ресурсам коллекции. Это потому, что Grav объединяет атрибуты из Twig и из определения YAML, отдавая приоритет атрибутам из YAML.

Если бы ресурс jquery-ui.min.js также включал атрибут defer: null, он получил бы приоритет над defer: 1 из Twig и не был бы отрендерен.

Сгруппированные ресурсы

Менеджер ресурсов позволяет передать необязательный group как часть массива опций при добавлении ресурсов. Хотя для CSS это имеет небольшое значение, особенно полезно для JavaScript, когда часть JS-файлов или встроенного JS нужно подключить в заголовке, а часть — внизу страницы.

Чтобы воспользоваться этой фичей, нужно указать группу при добавлении ресурса и использовать синтаксис опций:

{% do assets.addJs('theme://js/example.js', {'priority':102, 'group':'bottom'}) %}

Затем, чтобы эти ресурсы группы bottom отрендерились, нужно добавить в тему:

{{ assets.js('bottom')|raw }}

Если для ресурса не задана группа, по умолчанию используется head. Если группа не задана для рендеринга, будет отрендерена группа head. Это гарантирует 100% обратную совместимость новой функциональности с существующими темами.

То же касается CSS-файлов:

{% do assets.addCss('theme://css/ie8.css', {'group':'ie'}) %}

и для рендеринга:

{{ assets.css('ie')|raw }}

Изменение атрибута отрендеренных CSS/JS-ресурсов

CSS по умолчанию добавляется с атрибутом rel="stylesheet" и type="text/css", а JS — с type="text/javascript".

Чтобы изменить значения по умолчанию или добавить новые атрибуты, нужно создать новую группу ресурсов и указать Grav рендерить её с этим атрибутом.

Пример изменения атрибута rel у группы ресурсов:

1
2
3
{% do assets.addCSS('theme://whatever.css', {'group':'my-alternate-group'}) %}
...
{{ assets.css('my-alternate-group', {'rel': 'alternate'})|raw }}

Встраивание ресурсов

Встраивание позволяет разместить критический CSS (и JS) код прямо в HTML-документе, чтобы браузер мог сразу отрендерить страницу, не ожидая загрузки внешних таблиц стилей или скриптов. Это может заметно улучшить производительность сайта, особенно в мобильных сетях. Подробности — в этой статье об оптимизации доставки CSS.

Однако напрямую вставлять CSS- или JavaScript-код в шаблон страницы не всегда возможно, например когда используется CSS, скомпилированный из Sass. Хранение CSS- и JS-ресурсов в отдельных файлах также упрощает сопровождение. Возможность встраивания в менеджере ресурсов позволяет оптимизировать скорость, не меняя способ хранения ресурсов. Встроить можно даже целые сборки.

Чтобы встроить содержимое файла ресурса, используйте опцию {'loading': 'inline'} с addCss() или addJs(). Также можно встроить все ресурсы при рендеринге группы через js() или css(), которые предоставляют ту же опцию.

Пример использования system.yaml для определения коллекций ресурсов с именами по требованиям загрузки, где app.css — CSS-файл, сгенерированный Sass:

assets:
  collections:
    css-inline:
      - 'http://fonts.googleapis.com/css?family=Ubuntu:400|Open+Sans:400,400i,700'
      - 'theme://css-compiled/app.css'
    js-inline:
      - 'https://use.fontawesome.com/<embedcode>.js'
    js-async:
      - 'theme://foundation/dist/assets/js/app.js'
      - 'theme://js/header-display.js'

Шаблон вставляет каждую коллекцию в соответствующую группу: head и head-link для CSS, head и head-async для JS. Группа head по умолчанию используется для встроенной загрузки в каждом случае:

{% block stylesheets %}
    {% do assets.addCss('css-inline') %}
    {% do assets.addCss('css-link', {'group': 'head-link'}) %}
{% endblock %}
{{ assets.css('head-link')|raw }}
{{ assets.css('head', {'loading': 'inline'})|raw }}
{% block javascripts %}
    {% do assets.addJs('js-inline') %}
    {% do assets.addJs('js-async', {'group': 'head-async'}) %}
{% endblock %}
{{ assets.js('head-async', {'loading': 'async'})|raw }}
{{ assets.js('head', {'loading': 'inline'})|raw }}

Статические ресурсы

Иногда нужно ссылаться на ресурсы без использования менеджера ресурсов. Для этого есть вспомогательный метод url(). Пример — ссылка на изображение из темы. Синтаксис:

<img src="{{ url("theme://" ~ widget.image)|e }}" alt="{{ widget.text|e }}" />

Метод url() принимает необязательный второй параметр true или false, чтобы URL включал схему и домен. По умолчанию предполагается false, то есть только относительный URL. Например:

<script src="{{ url('theme://some/extra.css', true)|e }}"></script>