Loading CSS & JS Assets

We have an HTML layout, yay! Good for us!

But... it's super boring... and that's just no fun. Besides, I want to talk about assets!

If you download the code for this project, in the start/ directory, you'll find a tutorial/ directory. I've already copied this into my project. It holds some goodies that we need to help get things looking less ugly, and more interesting!

Copying web files

First, copy the 4 directories in web/... to web/: this includes some CSS, images, JS and vendor files for Bootstrap and FontAwesome:

web/css
web/images
web/js
web/vendor

These are boring, normal, traditional static files: we're not doing anything fancy with frontend assets in this screencast.

Go Deeper!

One way to get fancy is by using Gulp to process, minify and combine assets. See Gulp! Refreshment for Your Frontend Assets.

Ok, important thing: the web/ directory is the document root. In other words, anything in web/ can be accessed by the public. If I wanted to load up that favicon.ico, I'd use my hostname /favicon.ico - like http://localhost:8000/favicon.ico. If a file is outside of web, then it's not publicly accessible.

Including Static Assets

Ok, more work: go into the app/ directory and copy the new base.html.twig file. Paste that over the original and open it up:

41 lines app/Resources/views/base.html.twig
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>{% block title %}AquaNote!{% endblock %}</title>
{% block stylesheets %}
<link rel="stylesheet" href="{{ asset('vendor/bootstrap/css/bootstrap.min.css') }}">
<link rel="stylesheet" href="{{ asset('css/styles.css') }}">
<link rel="stylesheet" href="{{ asset('vendor/fontawesome/css/font-awesome.min.css') }}">
{% endblock %}
<link rel="icon" type="image/x-icon" href="{{ asset('favicon.ico') }}" />
</head>
<body>
<div class="search-bar">
<form method="GET" action="" class="js-sea-search sea-search">
<input type="search" name="q" placeholder="Search Sea Creatures" autocomplete="off" class="search-input">
</form>
</div>
<header class="header">
<img class="logo-icon" src="{{ asset('images/aquanote-logo.png') }}">
<h1 class="logo">AquaNote</h1>
<ul class="navi">
<li class="search"><a href="#" class="js-header-search-toggle"><i class="fa fa-search"></i></a></li>
<li><a href="#">Login</a></li>
</ul>
</header>
{% block body %}{% endblock %}
<div class="footer">
<p class="footer-text">Made with <span class="heart"><3</span> <a href="https://knpuniversity.com">KnpUniversity</a></p>
</div>
{% block javascripts %}
<script src="//code.jquery.com/jquery-2.1.4.min.js"></script>
<script src="{{ asset('js/main.js') }}"></script>
{% endblock %}
</body>
</html>

Hey! We have some real-looking HTML! To bring this to life, we need to include some of those CSS and JS assets that we just put into web/. And here's the key: Symfony doesn't care about your assets... at all. It's not personal, it keeps things simple. You include CSS and JS files the way you always have: with tried-and-true link and script tags. These paths are relative to the web/ directory, because that's the document root.

The stylesheets and javascripts blocks

Ok ok, in reality there are two little-itty-bitty Symfony things to show you about assets. First, notice that the link tags live inside a block called stylesheets:

41 lines app/Resources/views/base.html.twig
... lines 1 - 6
{% block stylesheets %}
<link rel="stylesheet" href="{{ asset('vendor/bootstrap/css/bootstrap.min.css') }}">
<link rel="stylesheet" href="{{ asset('css/styles.css') }}">
<link rel="stylesheet" href="{{ asset('vendor/fontawesome/css/font-awesome.min.css') }}">
{% endblock %}
... lines 12 - 41

Really, technically, that does... nothing! Seriously: you don't have to do this, it will make no difference... for now.

But, in the future, doing this will give you the power to add page-specific CSS by adding more link tags to the bottom of the stylesheets block from inside a child template. I'll show you that later. Just know that it's a good practice to put CSS inside of a block, like stylesheets.

Go Deeper!

How can you add page-specific CSS or JS files? See ReactJS talks to your API.

The same is true for script tags: I've got mine in a block called javascripts:

41 lines app/Resources/views/base.html.twig
... lines 1 - 34
{% block javascripts %}
<script src="//code.jquery.com/jquery-2.1.4.min.js"></script>
<script src="{{ asset('js/main.js') }}"></script>
{% endblock %}
... lines 39 - 41

The asset function

You're probably already looking at the second important Symfony thing about assets: the asset() function. Whenever you refer to a static file, you'll wrap the path in {{ asset() }}. This does... you guessed it! Nothing! Ok, that's not totally true. But it really doesn't do much, and you'd be just fine if you forgot it and hardcoded the path.

So what does asset() do? Well, if you eventually deploy and use a CDN, it will save your butt. With just one tiny config change, Symfony can prefix every static URL with your CDN host. So /css/styles.css becomes http://superfastcdn.com/css/styles.css. That's pretty awesome, so be good and use asset() in case you need it. You can also do some cool cache-busting stuff.

Other than the asset stuff, the base layout is just like before: it has a title block, a body block in the middle and some javascripts. We just added the pretty markup.

Updating show.html.twig

Let's finish this! Copy show.html.twig and overwrite our boring version:

39 lines app/Resources/views/genus/show.html.twig
{% extends 'base.html.twig' %}
{% block title %}Genus {{ name }}{% endblock %}
{% block body %}
<h2 class="genus-name">{{ name }}</h2>
<div class="sea-creature-container">
<div class="genus-photo"></div>
<div class="genus-details">
<dl class="genus-details-list">
<dt>Subfamily:</dt>
<dd>Octopodinae</dd>
<dt>Known Species:</dt>
<dd>289</dd>
<dt>Fun Fact:</dt>
<dd>Octopuses can change the color of their body in just three-tenths of a second!</dd>
</dl>
</div>
</div>
<div class="notes-container">
<h2 class="notes-header">Notes</h2>
<div><i class="fa fa-plus plus-btn"></i></div>
</div>
<section id="cd-timeline">
{% for note in notes %}
<div class="cd-timeline-block">
<div class="cd-timeline-img">
<img src="{{ asset('images/leanna.jpeg') }}" class="img-circle" alt="Leanna!">
</div>
<div class="cd-timeline-content">
<h2><a href="#">AquaPelham</a></h2>
<p>{{ note }}</p>
<span class="cd-date">Dec. 10, 2015</span>
</div>
</div>
{% endfor %}
</section>
{% endblock %}

And yep, it's also similar to before - I swear I'm not trying to sneak in any magic! It still extends base.html.twig, prints out the genus name and loops over the notes. Oh, and hey! When I refer to the image - which is a static file - I'm using the asset() function.

Ok, ready for this? Refresh the page. Boom! So much prettier.

These days, you can do some pretty crazy things with assets via frontend tools like Gulp or PHP tools like Assetic. But you might not need any of these. If you can, keep it simple.

Leave a comment!

  • 2016-08-23 Victor Bocharsky

    Hey James,

    Thanks for your kind words! The most popular OS e-commerce project is Sylius. It has a lot of distributed bundles, including the cart bundle. But probably it's not ready for Symfony 3 yet. You could also check https://github.com/leaphly/Car... bundle, looks pretty popular on GitHub.

    Cheers!

  • 2016-08-23 james

    Very good tutorial until the end! Is there any bundle for a shopping cart for Symfony 3?

    Thanks

  • 2016-07-16 Luciano Marinho

    After searching a lot, i found it, thanks.

  • 2016-07-16 weaverryan

    Hey Luciano! Check out my comment over here about that :) https://knpuniversity.com/scre...

  • 2016-07-15 Luciano Marinho

    I can't find tutorial directory, please help me

  • 2016-07-04 Tadas

    dont 4 get to write in console, from working directory ./bin/console cache:clear "... & Boom. Soooo much prettier ..."

  • 2016-06-29 weaverryan

    Yeaaaa! Super happy we got it working!

    So, in general, the explanation of app_dev.php and app.php is here: http://knpuniversity.com/scree...

    But, your solution of changing the .htaccess from app.php to app_dev.php *should* have also worked (you should have then been able to go to http://aqua_note/genus/octopus and it would have loaded through the app_dev.php file). So, you're thinking correctly :). My guess is that Apache is not properly reading the web/.htaccess file - which is most commonly caused by not having the "AllowOverride All" in your Apache VirtualHost.

    I hope that clears things up!

    Cheers!

  • 2016-06-29 Ilya

    I'm sorry the problem was that I didn't install PHP Annotation plugin.
    Now It works fine!!!
    Many thanks to you!

  • 2016-06-29 Ilya

    Hi (one more time)
    Problems with app_dev.php keep following me =(

    On next lesson when I go to http://aqua_note/app_dev.php/genus/octupus/notes it gives
    "No route found for "GET /genus/octupus/notes"
    404 Not Found - NotFoundHttpException
    1 linked Exception: ResourceNotFoundException »"
    Logs (ERROR - Uncaught PHP Exception Symfony\Component\HttpKernel\Exception\NotFoundHttpException: "No route found for "GET /genus/octupus/notes"" at C:\Apache24\htdocs\aqua_note\var\cache\dev\classes.php line 2357 )

    When I go http://aqua_note/app.php/genus/octupus/notes It gives
    "Oops! An Error Occurred
    The server returned a "404 Not Found".
    Something is broken. Please let us know what you were doing when this error occurred. We will fix it as soon as possible. Sorry for any inconvenience caused. "

    When I go http://aqua_note/genus/octupus/notes It gives
    "Not Found

    The requested URL /genus/octupus/notes was not found on this server."

    Sorry for my obsession

  • 2016-06-28 Ilya

    Hey, Ryan
    I tried http://aqua_note/app_dev.php/genus/octopus and IT WORKS!!! So сan you briefly explain what was the problem? I tried change in htaaccess from app.dev to app_dev.php and it did't help
    I am very grateful for your help. I was suffering about 4 days with this issue.
    Thanks to all of you!

  • 2016-06-28 weaverryan

    Ah, this is a good sign! This error - No route found for "GET /" - is coming from Symfony, which means that it's hitting our app! And the error makes sense - at this point in the project, we haven't created a "homepage" yet.

    So, try going to http://yourhostname.local/app_dev.php/genus/octopus

    The key is having the app_dev.php in the URL. Without this, Apache will either (A) not know what to do or (B) will try to execute app.php, which boots symfony in the "prod" environment (we talk about that in the next course). The reason that you don't see me using app_dev.php in the URL during the screencasts is that the built-in web server is pre-configured to know to use app_dev.php.

    Let me know if this helps!

  • 2016-06-28 Ilya

    Hey
    1. All progects in Apache24\htdocs
    2. It gives an error No route found for "GET /" 404 Not Found - NotFoundHttpException 1 linked Exception: ResourceNotFoundException ».
    Error from logs (ERROR - Uncaught PHP Exception Symfony\Component\HttpKernel\Exception\NotFoundHttpException: "No route found for "GET /"" at Apache24\htdocs\aqua_note\var\cache\dev\classes.php line 2357 )

  • 2016-06-26 Daniel Lamas

    It works after:
    php bin/console assets:install --symlink
    bin/console cache:clear
    Thanks!

  • 2016-06-26 weaverryan

    Hey Ilya!

    Hmm! Were those other projects Symfony projects? What happens if you try going to "http://yourhostname.local/app_dev.php"? If you don't have the proper rewrite rules, then you may be getting a 404 because Apache doesn't know what file to execute if none is in the URL. And if those other projects have an index.php file, then it might be working there because Apache knows to look for that file :).

    You were definitely right to add the above "use" statement! But I don't think it's the problem. Your error - "The requested URL /genus/octopus was not found on this server" is coming from your web server - not Symfony. If the @Route isn't configured properly, you would get an error from Symfony. What I mean is, we're not *yet* even hitting the Symfony app - so we can definitely say the problem is not (yet) with our code :).

    Cheers!

  • 2016-06-24 Ilya

    I tested same vhosts on other project It WORKS!
    I'm thinkin about routing 'couse I remembered that when I was typing
    /**
    * @Route()
    */
    in 3.1 First Page Wildcards PHP Storm didn't suggest autocomplete so I copy\paste line
    "use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;"
    Maybe that's the problem?

  • 2016-06-24 Ilya

    Victor, Hi
    Yes, I think problem in Apache. Maybe permissions...
    I tried to change vhosts as written with "Require all granted" and with\without htaaccess
    Main problem when DocumentRoot is "project_name/web/app_dev.php" css,js,images is not loaded to the browser
    when DocumentRoot is "project_name/web" I'm getting "Not Found

    The requested URL /genus/octupus was not found on this server."
    I'm using Apache 2.4.20 and PHP 7.0.7 on Windows 7

  • 2016-06-24 Victor Bocharsky

    Hey, Ilya!

    If assets loads properly with built-in PHP web server, but don't load on a real web server (Nginx, Apache, etc.) - so most probably you have a problem with your web server configuration. From your stackoverflow link I realized you have a problem with Apache config, right?

    Could you check your VirtualHost configuration with the Configuring a Web Server Symfony official docs? There's an example how to configure Apache web server properly for Symfony app.

    Cheers!

  • 2016-06-24 Ilya

    I think the problem was in my vhost I finally found same issue on stack overflow
    http://stackoverflow.com/quest...
    but after that manipulation i got 404. And I don't understand where coul'd be problem now
    P.S. Thanks for your respond and sorry for my English

  • 2016-06-24 weaverryan

    Oh no!

    Let's see if we can fix this once and for all! If you can help me answer a few questions, I bet we can get to the bottom of it. I have a feeling that it's not your fault - just some small misconfiguration somewhere (and it could be our fault!)

    1) What assets are you not seeing exactly? For example, if you go to /genus/octopus - do you see the Octopus image? Do the CSS files load?

    2) Supposing the CSS files - like styles.css - are not loading, if you view the HTML source of your page and click the CSS link (which should open it in a new browser tab) - does that work? If not, can you paste the full URL from this new tab? Here's a screenshot of the "link" in the HTML source that I want you to click - this is in Chrome - other browsers may not make this a link (so use Chrome for this!) http://i.imgur.com/EPTp8ar.png

    I'm sure we can work out the problem :).

    Cheers!

  • 2016-06-23 Ilya

    I have the same issue, i cleared cache... but all files in web folder are 404 i cheked evrything million times and still got "failed to load resource: the server responded with a status of 404 (Not Found)" I'm using 3.1.1, whats wrong with symfony or problem in me?

  • 2016-06-14 weaverryan

    Hi Karolina!

    I know your solved your own problem, but I just wanted to answer your question/comment about Symfony projects just being folders :). In your case, it was failing to load the vendor/autoload.php file. The vendor/ directory is populated by Composer, so if you're ever missing anything in there, just run:


    composer install

    Or "php composer.phar install" - it depends on how you installed Composer. So, Symfony projects *are* just a directory, but somehow you lost the contents of your vendor/ directory, which is totally fine, as long as you re-install via Composer!

    Cheers!

  • 2016-06-14 Saresa Smith

    Thanks a bunch!!

  • 2016-06-12 Karolina Milewska

    (self-reply, lol)
    It's OK now, all I needed to do next is shut down everything but Ubuntu (close PHPStorm, server, the other terminal, clear browser cache) :)

  • 2016-06-12 Karolina Milewska

    Hello! I had the same issue, so another time I made a backup of the plain project (without assets) and then reverted to it (just swapped the folders) when the asset loading didn't work yet again. But now I get console errors even trying to clear the cache :(

    PHP Warning: require(/home/karolina/.local/share/Trash/files/aqua_notes/app/../vendor/autoload.php): failed to open stream: No such file or directory in /home/karolina/.local/share/Trash/files/aqua_notes/app/autoload.php on line 11
    PHP Fatal error: require(): Failed opening required '/home/karolina/.local/share/Trash/files/aqua_notes/app/../vendor/autoload.php' (include_path='.:/usr/share/php') in /home/karolina/.local/share/Trash/files/aqua_notes/app/autoload.php on line 11

    (be damned someone who wrote on S.O. that SF projects are just folders...)
    What do I do to avoid going through all the steps to this point yet again? It would probably do me good to retype all from scratch but I have no time to do it again! :(

  • 2016-05-25 weaverryan

    Hey Chris!

    Thanks man! If you're a subscriber, you'll see a "Download" link on the upper right of this page. If not, you can also find the start code up on our GitHub page: https://github.com/knpuniversi...

    Cheers!

  • 2016-05-24 Chris Christian

    hi great works super tutorial !! where can i find your css, vendor, images, js and their content ?

  • 2016-04-01 Maciek

    Hi! Thanks for the great tutorial. You should mention about clearing the cache after copying the files.

  • 2016-03-13 aitorpc

    Thanks a lot! I worked after clearing the cache!

  • 2016-03-05 Eddy de Boer

    First time, for me neither, but I think clearing the cache helps: $ bin/console cache:clear

  • 2016-02-23 cescou

    It's working now. I did reload the base.html.twig and it worked just fine. Thank for your help.

  • 2016-02-23 weaverryan

    Hey there!

    Check a few things:

    1) After moving the files, you should have a web/css/styles.css file in your project. Is it there?
    2) In base.html.twig, you should have all the `link` tags that you see here: https://knpuniversity.com/scre...

    Also, if you use the Network tab of your browser's debugging tools, do you see that the CSS files are causing 404?s Or do they not show up at all?

    Cheers!

  • 2016-02-23 cescou

    Css styles are not loading.I am working with version 3.0.2. I put the four folders from the start folder in tutorial.

  • 2016-02-01 Ivan

    Thanks

  • 2016-01-30 diegotham

    You can download the "Course Code" from the top right where it says "Download"

  • 2016-01-29 Ivan

    I have version 3.01 and don't have folder tutorial.
    Where can I take folders css, images and ect.?

  • 2016-01-10 weaverryan

    Hey Daniel!

    That's a loaded question - a lot of people have opinions on that. I personally have an `assets` directory at the root of my project (so not in web) and I use gulp to process and move everything into `web/`. The Symfony Demo actually uses app/Resources/assets, which makes a lot of sense, but it is a bit deeper in your directory structure: https://github.com/symfony/sym...

    Cheers!

  • 2016-01-09 daniel

    where do you put the sass folder if you work with sass?