11How to Use Assetic for Asset Management
22=======================================
33
4- Assetic is a powerful asset management library which is packaged with the
5- Symfony2 Standard Edition and can be easily used in Symfony2 directly from
6- Twig or PHP templates.
7-
84Assetic combines two major ideas: assets and filters. The assets are files
9- such as CSS, JavaScript andimages files. The filters are things that can
5+ such as CSS, JavaScript andimage files. The filters are things that can
106be applied to these files before they are served to the browser. This allows
117a separation between the asset files stored in the application and the files
128actually presented to the user.
@@ -46,7 +42,8 @@ drawn from various sources such as from within a bundle:
4642
4743 ..code - block:: html+ jinja
4844
49- {% javascripts' @AcmeFooBundle/Resources/public/js/*'
45+ {% javascripts
46+ ' @AcmeFooBundle/Resources/public/js/*'
5047% }
5148< script type= " text/javascript" src= " {{ asset_url }}" > </script >
5249 {% endjavascripts %}
@@ -58,27 +55,62 @@ drawn from various sources such as from within a bundle:
5855 <script type="text/javascript" src="<?php echo $view->escape($url) ?>"></script>
5956 <?php endforeach; ?>
6057
58+ ..tip ::
59+
60+ To bring in CSS stylesheets, you can use the same methodologies seen
61+ in this entry, except with the `stylesheets ` tag:
62+
63+ ..configuration-block ::
64+
65+ ..code-block ::html+jinja
66+
67+ {% stylesheets
68+ '@AcmeFooBundle/Resources/public/css/*'
69+ %}
70+ <link rel="stylesheet" href="{{ asset_url }}" />
71+ {% endstylesheets %}
72+
73+ ..code-block ::html+php
74+
75+ <?php foreach ($view['assetic']->stylesheets(
76+ array('@AcmeFooBundle/Resources/public/css/*')) as $url): ?>
77+ <link rel="stylesheet" href="<?php echo $view->escape($url) ?>" />
78+ <?php endforeach; ?>
79+
6180In this example, all of the files in the ``Resources/public/js/ `` directory
6281of the ``AcmeFooBundle `` will be loaded and served from a different location.
6382The actual rendered tag might simply look like:
6483
65- <script src="/js/abcd123.js"></script>
84+ ..code-block ::html
85+
86+ <script src =" /app_dev.php/js/abcd123.js" ></script >
87+
88+ ..note ::
89+
90+ This is a key point: once you let Assetic handle your assets, the files are
91+ served from a different location. This *can * cause problems with CSS files
92+ that reference images by their relative path. However, this can be fixed
93+ by using the ``cssrewrite `` filter, which updates paths in CSS files
94+ to reflect their new location.
95+
96+ Combining Assets
97+ ~~~~~~~~~~~~~~~~
6698
6799You can also combine several files into one. This helps to reduce the number
68- of HTTP requests which is good for front end performance, as most browsers
69- will only process a limited number at a time slowing down page load times.
70- It also allows you to maintain the files more easily by splitting them into
71- manageable parts. This can also help with re-usability as you can easily
72- split project specific files from those which can be used in other applications
73- but still serve them as a single file:
100+ of HTTP requests, which is great for front end performance. It also allows
101+ you to maintain the files more easily by splitting them into manageable parts.
102+ This can help with re-usability as you can easily split project-specific
103+ files from those which can be used in other applications, but still serve
104+ them as a single file:
74105
75106..configuration-block ::
76107
77108 ..code-block ::html+jinja
78109
79- {% javascripts '@AcmeFooBundle/Resources/public/js/*'
80- '@AcmeBarBundle/Resources/public/js/form.js'
81- '@AcmeBarBundle/Resources/public/js/calendar.js'
110+ {% javascripts
111+ '@AcmeFooBundle/Resources/public/js/*'
112+ '@AcmeBarBundle/Resources/public/js/form.js'
113+ '@AcmeBarBundle/Resources/public/js/calendar.js'
82114 %}
83115 <script src="{{ asset_url }}"></script>
84116 {% endjavascripts %}
@@ -92,15 +124,27 @@ but still serve them as a single file:
92124 <script src="<?php echo $view->escape($url) ?>"></script>
93125 <?php endforeach; ?>
94126
95- This does not only apply to your own files you can also use Assetic to
96- combine third party assets, such as jQuery with your own into a single file:
127+ In the `dev ` environment, each file is still served individually, so that
128+ you can debug problems more easily. However, in the `prod ` environment, this
129+ will be rendered as a single `script ` tag.
130+
131+ ..tip ::
132+
133+ If you're new to Assetic and try to use your application in the ``prod ``
134+ environment (by using the ``app.php `` controller), you'll likely see
135+ that all of your CSS and JS breaks. Don't worry! This is on purpose.
136+ For details on using Assetic in the `prod ` environment, see:ref: `cookbook-assetic-dumping `.
137+
138+ And combining files doesn't only apply to *your * files. You can also use Assetic to
139+ combine third party assets, such as jQuery, with your own into a single file:
97140
98141..configuration-block ::
99142
100143 ..code-block ::html+jinja
101144
102- {% javascripts '@AcmeFooBundle/Resources/public/js/thirdparty/jquery.js'
103- '@AcmeFooBundle/Resources/public/js/*'
145+ {% javascripts
146+ '@AcmeFooBundle/Resources/public/js/thirdparty/jquery.js'
147+ '@AcmeFooBundle/Resources/public/js/*'
104148 %}
105149 <script src="{{ asset_url }}"></script>
106150 {% endjavascripts %}
@@ -116,21 +160,26 @@ combine third party assets, such as jQuery with your own into a single file:
116160Filters
117161-------
118162
119- Additionally to this Assetic can apply filters to the assets before they
120- are served. This includes tasks such as compressing the output for smaller
121- file sizes which is another valuable front end optimisation. Other filters
122- include compiling JavaScript file from CoffeeScript files and SASS to CSS.
163+ Once they're managed by Assetic, you can apply filters to your assets before
164+ they are served. This includes filters that compress the output of your assets
165+ for smaller file sizes (and better front-end optimization). Other filters
166+ can compile JavaScript file from CoffeeScript files and process SASS into CSS.
167+ In fact, Assetic has a long list of available filters.
168+
169+ Many of the filters do not do the work directly, but use existing third-party
170+ libraries to do the heavy-lifting. This means that you'll often need to install
171+ a third-party library to use a filter. The great advantage of using Assetic
172+ to invoke these libraries (as opposed to using them directly) is that instead
173+ of having to run them manually after you work on the files, Assetic will
174+ take care of this for you and remove this step altogether from your development
175+ and deployment processes.
123176
124- Many of the filters do not do the work directly but use other libraries
125- to do it, this so you will often have to install that software as well.
126- The great advantage of using Assetic to invoke these libraries is that
127- instead of having to run them manually when you have worked on the files,
128- Assetic will take care of this for you and remove this step altogether
129- from your development and deployment processes.
177+ To use a filter, you first need to specify it in the Assetic configuration.
178+ Adding a filter here doesn't mean it's being used - it just means that it's
179+ available to use (we'll use the filter below).
130180
131- To use a filter you must specify it in the Assetic configuration
132- as they are not enabled by default. For example to use the JavaScript YUI
133- Compressor the following config needs to be added:
181+ For example to use the JavaScript YUI Compressor the following config should
182+ be added:
134183
135184..configuration-block ::
136185
@@ -162,14 +211,17 @@ Compressor the following config needs to be added:
162211 ),
163212 ));
164213
165-
166- You can then specify using the filter in the template:
214+ Now, to actually * use * the filter on a group of JavaScript files, add it
215+ into your template:
167216
168217..configuration-block ::
169218
170219 ..code-block ::html+jinja
171220
172- {% javascripts '@AcmeFooBundle/Resources/public/js/*' filter='yui_js' %}
221+ {% javascripts
222+ '@AcmeFooBundle/Resources/public/js/*'
223+ filter='yui_js'
224+ %}
173225 <script src="{{ asset_url }}"></script>
174226 {% endjavascripts %}
175227
@@ -181,22 +233,22 @@ You can then specify using the filter in the template:
181233 <script src="<?php echo $view->escape($url) ?>"></script>
182234 <?php endforeach; ?>
183235
184-
185- A more detail guide to configuring and using Assetic filters as well as
236+ A more detailed guide abour configuring and using Assetic filters as well as
186237details of Assetic's debug mode can be found in:doc: `/cookbook/assetic/yuicompressor `.
187238
188239Controlling the URL used
189240------------------------
190241
191- If you wish to you can control the URLswhich Assetic produces. This is
242+ If you wish to you can control the URLsthat Assetic produces. This is
192243done from the template and is relative to the public document root:
193244
194245..configuration-block ::
195246
196247 ..code-block ::html+jinja
197248
198- {% javascripts '@AcmeFooBundle/Resources/public/js/*'
199- output='js/combined.js'
249+ {% javascripts
250+ '@AcmeFooBundle/Resources/public/js/*'
251+ output='js/compiled/main.js'
200252 %}
201253 <script src="{{ asset_url }}"></script>
202254 {% endjavascripts %}
@@ -206,48 +258,131 @@ done from the template and is relative to the public document root:
206258 <?php foreach ($view['assetic']->javascripts(
207259 array('@AcmeFooBundle/Resources/public/js/*'),
208260 array(),
209- array('output' => 'js/combined .js')
261+ array('output' => 'js/compiled/main .js')
210262 ) as $url): ?>
211263 <script src="<?php echo $view->escape($url) ?>"></script>
212264 <?php endforeach; ?>
213265
214266..note ::
215267
216268 Symfony also contains a method for cache *busting *, where the final URL
217- generated by Assetic in the ``prod `` environment contains a query parameter
218- that can be incremented via configuration on each deployment. For more
219- information, see the:ref: `ref-framework-assets-version ` configuration
220- option.
221-
222- Caching the output
223- ------------------
224-
225- The process of creating the files served up can be quite slow especially
226- when using some of the filters which invoke third party software to the
227- actual work. Even when working in the development environment the slow
228- down in the page loads if this was to be done each time would quickly get
229- frustrating. Fortunately in the dev environment Assetic caches the output
230- so this will not happen, rather than having to clear the cache manually
231- though, it monitors for changes to the assets and regenerates the files
232- as needed. This means you can work on the asset files and see the results
233- on page load but without having to suffer continual slow page loads.
234-
235- For production, where you will not be making changes to the asset files,
236- performance can be increased by avoiding the step of checking for changes.
237- Assetic allows you to go further than this and avoid touching Symfony2
238- and even PHP at all when serving the files. This is done by dumping all
239- of the output files using a console command. These can then be served directly
240- by the web server as static files, increasing performance and allowing the
241- web server to deal with caching headers. The console command to dump the files
242- is:
269+ generated by Assetic contains a query parameter that can be incremented
270+ via configuration on each deployment. For more information, see the
271+ :ref: `ref-framework-assets-version ` configuration option.
272+
273+ .. _cookbook-assetic-dumping :
274+
275+ Dumping Asset Files
276+ -------------------
277+
278+ In the ``dev `` environment, Assetic generates paths to CSS and JavaScript
279+ files that don't physically exist on your computer. But they render nonetheless
280+ because an internal Symfony controller opens the files and serves back the
281+ content (after running any filters).
282+
283+ This kind of dynamic serving of processed assets is great because it means
284+ that you can immediately see the new state of any asset files you change.
285+ It's also bad, because it can be quite slow. If you're using a lot of filters,
286+ it might be downright frustrating.
287+
288+ Fortunately, Assetic provides a way to dump your assets to real files, instead
289+ of being generated dynamically.
290+
291+ Dumping Asset Files in the ``prod `` environment
292+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
293+
294+ In the ``prod `` environment, your JS and CSS files are represented by a single
295+ tag each. In other words, instead of seeing each JavaScript file you're including
296+ in your source, you'll likely just see something like this:
297+
298+ ..code-block ::html
299+
300+ <script src =" /app_dev.php/js/abcd123.js" ></script >
301+
302+ Moreover, that file does **not ** actually exist, nor is it dynamically rendered
303+ by Symfony (as the asset files are in the ``dev `` environment). This is on
304+ purpose - letting Symfony generate these files dynamically in a production
305+ environment is just too slow.
306+
307+ Instead, each time you use your app in the ``prod `` environment (and therefore,
308+ each time you deploy), you should run the following task:
309+
310+ ..code-block ::bash
311+
312+ php app/console assetic:dump --env=prod --no-debug
313+
314+ This will physically generate and write each file that you need (e.g. ``/js/abcd123.js ``).
315+ If you update any of your assets, you'll need to run this again to regenerate
316+ the file.
317+
318+ Dumping Asset Files in the ``dev `` environment
319+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
320+
321+ By default, each asset path generated in the ``dev `` environment is handled
322+ dynamically by Symfony. This has no disadvantage (you can see your changes
323+ immediately), except that assets can load noticeably slow. If you feel like
324+ your assets are loading too slowly, follow this guide.
325+
326+ First, tell Symfony to stop trying to process these files dynamically. Make
327+ the following change in your ``config_dev.yml `` file:
328+
329+ ..configuration-block ::
330+
331+ ..code-block ::yaml
332+
333+ # app/config/config_dev.yml
334+ assetic :
335+ use_controler :false
336+
337+ ..code-block ::xml
338+
339+ <!-- app/config/config_dev.xml-->
340+ <assetic : config use-controller =" false" />
341+
342+ ..code-block ::php
343+
344+ // app/config/config_dev.php
345+ $container->loadFromExtension('assetic', array(
346+ 'use_controller' => false,
347+ ));
348+
349+ Next, since Symfony is no longer generating these assets for you, you'll
350+ need to dump them manually. To do so, run the following:
243351
244352..code-block ::bash
245353
246354 php app/console assetic:dump
247355
248- ..note ::
356+ This physically writes all of the asset files you need for your ``dev ``
357+ environment. The big disadvantage is that you need to run this each time
358+ you update an asset. Fortunately, by passing the ``--watch `` option, the
359+ command will automatically regenerate assets *as they change *:
360+
361+ ..code-block ::bash
362+
363+ php app/console assetic:dump --watch
364+
365+ Since running this command in the ``dev `` environment may generate a bunch
366+ of files, it's usually a good idea to point your generated assets files to
367+ some isolated directory (e.g. ``/js/compiled ``), to keep things organized:
368+
369+ ..configuration-block ::
370+
371+ ..code-block ::html+jinja
372+
373+ {% javascripts
374+ '@AcmeFooBundle/Resources/public/js/*'
375+ output='js/compiled/main.js'
376+ %}
377+ <script src="{{ asset_url }}"></script>
378+ {% endjavascripts %}
249379
250- Once you have dumped the output you will need to run the console
251- command again to see any new changes. If you run it on your development
252- server you will need to remove the files in order to start letting Assetic
253- process the assets on the fly again.
380+ ..code-block ::html+php
381+
382+ <?php foreach ($view['assetic']->javascripts(
383+ array('@AcmeFooBundle/Resources/public/js/*'),
384+ array(),
385+ array('output' => 'js/compiled/main.js')
386+ ) as $url): ?>
387+ <script src="<?php echo $view->escape($url) ?>"></script>
388+ <?php endforeach; ?>