Ресурсы

Ресурс в Yii это файл который может быть задан в Web странице. Это может быть CSS файл, JavaScript файл, изображение или видео файл и т.д. Ресурсы располагаются в Web доступных директориях и обслуживаются непосредственно Web серверами.

Желательно, управлять ресурсами программно. Например, при использовании виджета yii\jui\DatePicker в странице, автоматически включаются необходимые CSS и JavaScript файлы, вместо того чтобы просить Вас вручную найти эти файлы и включить их. И когда Вы обновляете виджет до новой версии, будут автоматически использованы новые версии файлов-ресурсов. В этом руководстве будет описана мощная возможность управления ресурсами представленная в Yii.

Комплекты ресурсов

Yii управляет ресурсами как единицей комплекта ресурсов. Комплект ресурсов - это простой набор ресурсов расположенных в директории. Когда Вы регистрируете комплект ресурсов в представлении, в отображаемой Web странице включается набор CSS и JavaScript файлов.

Задание Комплекта Ресурсов

Комплект ресурсов определяется как PHP класс расширяющийся от yii\web\AssetBundle. Имя комплекта соответствует полному имени PHP класса (без ведущей обратной косой черты - backslash "\"). Класс комплекта ресурсов должен быть в состоянии возможности автозагрузки. При задании комплекта ресурсов обычно указывается где ресурсы находятся, какие CSS и JavaScript файлы содержит комплект, и как комплект зависит от других комплектов.

Следующий код задаёт основной комплект ресурсов используемый в шаблоне базового приложения:

<?php

namespace app\assets;

use yii\web\AssetBundle;

class AppAsset extends AssetBundle
{
    public $basePath = '@webroot';
    public $baseUrl = '@web';
    public $css = [
        'css/site.css',
    ];
    public $js = [
    ];
    public $depends = [
        'yii\web\YiiAsset',
        'yii\bootstrap\BootstrapAsset',
    ];
}

В коде выше класс AppAsset указывает, что файлы ресурса находятся в директории @webroot, которой соответствует URL @web; комплект содержит единственный CSS файл css/site.css и не содержит JavaScript файлов; комплект зависит от двух других комплектов: yii\web\YiiAsset и yii\bootstrap\BootstrapAsset. Более детальное объяснение о свойствах yii\web\AssetBundle может быть найдено ниже:

  • sourcePath: задаёт корневую директорию содержащую файлы ресурса в этом комплекте. Это свойство должно быть установлено если корневая директория не доступна из Web. В противном случае, Вы должны установить basePath свойство и baseUrl свойство вместо текущего. Здесь могут быть использованы псевдонимы путей.
  • basePath: задаёт Web доступную директорию, которая содержит файлы ресурсов текущего комплекта. Когда Вы задаёте свойство sourcePath Менеджер ресурсов опубликует ресурсы текущего комплекта в Web доступную директорию и перезапишет соответственно данное свойство. Вы должны задать данное свойство если Ваши файлы ресурсов уже в Web доступной директории и не нужно опубликовывать ресурсы. Здесь могут быть использованы псевдонимы путей.
  • baseUrl: задаёт URL соответствующий директории basePath. Также как и для basePath, если Вы задаёте свойство sourcePath Менеджер ресурсов опубликует ресурсы и перезапишет это свойство соответственно. Здесь могут быть использованы псевдонимы путей.
  • js: массив, перечисляющий JavaScript файлы, содержащиеся в данном комплекте. Заметьте, что только прямая косая черта (forward slash - "/") может быть использована, как разделитель директорий. Каждый JavaScript файл может быть задан в одном из следующих форматов:
    • относительный путь, представленный локальным JavaScript файлом (например js/main.js). Актуальный путь файла может быть определён путём добавления yii\web\AssetManager::$basePath к относительному пути, и актуальный URL файла может быть определён путём добавления yii\web\AssetManager::$baseUrl к относительному пути.
    • абсолютный URL, представленный внешним JavaScript файлом. Например, http://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js или //ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js.
  • css: массив, перечисляющий CSS файлы, содержащиеся в данном комплекте. Формат этого массива такой же, как и у js.
  • depends: массив, перечисляющий имена комплектов ресурсов, от которых зависит данный комплект.
  • jsOptions: задаёт параметры, которые будут относится к методу yii\web\View::registerJsFile(), когда он вызывается для регистрации каждого JavaScript файла данного комплекта.
  • cssOptions: задаёт параметры, которые будут приняты методом yii\web\View::registerCssFile(), когда он вызывается для регистрации каждого CSS файла данного комплекта.
  • publishOptions: задаёт параметры, которые будут приняты методом yii\web\AssetManager::publish(), когда метод будет вызван, опубликуются исходные файлы ресурсов в Web директории. Этот параметр используется только в том случае, если задаётся свойство sourcePath.

Расположение ресурсов

Ресурсы, в зависимости от их расположения, могут быть классифицированы как:

  • исходные ресурсы: файлы ресурсов, расположенные вместе с исходным кодом PHP, которые не могут быть непосредственно доступны через Web. Для того, чтобы использовать исходные ресурсы на странице, они должны быть скопированы в Web директорию и превратиться в так называемые опубликованные ресурсы. Этот процесс называется публикацией ресурсов, который более подробно описан ниже
  • опубликованные ресурсы: файлы ресурсов, расположенные в Web директории и, таким образом, могут быть напрямую доступны через Web.
  • внешние ресурсы: файлы ресурсов, расположенные на другом Web сервере, отличного от веб-хостинга вашего приложения.

При определении класса комплекта ресурсов, если Вы задаёте свойство sourcePath, это означает, что любые перечисленные ресурсы, используя относительные пути, будут рассматриваться как исходные ресурсы. Если Вы не задаёте данное свойство, это означает, что эти ресурсы - это опубликованные ресурсы (в этом случае Вам следует указать basePath и baseUrl, чтобы дать знать Yii где ресурсы располагаются).

Рекомендуется размещать ресурсы, принадлежащие приложению, в Web директорию, для того, чтобы избежать не нужного процесса публикации ресурсов. Вот почему AppAsset в предыдущем примере задаёт basePath вместо sourcePath.

Для расширений, в связи с тем, что их ресурсы располагаются вместе с их исходным кодом в директориях, которые не являются веб-доступными, необходимо указать свойство sourcePath при задании класса комплекта ресурсов для них.

Примечание: Не используйте @webroot/assets как source path. Эта директория по умолчанию используется менеджером ресурсов asset manager для сохранения файлов ресурсов, опубликованных из их исходного месторасположения. Любое содержимое этой директории расценивается как временное и может быть удалено.

Зависимости ресурсов

Когда Вы включаете несколько CSS или JavaScript файлов в Web страницу, они должны следовать в определенном порядке, чтобы избежать переопределения при выдаче. Например, если Вы используете виджет jQuery UI в Web странице, вы должны убедиться, что jQuery JavaScript файл был включен до jQuery UI JavaScript файла. Мы называем такой порядок зависимостью между ресурсами.

Зависимости ресурсов в основном указываются через свойство yii\web\AssetBundle::$depends. Например в AppAsset, комплект ресурсов зависит от двух других комплектов ресурсов: yii\web\YiiAsset и yii\bootstrap\BootstrapAsset, что обозначает, что CSS и JavaScript файлы AppAsset будут включены после файлов этих двух комплектов зависимостей.

Зависимости ресурсов являются также зависимыми. Это значит, что если комплект А зависит от В, который зависит от С, то А тоже зависит от С.

Параметры ресурсов

Вы можете задать свойства cssOptions и jsOptions, чтобы настроить путь для включения CSS и JavaScript файлов в страницу. Значения этих свойств будут приняты методами yii\web\View::registerCssFile() и yii\web\View::registerJsFile() соответственно, когда они (методы) вызываются представлением происходит включение CSS и JavaScript файлов.

Примечание: Параметры, заданные в комплекте класса применяются для каждого CSS/JavaScript-файла в комплекте. Если Вы хотите использовать различные параметры для разных файлов, Вы должны создать раздельные комплекты ресурсов, и использовать одну установку параметров для каждого комплекта.

Например, условно включим CSS файл для браузера IE9 или ниже. Для этого Вы можете использовать следующий параметр:

public $cssOptions = ['condition' => 'lte IE9'];

Это вызовет CSS файл из комплекта, который будет включен в страницу, используя следующие HTML теги:

<!--[if lte IE9]>
<link rel="stylesheet" href="path/to/foo.css">
<![endif]-->

Для того чтобы обернуть созданную CSS ссылку в тег <noscript>, Вы можете настроить cssOptions следующим образом:

public $cssOptions = ['noscript' => true];

Для включения JavaScript файла в head раздел страницы (по умолчанию, JavaScript файлы включаются в конец раздела body) используйте следующий параметр:

public $jsOptions = ['position' => \yii\web\View::POS_HEAD];

По умолчанию, когда комплект ресурсов публикуется, всё содержимое в заданной директории yii\web\AssetBundle::$sourcePath будет опубликовано. Вы можете настроить это поведение, сконфигурировав свойство publishOptions. Например, опубликовать одну или несколько поддиректорий yii\web\AssetBundle::$sourcePath в классе комплекта ресурсов Вы можете в следующим образом:

<?php
namespace app\assets;

use yii\web\AssetBundle;

class FontAwesomeAsset extends AssetBundle 
{
    public $sourcePath = '@bower/font-awesome'; 
    public $css = [ 
        'css/font-awesome.min.css', 
    ]; 
    public $publishOptions = [
        'only' => [
            'fonts/*',
            'css/*',
        ]
    ];
}  

Более сложную логику можно реализовать с помощью переопределения init(). Ниже указан пример публикации поддиректорий этим способом:

<?php
namespace app\assets;

use yii\web\AssetBundle;

class FontAwesomeAsset extends AssetBundle 
{
    public $sourcePath = '@bower/font-awesome'; 
    public $css = [ 
        'css/font-awesome.min.css', 
    ]; 
    
    public function init()
    {
        parent::init();
        $this->publishOptions['beforeCopy'] = function ($from, $to) {
            if (basename(dirname($from)) !== 'font-awesome') {
                return true;
            }
            $dirname = basename($from);
            return $dirname === 'fonts' || $dirname === 'css';
        };
    }
}  

В выше указанном примере определён комплект ресурсов для пакета "fontawesome". Задан параметр публикации beforeCopy, здесь только fonts и css поддиректории будут опубликованы.

Установка ресурсов Bower и NPM

Большинство JavaScript/CSS пакетов управляются Bower и/или NPM. В мире PHP мы испольуем Composer для управления зависимостями, но он не позволяет устанавливать пакеты Bower и NPM, просто указывая их в composer.json.

Чтобы получить такую возможность, нужно немного настроить Composer. Существует два варианта:


Используя репозиторий asset-packagist

Этот способ удовлетворяет потребности большинства проектов, которым нужны Bower или NPM пакеты.

Примечание: Начиная с версии 2.0.13, Basic и Advanced шаблоны приложений уже сконфигурированы для использования asset-packagist, так что этот раздел можно пропустить.

В файле composer.json вашего проекта, добавьте следующие строки:

"repositories": [
    {
        "type": "composer",
        "url": "https://asset-packagist.org"
    }
]

Настройте алиасы @npm и @bower в файле конфигурации вашего приложения:

$config = [
    ...
    'aliases' => [
        '@bower' => '@vendor/bower-asset',
        '@npm'   => '@vendor/npm-asset',
    ],
    ...
];

Посетите asset-packagist.org чтобы узнать, как это работает.

Используя fxp/composer-asset-plugin

По сравнению с asset-packagist, composer-asset-plugin не требует изменять конфигурацию приложения. Вместо этого, требуется установить специальный глобальный пакет Composer, выполнив следующую команду:

composer global require "fxp/composer-asset-plugin:^1.4.1"

Эта команда устанавливает composer asset plugin глобально, что позволит устанавливать зависимости из Bower и NPM. После установки все проекты на вашем комьютере будут поддерживать установку Bower и NPM пакетов, описанных в composer.json.

Добавьте следующие строки в composer.json вашего проекта, чтобы указать директории, в которые будут установлены необходимые Bower и NPM пакеты:

"extra": {
    "asset-installer-paths": {
        "npm-asset-library": "vendor/npm",
        "bower-asset-library": "vendor/bower"
    }
}

Примечание: fxp/composer-asset-plugin выполняет команду composer update существенно дольше, по сравнению с asset-packagist.


После настройки Composer для поддержки Bower и NPM пакетов:

  1. Исправьте файл composer.json Вашего приложения или расширения и включите пакет в список в раздел require. Следует использовать bower-asset/PackageName (для Bower пакетов) или npm-asset/PackageName (для NPM пакетов) для обращения к соответствующей библиотеке.
  2. Выполните composer update
  3. Создайте класс комплекта ресурсов и перечислите JavaScript/CSS файлы, которые Вы планируете использовать в Вашем приложении или расширении. Вы должны задать свойство sourcePath как @bower/PackageName или @npm/PackageName.

Это происходит потому, что Composer устанавливает Bower или NPM пакет в директорию, соответствующую этим псевдонимам.

Примечание: В некоторых пакетах файлы дистрибутива могут находиться в поддиректории. В этом случае, Вы должны задать поддиректорию как значение sourcePath. Например, yii\web\JqueryAsset использует @bower/jquery/dist вместо @bower/jquery.

Использование Комплекта Ресурсов

Для использования комплекта ресурсов, зарегистрируйте его в представлении вызвав метод yii\web\AssetBundle::register(). Например, комплект ресурсов в представлении может быть зарегистрирован следующим образом:

use app\assets\AppAsset;
AppAsset::register($this);  // $this - представляет собой объект представления

Информация: Метод yii\web\AssetBundle::register() возвращает объект комплекта ресурсов, содержащий информацию о публикуемых ресурсах, таких как basePath или baseUrl.

Если Вы регистрируете комплект ресурсов в других местах (т.е. не в представлении), Вы должны обеспечить необходимый объект представления. Например, при регистрации комплекта ресурсов в классе widget, Вы можете взять за объект представления $this->view.

Когда комплект ресурсов регистрируется в представлении, Yii регистрирует все зависимые от него комплекты ресурсов. И, если комплект ресурсов расположен в директории не доступной из Web, то он будет опубликован в Web директории. Затем, когда представление отображает страницу, сгенерируются теги <link> и <script> для CSS и JavaScript файлов, перечисленных в регистрируемых комплектах. Порядок этих тегов определён зависимостью среди регистрируемых комплектов, и последовательность ресурсов перечислена в yii\web\AssetBundle::$css и yii\web\AssetBundle::$js свойствах.

Динамические Комплекты Ресурсов

Поскольку комплект ресурсов это обычный PHP класс, он может содержать дополнительную логику, связанную с ним, и может корректировать свои внутренние параметры динамически. Например, вы можете использовать сложную JavaScript библиотеку, которая предоставляет интернационализацию через отдельные исходные файлы: по одному на каждый поддерживаемый язык. Таким образом, вам нужно добавить определенный '.js' файл на вашу страницу, чтобы применить перевод для библиотеки. Этого можно достичь, переопределив метод yii\web\AssetBundle::init():

namespace app\assets;

use yii\web\AssetBundle;
use Yii;

class SophisticatedAssetBundle extends AssetBundle
{
    public $sourcePath = '/path/to/sophisticated/src';
    public $js = [
        'sophisticated.js' // file, which is always used
    ];

    public function init()
    {
        parent::init();
        $this->js[] = 'i18n/' . Yii::$app->language . '.js'; // dynamic file added
    }
}

Конкретный комплект ресурсов может быть также изменен через его экземпляр, возвращенный методом yii\web\AssetBundle::register(). Например:

use app\assets\SophisticatedAssetBundle;
use Yii;

$bundle = SophisticatedAssetBundle::register(Yii::$app->view);
$bundle->js[] = 'i18n/' . Yii::$app->language . '.js'; // dynamic file added

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

Настройка Комплектов Ресурсов

Yii управляет комплектами ресурсов через компонент приложения называемый assetManager, который реализован в yii\web\AssetManager. Путём настройки свойства yii\web\AssetManager::$bundles, возможно настроить поведение комплекта ресурсов. Например, комплект ресурсов yii\web\JqueryAsset по умолчанию использует jquery.js файл из установленного jquery Bower пакета. Для повышения доступности и производительности, можно использовать версию jquery на Google хостинге. Это может быть достигнуто, настроив assetManager в конфигурации приложения следующим образом:

return [
    // ...
    'components' => [
        'assetManager' => [
            'bundles' => [
                'yii\web\JqueryAsset' => [
                    'sourcePath' => null,   // не опубликовывать комплект
                    'js' => [
                        '//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js',
                    ]
                ],
            ],
        ],
    ],
];

Можно сконфигурировать несколько комплектов ресурсов аналогично через yii\web\AssetManager::$bundles. Ключи массива должны быть именами класса (без впереди стоящей обратной косой черты) комплектов ресурсов, а значения массивов должны соответствовать конфигурации массивов.

Совет: Можно условно выбрать, какой из ресурсов будет использован в комплекте ресурсов. Следующий пример показывает, как можно использовать в разработке окружения jquery.js или jquery.min.js в противном случае:

'yii\web\JqueryAsset' => [
    'js' => [
        YII_ENV_DEV ? 'jquery.js' : 'jquery.min.js'
    ]
],

Можно запретить один или несколько комплектов ресурсов, связав false с именами комплектов ресурсов, которые Вы хотите сделать недоступными. Когда Вы регистрируете недоступный комплект ресурсов в представлении, обратите внимание, что зависимость комплектов будет зарегистрирована, и представление также не включит ни один из ресурсов комплекта в отображаемую страницу. Например, для запрета yii\web\JqueryAsset можно использовать следующую конфигурацию:

return [
    // ...
    'components' => [
        'assetManager' => [
            'bundles' => [
                'yii\web\JqueryAsset' => false,
            ],
        ],
    ],
];

Можно также запретить все комплекты ресурсов, установив yii\web\AssetManager::$bundles как false.

Имейте в виду, что настройки, установленные через yii\web\AssetManager::$bundles, применяются в момент создания комплекта ресурсов, т.е. в момент срабатывания конструктора. Таким образом, любые изменения, которые произведены над экземпляром комплекта ресурсов после этого, перекроют настройки, установленные на уровне yii\web\AssetManager::$bundles. В частности, изменения, произведенные внутри метода yii\web\AssetBundle::init() или после регистрации комплекта ресурсов, имеют приоритет над настройками AssetManager. Ниже приведены примеры, в которых значения, установленные через yii\web\AssetManager::$bundles не возымеют никакого эффекта:

// Program source code:

namespace app\assets;

use yii\web\AssetBundle;
use Yii;

class LanguageAssetBundle extends AssetBundle
{
    // ...

    public function init()
    {
        parent::init();
        $this->baseUrl = '@web/i18n/' . Yii::$app->language; // can NOT be handled by `AssetManager`!
    }
}
// ...

$bundle = \app\assets\LargeFileAssetBundle::register(Yii::$app->view);
$bundle->baseUrl = YII_DEBUG ? '@web/large-files': '@web/large-files/minified'; // can NOT be handled by `AssetManager`!


// Application config :

return [
    // ...
    'components' => [
        'assetManager' => [
            'bundles' => [
                'app\assets\LanguageAssetBundle' => [
                    'baseUrl' => 'http://some.cdn.com/files/i18n/en' // makes NO effect!
                ],
                'app\assets\LargeFileAssetBundle' => [
                    'baseUrl' => 'http://some.cdn.com/files/large-files' // makes NO effect!
                ],
            ],
        ],
    ],
];

Привязка ресурсов

Иногда необходимо исправить пути до файлов ресурсов, в нескольких комплектах ресурсов. Например, комплект А использует jquery.min.js версии 1.11.1, а комплект В использует jquery.js версии 2.1.1. Раньше Вы могли решить данную проблему, настраивая каждый комплект ресурсов по отдельности, но более простой способ - использовать asset map возможность, чтобы найти неверные ресурсы и исправить их. Сделать это можно, сконфигурировав свойство yii\web\AssetManager::$assetMap следующим образом:

return [
    // ...
    'components' => [
        'assetManager' => [
            'assetMap' => [
                'jquery.js' => '//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js',
            ],
        ],
    ],
];

Ключи assetMap - это имена ресурсов, которые Вы хотите исправить, а значения - это требуемые пути для ресурсов. Когда регистрируется комплект ресурсов в представлении, каждый соответствующий файл ресурса в css или js массивах будет рассмотрен в соответствии с этой привязкой. И, если какой-либо из ключей найден, как последняя часть пути до файла ресурса (путь на который начинается с yii\web\AssetBundle::$sourcePath по возможности), то соответствующее значение заменит ресурс и будет зарегистрировано в представлении. Например, путь до файла ресурса my/path/to/jquery.js - это соответствует ключу jquery.js.

Примечание: Ресурсы заданные только с использованием относительного пути могут использоваться в привязке ресурсов. Пути ресурсов должны быть абсолютные URLs или путь относительно yii\web\AssetManager::$basePath.

Публикация Ресурсов

Как уже было сказано выше, если комплект ресурсов располагается в директории которая не доступна из Web, эти ресурсы будут скопированы в Web директорию, когда комплект будет зарегистрирован в представлении. Этот процесс называется публикацией ресурсов, его автоматически выполняет asset manager.

По умолчанию, ресурсы публикуются в директорию @webroot/assets которая соответствует URL @web/assets. Можно настроить это местоположение сконфигурировав свойства basePath и baseUrl.

Вместо публикации ресурсов путём копирования файлов, можно рассмотреть использование символических ссылок, если Ваша операционная система или Web сервер это разрешают. Эта функция может быть включена путем установки linkAssets в true.

return [
    // ...
    'components' => [
        'assetManager' => [
            'linkAssets' => true,
        ],
    ],
];

С конфигурацией, установленной выше, менеджер ресурсов будет создавать символические ссылки на исходные пути комплекта ресурсов когда он будет публиковаться. Это быстрее, чем копирование файлов, а также может гарантировать, что опубликованные ресурсы всегда up-to-date(обновлённые/свежие).

Перебор Кэша

Для Web приложения запущенного в режиме продакшена, считается нормальной практикой разрешить HTTP кэширование для ресурсов и других статичных источников. Недостаток такой практики в том, что всякий раз, когда изменяется ресурс и разворачивается продакшен, пользователь может по-прежнему использовать старую версию ресурса вследствие HTTP кэширования. Чтобы избежать этого, можно использовать возможность перебора кэша, которая была добавлена в версии 2.0.3, для этого можно настроить yii\web\AssetManager следующим образом:

return [
    // ...
    'components' => [
        'assetManager' => [
            'appendTimestamp' => true,
        ],
    ],
];

Делая таким образом, к URL каждого опубликованного ресурса будет добавляться временная метка его последней модификации. Например, URL для yii.js может выглядеть как /assets/5515a87c/yii.js?v=1423448645", где параметр v представляет собой временную метку последней модификации файла yii.js. Теперь если изменить ресурс, его URL тоже будет изменен, это означает что клиент получит последнюю версию ресурса.

Обычное Использование Комплекта Ресурсов

Код ядра Yii содержит большое количество комплектов ресурсов. Среди них, следующие комплекты широко используются и могут упоминаться в Вашем приложении или коде расширения:

  • yii\web\YiiAsset: Включает основной yii.js файл который реализует механизм организации JavaScript кода в модулях. Также обеспечивает специальную поддержку для data-method и data-confirm атрибутов и содержит другие полезные функции.
  • yii\web\JqueryAsset: Включает jquery.js файл из jQuery Bower пакета.
  • yii\bootstrap\BootstrapAsset: Включает CSS файл из Twitter Bootstrap фреймворка.
  • yii\bootstrap\BootstrapPluginAsset: Включает JavaScript файл из Twitter Bootstrap фреймворка для поддержки Bootstrap JavaScript плагинов.
  • yii\jui\JuiAsset: Включает CSS и JavaScript файлы из jQuery UI библиотеки.

Если Ваш код зависит от jQuery, jQuery UI или Bootstrap, Вам необходимо использовать эти предопределенные комплекты ресурсов, а не создавать свои собственные варианты. Если параметры по умолчанию этих комплектов не удовлетворяют Вашим нуждам, Вы можете настроить их как описано в подразделе Настройка Комплектов Ресурсов.

Преобразование Ресурсов

Вместо того, чтобы напрямую писать CSS и/или JavaScript код, разработчики часто пишут его в некотором расширенном синтаксисе и используют специальные инструменты конвертации в CSS/JavaScript. Например, для CSS кода можно использовать LESS или SCSS; а для JavaScript можно использовать TypeScript.

Можно перечислить файлы ресурсов в расширенном синтаксисе в css и js свойствах из комплекта ресурсов. Например,

class AppAsset extends AssetBundle
{
    public $basePath = '@webroot';
    public $baseUrl = '@web';
    public $css = [
        'css/site.less',
    ];
    public $js = [
        'js/site.ts',
    ];
    public $depends = [
        'yii\web\YiiAsset',
        'yii\bootstrap\BootstrapAsset',
    ];
}

Когда Вы регистрируете такой комплект ресурсов в представлении, asset manager автоматически запустит нужные инструменты препроцессора и конвертирует ресурсы в CSS/JavaScript, если их расширенный синтаксис распознан. Когда представление окончательно отобразит страницу, в неё будут включены файлы CSS/JavaScript, вместо оригинальных ресурсов в расширенном синтаксисе.

Yii использует имена расширений файлов для идентификации расширенного синтаксиса внутри ресурса. По умолчанию признаны следующие синтаксисы и имена расширений файлов:

Yii ориентируется на установленные инструменты конвертации ресурсов препроцессора. Например, используя LESS, Вы должны установить команду lessc препроцессора.

Вы можете настроить команды препроцессора и поддерживать расширенный синтаксис сконфигурировав yii\web\AssetManager::$converter следующим образом:

return [
    'components' => [
        'assetManager' => [
            'converter' => [
                'class' => 'yii\web\AssetConverter',
                'commands' => [
                    'less' => ['css', 'lessc {from} {to} --no-color'],
                    'ts' => ['js', 'tsc --out {to} {from}'],
                ],
            ],
        ],
    ],
];

В примере выше, Вы задали поддержку расширенного синтаксиса через yii\web\AssetConverter::$commands свойство. Ключи массива - это имена расширений файлов (без ведущей точки), а значения массива - это образующийся файл ресурса имён расширений и команд для выполнения конвертации ресурса. Маркеры {from} и {to} в командах будут заменены соответственно исходным путём файла ресурсов и путём назначения файла ресурсов.

Примечание: Существуют другие способы работы с ресурсами расширенного синтаксиса, кроме того, который указан выше. Например, Вы можете использовать инструменты построения, такие как grunt для отслеживания и автоматической конвертации ресурсов расширенного синтаксиса. В этом случае, Вы должны перечислить конечные CSS/JavaScript файлы в комплекте ресурсов вместо исходных файлов.

Объединение и Сжатие Ресурсов

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

Примечание: Комбинирование и сжатие ресурсов обычно необходимо, когда приложение находится в режиме продакшена. В режиме разработки, использование исходных CSS/JavaScript файлов часто более удобно для отладочных целей.

Далее, мы представим подход комбинирования и сжатия файлов ресурсов без необходимости изменения Вашего существующего кода приложения.

  1. Найдите все комплекты ресурсов в Вашем приложении, которые Вы планируете скомбинировать и сжать.
  2. Распределите эти комплекты в одну или несколько групп. Обратите внимание, что каждый комплект может принадлежать только одной группе.
  3. Скомбинируйте/сожмите CSS файлы каждой группы в один файл. Сделайте то же самое для JavaScript файлов.
  4. Определите новый комплект ресурсов для каждой группы:
    • Или установите css и js свойства. Соответствующие CSS и JavaScript файлы будут объединены.
    • Или настройте комплекты ресурсов каждой группы, установив их css и js свойства как пустые, и установите их depends свойство как новый комплект ресурсов, созданный для группы.

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

Пример

Давайте рассмотрим пример, чтобы объяснить вышеуказанный подход.

Предположим, ваше приложение имеет две страницы, X и Y. Страница X использует комплект ресурсов A, B и C, в то время, как страница Y использует комплект ресурсов, B, C и D.

У Вас есть два пути, чтобы разделить эти комплекты ресурсов. Первый - использовать одну группу, включающую в себя все комплекты ресурсов. Другой путь - положить комплект А в группу Х, D в группу Y, а (B, C) в группу S. Какой из этих вариантов лучше? Первый способ имеет преимущество в том, что в обоих страницах одинаково скомбинированы файлы CSS и JavaScript, что делает HTTP кэширование более эффективным. С другой стороны, поскольку одна группа содержит все комплекты, размер скомбинированных CSS и JavaScript файлов будет больше, и таким образом увеличится время отдачи файла (загрузки страницы). Для простоты в этом примере, мы будем использовать первый способ, то есть использовать единую группу, содержащую все пакеты.

Примечание: Разделение комплекта ресурсов на группы это не тривиальная задача. Это, как правило, требует анализа реальных данных о трафике различных ресурсов на разных страницах. В начале вы можете начать с одной группы, для простоты.

Используйте существующие инструменты (например Closure Compiler, YUI Compressor) для объединения и сжатия CSS и JavaScript файлов во всех комплектах. Обратите внимание, что файлы должны быть объединены в том порядке, который удовлетворяет зависимости между комплектами. Например, если комплект A зависит от В, который зависит от С и D, то Вы должны перечислить файлы ресурсов начиная с С и D, затем B, и только после этого А.

После объединения и сжатия, Вы получите один CSS файл и один JavaScript файл. Предположим, они названы как all-xyz.css и all-xyz.js, где xyz это временная метка или хэш, который используется, чтобы создать уникальное имя файла, чтобы избежать проблем с HTTP кэшированием.

Сейчас мы находимся на последнем шаге. Настройте asset manager в конфигурации вашего приложения, как показано ниже:

return [
    'components' => [
        'assetManager' => [
            'bundles' => [
                'all' => [
                    'class' => 'yii\web\AssetBundle',
                    'basePath' => '@webroot/assets',
                    'baseUrl' => '@web/assets',
                    'css' => ['all-xyz.css'],
                    'js' => ['all-xyz.js'],
                ],
                'A' => ['css' => [], 'js' => [], 'depends' => ['all']],
                'B' => ['css' => [], 'js' => [], 'depends' => ['all']],
                'C' => ['css' => [], 'js' => [], 'depends' => ['all']],
                'D' => ['css' => [], 'js' => [], 'depends' => ['all']],
            ],
        ],
    ],
];

Как объяснено в подразделе Настройка Комплектов Ресурсов, приведенная выше конфигурация изменяет поведение по умолчанию каждого комплекта. В частности, комплекты A, B, C и D не имеют больше никаких файлов ресурсов. Теперь они все зависят от all комплекта, который содержит скомбинированные all-xyz.css и all-xyz.js файлы. Следовательно, для страницы X, вместо включения исходных файлов ресурсов из комплектов A, B и C, только два этих объединённых файла будут включены, то же самое произойдёт и со страницей Y.

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

return [
    'components' => [
        'assetManager' => [
            'bundles' => require __DIR__ . '/' . (YII_ENV_PROD ? 'assets-prod.php' : 'assets-dev.php'),  
        ],
    ],
];

То есть, массив конфигурации комплекта ресурсов сохраняется в assets-prod.php для режима продакшена, и в assets-dev.php для режима не продакшена (разработки).

Замечание: этот механизм объединения комплектов ресурсов основан на способности yii\web\AssetManager::$bundles перекрывать поля регистрируемых комплектов ресурсов. Однако, как уже было сказано выше, эта возможность не распространяется на изменения, внесенные в комплекты ресурсов на уровне метода yii\web\AssetBundle::init() или после регистрации. Вам следует избегать использования динамических комплектов ресурсов в процессе объединения.

Использование команды asset

Yii предоставляет консольную команду с именем asset для автоматизации подхода, который мы только что описали.

Чтобы использовать эту команду, Вы должны сначала создать файл конфигурации для описания того, как комплекты ресурсов должны быть скомбинированы, и как они должны быть сгруппированы. Затем Вы можете использовать подкоманду asset/template, чтобы сгенерировать первый шаблон и затем отредактировать его под свои нужды.

yii asset/template assets.php

Данная команда сгенерирует файл с именем assets.php в текущей директории. Содержание этого файла можно увидеть ниже:

<?php
/**
 * Файл конфигурации команды консоли "yii asset".
 * Обратите внимание, что в консольной среде, некоторые псевдонимы путей, такие как "@webroot' и '@web ",
 * не могут быть использованы.
 * Пожалуйста, определите отсутствующие псевдонимы путей.
 */
return [
    // Настроить команду/обратный вызов для сжатия файлов JavaScript:
    'jsCompressor' => 'java -jar compiler.jar --js {from} --js_output_file {to}',
    // Настроить команду/обратный вызов для сжатия файлов CSS:
    'cssCompressor' => 'java -jar yuicompressor.jar --type css {from} -o {to}',
    // Whether to delete asset source after compression:
    'deleteSource' => false,
    // Список комплектов ресурсов для сжатия:
    'bundles' => [
        // 'yii\web\YiiAsset',
        // 'yii\web\JqueryAsset',
    ],
    // Комплект ресурса после сжатия:
    'targets' => [
        'all' => [
            'class' => 'yii\web\AssetBundle',
            'basePath' => '@webroot/assets',
            'baseUrl' => '@web/assets',
            'js' => 'js/all-{hash}.js',
            'css' => 'css/all-{hash}.css',
        ],
    ],
    // Настройка менеджера ресурсов:
    'assetManager' => [
    ],
];

Вы должны изменить этот файл и указать в bundles параметре, какие комплекты Вы планируете объединить. В параметре targets вы должны указать, как комплекты должны быть поделены в группы. Вы можете указать одну или несколько групп, как уже было сказано выше.

Примечание: Так как псевдонимы путей @webroot и @web не могут быть использованы в консольном приложении, Вы должны явно задать их в файле конфигурации.

JavaScript файлы объединены, сжаты и записаны в js/all-{hash}.js, где {hash} перенесён из хэша результирующего файла.

Параметры jsCompressor и cssCompressor указывают на консольные команды или обратный вызов PHP, выполняющие JavaScript и CSS объединение/сжатие. По умолчанию Yii использует Closure Compiler для объединения JavaScript файлов и YUI Compressor для объединения CSS файлов. Вы должны установить эти инструменты вручную или настроить данные параметры, чтобы использовать ваши любимые инструменты.

Вы можете запустить команду asset с файлом конфигурации для объединения и сжатия файлов ресурсов, а затем создать новый файл конфигурации комплекта ресурса assets-prod.php:

yii asset assets.php config/assets-prod.php

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

Примечание: в случае если вы перенастраиваете комплекты ресурсов через yii\web\AssetManager::$bundles или yii\web\AssetManager::$assetMap, и хотите, чтобы эти настройки применились для исходных файлов для сжатия, вы должны занести эти опции в раздел assetManager файла кофигурации для команды asset.

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

Для справки: Команда asset является не единственной опцией для автоматического процесса объединения и сжатия ресурсов. Вы можете также использовать такой замечательный инструмент запуска приложений как grunt для достижения той же цели.

Группировка Комплектов Ресурсов

В последнем подразделе, мы пояснили, как объединять все комплекты ресурсов в единый в целях минимизации HTTP запросов для файлов ресурсов, упоминавшихся в приложении. Это не всегда желательно на практике. Например, представьте себе, что Ваше приложение содержит "front end", а также и "back end", каждый из которых использует свой набор JavaScript и CSS файлов. В этом случае, объединение всех комплектов ресурсов с обеих сторон в один не имеет смысла потому, что комплекты ресурсов для "front end" не используются в "back end", и это будет бесполезной тратой трафика - отправлять "back end" ресурсы, когда страница из "front end" будет запрошена.

Для решения вышеуказанной проблемы, вы можете разделить комплекты по группам и объединить комплекты ресурсов для каждой группы. Следующая конфигурация показывает, как Вы можете объединять комплекты ресурсов:

return [
    ...
    // Укажите выходной комплект для групп:
    'targets' => [
        'allShared' => [
            'js' => 'js/all-shared-{hash}.js',
            'css' => 'css/all-shared-{hash}.css',
            'depends' => [
                // Включаем все ресурсы поделённые между 'backend' и 'frontend'
                'yii\web\YiiAsset',
                'app\assets\SharedAsset',
            ],
        ],
        'allBackEnd' => [
            'js' => 'js/all-{hash}.js',
            'css' => 'css/all-{hash}.css',
            'depends' => [
                // Включаем только 'backend' ресурсы:
                'app\assets\AdminAsset'
            ],
        ],
        'allFrontEnd' => [
            'js' => 'js/all-{hash}.js',
            'css' => 'css/all-{hash}.css',
            'depends' => [], // Включаем все оставшиеся ресурсы
        ],
    ],
    ...
];

Как вы можете видеть, комплекты ресурсов поделены на три группы: allShared, allBackEnd и allFrontEnd. Каждая из которых зависит от соответствующего набора комплектов ресурсов. Например, allBackEnd зависит от app\assets\AdminAsset. При запуске команды asset с данной конфигурацией будут объединены комплекты ресурсов согласно приведенной выше спецификации.

Для справки: Вы можете оставить depends конфигурацию пустой для одного из намеченных комплектов. Поступая таким образом, данный комплект ресурсов будет зависеть от всех остальных комплектов ресурсов, от которых другие целевые комплекты не зависят.