4

I'm using Symfony2, with Assetic and Twig. I have various frontend libraries - Backbone, jQuery, jQuery UI, and Bootstrap. Both Bootstrap and jQuery UI include CSS and JS files.

Is there a way that I can define the resources they need to include (including dependencies), and then in Twig / Assetic just include all those resources in one tag? What I'd look to have is something like:

// config.yml <!-- DOES NOT WORK -->
assetic:
  resources:
    jquery:
      js: /filepath/to/jquery.js
    jquery_ui:
      dependencies: jquery
      css: /filepath/to/jqueryui.css
      js: /filepath/to/jqueryui.js
    less:
      js: /filepath/to/less.js
    bootstrap:
      dependencies: { less, jquery }
      js: /filepath/to/bootstrap.js
      css: /filepath/to/bootstrap.css
    backbone:
      dependencies: { jquery }
      js: { /filepath/to/underscore.js, /filepath/to/backbone.js }

// view.html.twig
{% use jquery_ui %}
{% use bootstrap %} 

// outputs all js and css for jQuery, jQueryUI, Less, Backbone, and Bootstrap

I found a couple of related questions:

but neither seems to involve defining the resources in config.yml. Instead, they define them in base.html.twig but that's what I'm trying to avoid.

I tried using the use tag in Twig, by defining a template called 'jquery_ui' and using {% stylesheets %} and {% javascripts %} in that block and then in base.html.twig putting {% use "jquery-ui.html" %}. However, use won't import the template because it has a body.

Community
  • 1
  • 1
Dan Blows
  • 20,846
  • 10
  • 65
  • 96

3 Answers3

16

Although there is indeed support for defining front-end libraries, there is unfortunately no support for dependency resolving. You must also define your CSS and JavaScript separately.

What I have been doing, is creating a separate file in /app/config/ called assets.yml and including it in the main configuration to keep things clean.

assetic:
    assets:
        jquery:
            inputs:
                - '%kernel.root_dir%/Resources/public/js/jquery.js'
                - '%kernel.root_dir%/Resources/public/js/jquery-ui.js'
        my_lib:
            inputs:
                - '%kernel.root_dir%/Resources/public/js/my-custom-lib.js'
                - ...

Note that ´%kernel.root_dir%´ resolves to the app directory by default in Symfony2. You may now use the assets in your Twig templates.

{% block javascripts %}
    {% javascripts '@jquery' '@my_lib' output="js/jquery.js" %}
        <script type="text/javascript" src="{{ asset_url }}"></script>
    {% endjavascripts %}
{% endblock %}

The same could be done for CSS files. The example also demonstrates why it's not possible to define CSS and JavaScript as a single asset.

kgilden
  • 10,336
  • 3
  • 50
  • 48
  • I recommend to use a `package.json` in the root of the project, and a keep notes of how to rebuild the workspace in files at the root of the project. Sometimes I also add scripts in the `app/` directory. – renoirb Jul 17 '12 at 01:33
  • How could I use package.json for that? – P. R. Ribeiro Jul 25 '12 at 12:06
  • This looks brilliant. However, I have a question about what happens when you extend the template's `{% block javascripts %}`?. Presumably you need to use the `{{ parent() }}` placeholder in the child. Would it be better to define the `{% javascripts %}` tag outside of the `{% block javascripts %}` to avoid having to type this each time? Can the child-template also include a `{% javascripts %}` tag? Is Assetic still clever enough to compile only one css/js file? Or does it compile one for the 'global' site, and another for the extending bundle? – cartbeforehorse Aug 10 '13 at 13:39
  • 1
    @cartbeforehorse Well yeah. you'd have to use `{{ parent() }}` if you're extending a template and want to add some more scripts to the page. Assetic doesn't compile the parent scripts and scripts in the extended template to a single file and that in my opinion is good - the client will cache common scripts and download unique scripts for a page. Alternatively you could define a separate block if you don't want to write `{{ parent() }}` every time. – kgilden Aug 11 '13 at 05:38
  • @gilden I should have done more testing first before asking my questions. My confusion stemmed from the fact that I didn't fully understand the `{% javascripts %}` tag. I did a bit more research, and understand a bit better now. Thanks for your reply though -- it confirms everything else I found too, which is reassuring. – cartbeforehorse Aug 12 '13 at 05:52
  • @gilden How does the javascripts tag know how to use `@jquery` and `@my_lib` in this example? Where is this documented? – BadHorsie Jan 09 '15 at 17:37
  • @BadHorsie it's in [one of the Symfony cookbooks](http://symfony.com/doc/current/cookbook/assetic/asset_management.html#using-named-assets). If you're wondering how it's wired together with Assetic, then that's done in [AsseticBundle](https://github.com/symfony/AsseticBundle/blob/v2.5.0/DependencyInjection/AsseticExtension.php#L59) during container building. – kgilden Jan 09 '15 at 17:56
1

The simplest solution is to put them in appropriate directories in the web/ directory as this is the root of your site that is served for all your Symfony bundles.

Rob Tyler
  • 31
  • 2
0

You might want to check out Cartero, which allows you to define "asset bundles", including dependencies, and then include those bundles in your page.

https://github.com/rotundasoftware/cartero

You would need to write a Symfony2 Hook, but that wouldn't be too difficult.

Brave Dave
  • 1,300
  • 14
  • 9