Symfony2: Using Assetic from Twig

After my earlier post digging in to how Assetic (Symfony2's asset manager) works, I am now going to look at how you should actually use it from Symfony2's templating engine Twig. Kris Wallsmith the developer of Assetic pointed me in the right direction in the comments on that post. He has now added some official documentation on the Symfony site. This post covers much the same ground, but I had written the bulk of it yesterday before they were added so I am going to post it anyway.

It turns out it's much simpler than I had made it, putting the following into my base.html.twig file and updating the YUI compressor location in config.yml just achieved the mapping for my main CSS file:

{% stylesheets filter='yui_css' 
    '@LimeThinkingSpringBundle/Resources/css/overall.css'
    '@LimeThinkingSpringBundle/Resources/css/social.css' 
%}
    <link href="{{ asset_url }}" rel="stylesheet" media="screen" />
{% endstylesheets %}

In my defence with regards to overcomplicating things I could just not get this working at all when I last tried with PR7 of Symfony2 which lead to my getting sidetracked.

Basic Usage

So let's have a look in more detail at what is going on with the above. The only thing that you need to include in the %stylesheets% config is a file to make up the served file:

{% stylesheets 
    '@LimeThinkingSpringBundle/Resources/css/overall.css' 
%}
    <link href="{{ asset_url }}" rel="stylesheet" media="screen" />
{% endstylesheets %}

This will just include the single file as is, this does not provide much advantage over serving it directly apart from allowing you to keep the files out of the public web folder.

To combine multiple files they can just be added to the %stylesheets% tag, there is no separator needed between them:

{% stylesheets 
    '@LimeThinkingSpringBundle/Resources/css/overall.css'
    '@LimeThinkingSpringBundle/Resources/css/social.css' 
%}
    <link href="{{ asset_url }}" rel="stylesheet" media="screen" />
{% endstylesheets %}

Both files will now be served up as a single file allowing them to be maintained separately but served as single file to reduce HTTP requests. Further gains can be made by compressing the files, one of the built in Assetic filters is the YUI Compressor, adding the following will compress the combined file:

{% stylesheets filter='yui_css' 
    '@LimeThinkingSpringBundle/Resources/css/overall.css'
    '@LimeThinkingSpringBundle/Resources/css/social.css' 
%}
    <link href="{{ asset_url }}" rel="stylesheet" media="screen" />
{% endstylesheets %}

For more on the installation and configuration of the YUI Compressor for use with Assetic read http://sftuts.com/using-assetic-in-symfony2-for-css-compression

You can specify multiple filters by listing the common separated in the filter attribute e.g. filter="less,yui_css". You can see a list of the filters currently included in the GitHub documentation and read more about using the LESS filter at Dustin Dobervich's Blog.

By default the file will be served up with a URL such as /css/4586f12.css you can specify it though by adding an output attribute:

{% stylesheets filter='yui_css' 
     output="/css/main.css"
    '@LimeThinkingSpringBundle/Resources/css/overall.css'
    '@LimeThinkingSpringBundle/Resources/css/social.css' 
%}
    <link href="{{ asset_url }}" rel="stylesheet" media="screen" />
{% endstylesheets %}

It will now be served up from /css/main.css

Debug mode

Working in the dev environment it may not be working as you expect from the description above. This is because in debug mode each file is still served separately. You can explicitly set the debug mode in config.yml, by default it is set to the %kernel.debug% global parameter, meaning that it is on in the dev environment. You can also control it from within Twig with the debug attribute:

{% stylesheets filter='yui_css' 
     output="/css/main.css"
     debug=false
    '@LimeThinkingSpringBundle/Resources/css/overall.css'
    '@LimeThinkingSpringBundle/Resources/css/social.css' 
%}
    <link href="{{ asset_url }}" rel="stylesheet" media="screen" />
{% endstylesheets %}

Note, no quotation marks should be placed around the value.

In debug mode the files are served up separately as /css/main_overall1.css and /css/main_social2.css making it easier to work with them. As it stands though the yui_css filter is still applied in debug mode. This can be changed by placing a question mark in front of it:

{% stylesheets filter='?yui_css' 
     output="/css/main.css"
     debug=false
    '@LimeThinkingSpringBundle/Resources/css/overall.css'
    '@LimeThinkingSpringBundle/Resources/css/social.css' 
%}
    <link href="{{ asset_url }}" rel="stylesheet" media="screen" />
{% endstylesheets %}

Filters specified in that fashion are not applied in debug mode, it needs to explicitly specified like this because turning off filters such as LESS or SASS does not make sense even in debug mode.

Production

By default Assetic is not routed to in production. For production it is better to save the files directly to the location the browser is expecting to find them as static files. Fortunately this can be done easily enough using the command line.

app/console --env=prod assetic:dump

This will speed up the serving of the files by allowing Apache to deal with the caching headers and PHP to never be touched in serving them in production.