Как использовать Assetic для управления ресурсами

Как использовать Assetic для управления ресурсами

Установка и подключение Assetic

Начиная с Symfony 2.8, Assetic больше не включён по умолчанию в стандартную версию Symfony. До использования каких-либо из его функций, установите AsseticBundle, выполнив консольную команду в вашем проекте:

1
$ composer require symfony/assetic-bundle

Далее, включите пакет в файле AppKernel.php вашего приложения Symfony:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
// app/AppKernel.php

// ...
class AppKernel extends Kernel
{
    // ...

    public function registerBundles()
    {
        $bundles = array(
            // ...
            new Symfony\Bundle\AsseticBundle\AsseticBundle(),
        );

        // ...
    }
}

Наконец, добавьте следующую минимальную конфигурацию, чтобы включить поддержку Assetic в вашем приложении:

  • YAML
    1
    2
    3
    4
    5
    6
    7
    8
    # app/config/config.yml
    assetic:
        debug:          '%kernel.debug%'
        use_controller: '%kernel.debug%'
        filters:
            cssrewrite: ~
    
    # ...
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    <!-- app/config/config.xml -->
    <?xml version="1.0" encoding="UTF-8" ?>
    <container xmlns="http://symfony.com/schema/dic/services"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:assetic="http://symfony.com/schema/dic/assetic"
        xsi:schemaLocation="http://symfony.com/schema/dic/services
            http://symfony.com/schema/dic/services/services-1.0.xsd
            http://symfony.com/schema/dic/assetic
            http://symfony.com/schema/dic/assetic/assetic-1.0.xsd">
    
        <assetic:config debug="%kernel.debug%" use-controller="%kernel.debug%">
            <assetic:filters cssrewrite="null" />
        </assetic:config>
    
        <!-- ... -->
    </container>
    
  • PHP
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    // app/config/config.php
    $container->loadFromExtension('assetic', array(
        'debug' => '%kernel.debug%',
        'use_controller' => '%kernel.debug%',
        'filters' => array(
            'cssrewrite' => null,
        ),
        // ...
    ));
    
    // ...
    

Введение в Assetic

Assetic объединяет две главные идеи: ресурсы и фильтры. Ресурсы - это файлы вроде CSS, JavaScript и изображений. Фильтры - это то, что может быть применено к этим файлам до того, как они подаются браузеру. Это позволяет разграничивать файлы ресурсов, хранящиеся в приложении, и файлы, на самом деле представленные пользователю.

Без Assetic вы просто поставляете файлы, которые хранятся напрямую в приложении:

  • Twig
    1
    <script src="{{ asset('js/script.js') }}"></script>
    
  • PHP
    1
    <script src="<?php echo $view['assets']->getUrl('js/script.js') ?>"></script>
    

Но с Assetic, вы можете управлять этими ресурсами так, как вы хотите (или загружать их откуда угодно) до того, как представлять их. Это значит, что вы можете:

  • Уменьшать и комбинировать все ваши файлы CSS и JS
  • Запускать все (или только некоторые) ваши файлы CSS или JS через какой-то компилировщик, вроде LESS, SASS или CoffeeScript
  • Выполнять оптимизацию ваших изображений

Ресурсы

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

Вы можете использовать Assetiс, чтобы обрабатывать таблицы стилей CSS, файлы JavaScript и изображения. Философия, стоящая за добавлением чего-либо из этого, по сути одинакова, но с несколько разным синтаксисом.

Добавление файлов JavaScript

Чтобы добавить файлы JavaScript, используйте тег javascripts в любом шаблоне:

  • Twig
    1
    2
    3
    {% javascripts '@AppBundle/Resources/public/js/*' %}
        <script src="{{ asset_url }}"></script>
    {% endjavascripts %}
    
  • PHP
    1
    2
    3
    4
    5
    <?php foreach ($view['assetic']->javascripts(
        array('@AppBundle/Resources/public/js/*')
    ) as $url): ?>
        <script src="<?php echo $view->escape($url) ?>"></script>
    <?php endforeach ?>
    

Note

Если ваши щаблоны приложения используют имена блоков по умолчанию из стандартной версии Symfony, то тег javascripts будет скорее всего находиться в блоке javascripts:

1
2
3
4
5
6
7
{# ... #}
{% block javascripts %}
    {% javascripts '@AppBundle/Resources/public/js/*' %}
        <script src="{{ asset_url }}"></script>
    {% endjavascripts %}
{% endblock %}
{# ... #}

Tip

Вы также можете добавлять таблицы стилей CSS: см. Добавление таблиц стилей CSS.

В этом примере, все файлы в каталоге Resources/public/js/ AppBundle будут загружены и поданы из разных локаций. Отображённый тег может выглядеть просто так:

1
<script src="/app_dev.php/js/abcd123.js"></script>

Это ключевой момент: как только вы позволите Assetic заниматься вашими ресурсами, файлы подаются из другой лоакции. Это вызовет проблемы с CSS-файлами, которые ссылаются на изображения в своих относительных путях. См. Исправление CSS-путей с помощью фильтра cssrewrite.

Добавление таблиц стилей CSS

Чтобы добавить таблицы стилей CSS, вы можете использовать ту же технику, что была разъяснена выше, только с тегом stylesheets:

  • Twig
    1
    2
    3
    {% stylesheets 'bundles/app/css/*' filter='cssrewrite' %}
        <link rel="stylesheet" href="{{ asset_url }}" />
    {% endstylesheets %}
    
  • PHP
    1
    2
    3
    4
    5
    6
    <?php foreach ($view['assetic']->stylesheets(
        array('bundles/app/css/*'),
        array('cssrewrite')
    ) as $url): ?>
        <link rel="stylesheet" href="<?php echo $view->escape($url) ?>" />
    <?php endforeach ?>
    

Note

Если ваши щаблоны приложения используют имена блоков по умолчанию из стандартной версии Symfony, то тег stylesheets будет скорее всего находиться в блоке stylesheets:

1
2
3
4
5
6
7
{# ... #}
{% block stylesheets %}
    {% stylesheets 'bundles/app/css/*' filter='cssrewrite' %}
        <link rel="stylesheet" href="{{ asset_url }}" />
    {% endstylesheets %}
{% endblock %}
{# ... #}

Но так как Assetic изменяет пути к вашим ресурсам, это поломает все фоновые изображения (или другие пути). которые используют относительные пути, разве что вы используете фильтр cssrewrite.

Note

Заметьте, что в первоначальном примере, который включал файлы JavaScript files, вы ссылались на файлы, используя путь вроде @AppBundle/Resources/public/file.js, но в этом примере, вы ссылались на CSS-файлы, используя их настоящий публичнодоступный путь: bundles/app/css. Вы можете использовать любой, однако существует известная проблема, которая вызывает ошибку фильтра cssrewrite при исполоьзовании синтаксиса @AppBundle для таблиц стилей CSS.

Добавление изображений

Чтобы добавить изображение, вы можете использовать тег image.

  • Twig
    1
    2
    3
    {% image '@AppBundle/Resources/public/images/example.jpg' %}
        <img src="{{ asset_url }}" alt="Example" />
    {% endimage %}
    
  • PHP
    1
    2
    3
    4
    5
    <?php foreach ($view['assetic']->image(
        array('@AppBundle/Resources/public/images/example.jpg')
    ) as $url): ?>
        <img src="<?php echo $view->escape($url) ?>" alt="Example" />
    <?php endforeach ?>
    

Вы также можете использовать Assetic для оптимизации изображений. Больше информации вы найдёте в How to Use Assetic for Image Optimization with Twig Functions.

Tip

Вместо использования Assetic для добавления изображений, вы можете рассмотреть исползование общественного пакета LiipImagineBundle, который позволяет сжимать и изменять изображения (поворачивать, изменять размер, наносить водяной знак, и т.д.) до их подачи.

Исправление CSS-путей с помощью фильтра cssrewrite

Так как Assetic генерирует новые URL для ваших ресурсов, любые относительные пути внутри ваших CSS-файлов поломаются. Чтобы исправить это, убедитесь в том, что вы используете фильтр cssrewrite с вашим тегом stylesheets. Это анализирует ваши CSS-файлы и внутренне исправляет пути, чтобы отобразить новую локацию.

Вы можете увидеть пример в предыдущем разделе.

Caution

При использовании фильтра cssrewrite, не ссылайтесь на ваши CSS-файлы, используя синтаксис @AppBundle. См. примечание в разделе выше, чтобы узнать детали.

Комбинирование ресурсов

Одной из функций Assetic является то, что он будет комбинировать много файлов в один. Это помогает уменьшить количество HTTP-запросов, что отлично для фронт-энд производительности. Это также позволит вам легче содержать файлы, разделяя их на управляемые части. Это может помочь с повторным использование, так как вы можете с лёгкостю отделить файлы, относящиеся к конкретному проекту, от тех, которые могут быть использованы в другихприложениях, но всё равно подавать их, как единый файл:

  • Twig
    1
    2
    3
    4
    5
    6
    {% javascripts
        '@AppBundle/Resources/public/js/*'
        '@AcmeBarBundle/Resources/public/js/form.js'
        '@AcmeBarBundle/Resources/public/js/calendar.js' %}
        <script src="{{ asset_url }}"></script>
    {% endjavascripts %}
    
  • PHP
    1
    2
    3
    4
    5
    6
    7
    8
    9
    <?php foreach ($view['assetic']->javascripts(
        array(
            '@AppBundle/Resources/public/js/*',
            '@AcmeBarBundle/Resources/public/js/form.js',
            '@AcmeBarBundle/Resources/public/js/calendar.js',
        )
    ) as $url): ?>
        <script src="<?php echo $view->escape($url) ?>"></script>
    <?php endforeach ?>
    

В окружении dev, каждый файл всё ещё подаётся индивидуально, чтобы вы могли легче отладить проблемы. Однако, в окружении prod (или, точнее, когда флажок debug - false), это будет отображено как единый тег script, который содержит содержимой всех файлов JavaScript.

Tip

Если вы новичок в Assetic и пробуете использовать ваше приложение в окружении prod (используя контроллер app.php), то вы скорее всего увидите, что весь ваш CSS и JS сломается. Не волнуйтесь! Это специально. Чтобы узнать детали об использовании Assetic в окружении prod, см. Сброс файлов ресурса.

И комбинирование файлов не применяется только к вашим файлам. Вы также можете использовать Assetic, чтобы комбинировать сторонние ресурсы, например, jQuery, с вашими, в один общий файл:

  • Twig
    1
    2
    3
    4
    5
    {% javascripts
        '@AppBundle/Resources/public/js/thirdparty/jquery.js'
        '@AppBundle/Resources/public/js/*' %}
        <script src="{{ asset_url }}"></script>
    {% endjavascripts %}
    
  • PHP
    1
    2
    3
    4
    5
    6
    7
    8
    <?php foreach ($view['assetic']->javascripts(
        array(
            '@AppBundle/Resources/public/js/thirdparty/jquery.js',
            '@AppBundle/Resources/public/js/*',
        )
    ) as $url): ?>
        <script src="<?php echo $view->escape($url) ?>"></script>
    <?php endforeach ?>
    

Использование названных ресурсов

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

  • YAML
    1
    2
    3
    4
    5
    6
    7
    # app/config/config.yml
    assetic:
        assets:
            jquery_and_ui:
                inputs:
                    - '@AppBundle/Resources/public/js/thirdparty/jquery.js'
                    - '@AppBundle/Resources/public/js/thirdparty/jquery.ui.js'
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    <!-- app/config/config.xml -->
    <?xml version="1.0" encoding="UTF-8"?>
    <container xmlns="http://symfony.com/schema/dic/services"
        xmlns:assetic="http://symfony.com/schema/dic/assetic"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://symfony.com/schema/dic/services
            http://symfony.com/schema/dic/services/services-1.0.xsd
            http://symfony.com/schema/dic/assetic
            http://symfony.com/schema/dic/assetic/assetic-1.0.xsd">
    
        <assetic:config>
            <assetic:asset name="jquery_and_ui">
                <assetic:input>@AppBundle/Resources/public/js/thirdparty/jquery.js</assetic:input>
                <assetic:input>@AppBundle/Resources/public/js/thirdparty/jquery.ui.js</assetic:input>
            </assetic:asset>
        </assetic:config>
    </container>
    
  • PHP
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    // app/config/config.php
    $container->loadFromExtension('assetic', array(
        'assets' => array(
            'jquery_and_ui' => array(
                'inputs' => array(
                    '@AppBundle/Resources/public/js/thirdparty/jquery.js',
                    '@AppBundle/Resources/public/js/thirdparty/jquery.ui.js',
                ),
            ),
        ),
    ));
    

После того, как вы определили названные ресурсы, вы можете ссылаться на них в ваших шаблонах с примечанием @named_asset:

  • Twig
    1
    2
    3
    4
    5
    {% javascripts
        '@jquery_and_ui'
        '@AppBundle/Resources/public/js/*' %}
        <script src="{{ asset_url }}"></script>
    {% endjavascripts %}
    
  • PHP
    1
    2
    3
    4
    5
    6
    7
    8
    <?php foreach ($view['assetic']->javascripts(
        array(
            '@jquery_and_ui',
            '@AppBundle/Resources/public/js/*',
        )
    ) as $url): ?>
        <script src="<?php echo $view->escape($url) ?>"></script>
    <?php endforeach ?>
    

Фильтры

Когда он уже управляются Assetic, вы можете применять фильтры к вашим ресурсам до того, как они подаются. Это включает в себя фильтры, которые сжимают вывод ваших ресурсов для меньшего размера файлов (и лучшей фронт-энд оптимизации). Другие фильтры могут компилировать файлы CoffeeScript в JavaScript и обрабатывать SASS в CSS. На самом деле, Assetic имеет большой список доступных фильтров.

Многие из фильтров не работают напрямую, но используют существующие сторонние библиотеки для тяжёлой работы. Это означает, что вам часто будет нужно устанавливать сторонние библиотеки, чтобы использовать фильтр. Огромным преимуществом использования Assetic для вызова этих библиотек (а не использования их напрямую) является то, что вместо того, чтобы вручную запускать их после работы с файлами, Assetic позаботится об этом за васи удалит этот шаг из вашего процесса разработки и развёртывания.

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

Например, чтобы использовать уменьшитель UglifyJS JavaScript, нужно определить следующую конфигурацию:

  • YAML
    1
    2
    3
    4
    5
    # app/config/config.yml
    assetic:
        filters:
            uglifyjs2:
                bin: /usr/local/bin/uglifyjs
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    <!-- app/config/config.xml -->
    <?xml version="1.0" encoding="UTF-8"?>
    <container xmlns="http://symfony.com/schema/dic/services"
        xmlns:assetic="http://symfony.com/schema/dic/assetic"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://symfony.com/schema/dic/services
            http://symfony.com/schema/dic/services/services-1.0.xsd
            http://symfony.com/schema/dic/assetic
            http://symfony.com/schema/dic/assetic/assetic-1.0.xsd">
    
        <assetic:config>
            <assetic:filter
                name="uglifyjs2"
                bin="/usr/local/bin/uglifyjs" />
        </assetic:config>
    </container>
    
  • PHP
    1
    2
    3
    4
    5
    6
    7
    8
    // app/config/config.php
    $container->loadFromExtension('assetic', array(
        'filters' => array(
            'uglifyjs2' => array(
                'bin' => '/usr/local/bin/uglifyjs',
            ),
        ),
    ));
    

Теперь, чтобы действительно использовать фильтр в группе файлов JavaScript, добавьте его в ваш шаблон:

  • Twig
    1
    2
    3
    {% javascripts '@AppBundle/Resources/public/js/*' filter='uglifyjs2' %}
        <script src="{{ asset_url }}"></script>
    {% endjavascripts %}
    
  • PHP
    1
    2
    3
    4
    5
    6
    <?php foreach ($view['assetic']->javascripts(
        array('@AppBundle/Resources/public/js/*'),
        array('uglifyjs2')
    ) as $url): ?>
        <script src="<?php echo $view->escape($url) ?>"></script>
    <?php endforeach ?>
    

Более детализированный справочник о конфигурации и использовании фильтров Assetic, а также детали о режиме отладки Assetic, можно найти в How to Minify CSS/JS Files (Using UglifyJS and UglifyCSS).

Контролирование использованного URL

Если вы хотите, вы можете контролировать URL, которые производит Assetic. Это делается из шаблона и имеет отношение к корню публичного документа:

  • Twig
    1
    2
    3
    {% javascripts '@AppBundle/Resources/public/js/*' output='js/compiled/main.js' %}
        <script src="{{ asset_url }}"></script>
    {% endjavascripts %}
    
  • PHP
    1
    2
    3
    4
    5
    6
    7
    <?php foreach ($view['assetic']->javascripts(
        array('@AppBundle/Resources/public/js/*'),
        array(),
        array('output' => 'js/compiled/main.js')
    ) as $url): ?>
        <script src="<?php echo $view->escape($url) ?>"></script>
    <?php endforeach ?>
    

Note

Symfony также содержит метод для отключения кеширования, когда финальный URL, сгенерированный Assetic содержит параметр запроса, который может быть приращен через конфигурацию при каждом развёртывании. Чтобы узнать больше, см. опцию конфигурации version.

Сброс файлов ресурса

В окружении dev, Assetic генерирует пути к файлам CSS и JavaScript, которые физически не существуют на вашем компьютере. Но они всё равно отображаются, так как внутренний контроллер Symfony открывает файлы и подаёт обратно содержимое (после выполнения фильтров).

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

К счастью, Assetic предоставляет способ сбросить ваши ресурсы в настоящие файлы, вместо того, чтобы быть сгенерированными динамически.

Сброс файлов ресурсов в окружении prod

В окружении prod, ваши файлы JS и CSS каждый представлены одним тегом. Другими словами, вместотого, чтобы видеть каждый файл JavaScript, который вы включаете в ваш источник, вы скорее всего увидите что-то вроде:

1
<script src="/js/abcd123.js"></script>

Более того, этот файл на самом деле не существует, и не отображается Symfony динамически (как отображаются файлы ресурсов в окружении dev). Это специально - позволить Symfony генерировать эти файлы динамически в окружении производства просто слишком долго.

Вместо этого, каждый раз, когда вы используете ваше приложение в окружении prod (и, соответственно, каждый раз при запуске), вам нужно выполнять следующую команду:

1
$ php bin/console assetic:dump --env=prod --no-debug

Это физически сгенерируети написать каждый нужный вам файл (например, /js/abcd123.js). Если вы обновите любой из ваших ресурсов, то вам нужно будет выполнитьэто опять, чтобы сгенерировать файл.

Сброс файлов ресурсов в окружении dev

По умолчанию, каждый путь ресурса, сгенерированный в окружении dev, динамически обрабатывается Symfony. Это не имеет недостатков (вы можете увидеть ваши изменения немедленно), кроме того, что ресурсы могут загружаться заметно долго. Если вам кажется, что ваши ресурсы загружаются слишком долго, следуйте этому справочнику.

Во-первых, скажите Symfony перестать пытаться обработать эти файлы динамически. Сделайте следующее изменение в вашем файле config_dev.yml:

  • YAML
    1
    2
    3
    # app/config/config_dev.yml
    assetic:
        use_controller: false
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    <!-- app/config/config_dev.xml -->
    <?xml version="1.0" encoding="UTF-8"?>
    <container xmlns="http://symfony.com/schema/dic/services"
        xmlns:assetic="http://symfony.com/schema/dic/assetic"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://symfony.com/schema/dic/services
            http://symfony.com/schema/dic/services/services-1.0.xsd
            http://symfony.com/schema/dic/assetic
            http://symfony.com/schema/dic/assetic/assetic-1.0.xsd">
    
        <assetic:config use-controller="false" />
    </container>
    
  • PHP
    1
    2
    3
    4
    // app/config/config_dev.php
    $container->loadFromExtension('assetic', array(
        'use_controller' => false,
    ));
    

Далее, так как Symfony больше не генерирует эти ресурсы для вас, вам нужно будет сбросить их вручную. Чтобы сделат это, выполните следующую команду:

1
$ php bin/console assetic:dump

Это физически пишет все файлы ресурсов, нужные вам для вашего окружения dev. Большим недостатком является то, что вам нужно выполнять это каждый раз,когда вы обновляете ресурс. К счастью, при использовании команды assetic:watch, ресурсы будут сгенерированы автоматически при их изменении:

1
$ php bin/console assetic:watch

Команды assetic:watch была представлена в AsseticBundle 2.4. В более ранних версиях вам нужно было использовать опцию --watch команды assetic:dump для такого же поведения.

Так как выполнение этой команды в окружении dev может сгенерировать кучу файлов, обычно хорошей идеей считается направить ваши сгенерированные файлы ресурсов в какой-то изолированный каталог (например, /js/compiled), чтобы всё было систематизировано:

  • Twig
    1
    2
    3
    {% javascripts '@AppBundle/Resources/public/js/*' output='js/compiled/main.js' %}
        <script src="{{ asset_url }}"></script>
    {% endjavascripts %}
    
  • PHP
    1
    2
    3
    4
    5
    6
    7
    <?php foreach ($view['assetic']->javascripts(
        array('@AppBundle/Resources/public/js/*'),
        array(),
        array('output' => 'js/compiled/main.js')
    ) as $url): ?>
        <script src="<?php echo $view->escape($url) ?>"></script>
    <?php endforeach ?>
    

Эта документация является переводом официальной документации Symfony и предоставляется по свободной лицензии CC BY-SA 3.0.