CSS & JavaScript with Asset Mapper
What about images, CSS and JavaScript? How does that work in Symfony?
Stuff in public is... Public
First off, the public/ directory is known as your document root. Anything inside public/ is accessible to your end user. Anything not in public/ is not accessible, which is great! None of our top secret source files can be downloaded by our users.
So if you want to create a CSS file or an image file or anything else, life can be as simple as putting it in public/. I can now go to /foo.txt... and we see the file.
Hello Asset Mapper
However, Symfony has a great component called Asset Mapper that lets us effectively do the same thing... but with some important, extra features. We have a few tutorials that go deeper into this topic: one about Asset Mapper specifically and another about building things with Asset Mapper called LAST Stack. Check those out to go deeper.
But let's dive into the friendly waters of Asset Mapper! Commit all your changes - I already have - then install it with:
composer require symfony/asset-mapper
This recipe makes several changes... and we'll walk through each little-by-little as they're important.
But already, if we move over and refresh, our background is blue! Inspect Element in your browser and go to the console. We also have a console log!
This log comes from
assets/app.js. Welcome to asset mapper.
Why thank you!
Asset Mapper's 2 Super Powers
Asset Mapper has two big superpowers. The first is that it helps us load CSS and JavaScript. The recipe gave us a new assets/ directory with an app.js file and a styles/app.css file. As we saw, the console log is coming from app.js.
| /* | |
| * Welcome to your app's main JavaScript file! | |
| * | |
| * This file will be included onto the page via the importmap() Twig function, | |
| * which should already be in your base.html.twig. | |
| */ | |
| import './styles/app.css'; | |
| console.log('This log comes from assets/app.js - welcome to AssetMapper! 🎉'); |
So this file is being loaded. It's also apparently including app.css, which is what gives us that blue background.
| body { | |
| background-color: skyblue; | |
| } |
We're going to talk more later about how these files are loaded and how this all works. But for right now, it's enough to know that app.js and app.css are included on the page.
The second big superpower of Asset Mapper is a bit simpler. The recipe created a config/packages/asset_mapper.yaml file. There's not a lot here:
| framework: | |
| asset_mapper: | |
| # The paths to make available to the asset mapper. | |
| paths: | |
| - assets/ |
just paths pointing to our assets/ directory. But because of this line, any file that we put in the assets/ directory becomes available publicly. It's as if the assets/ directory physically lives inside public/. This is useful because, along the way, Asset Mapper adds asset versioning: an important frontend concept that we'll see in a minute.
Listing Assets & the Logical Path
But first, head to your terminal and run another new debug command:
php bin/console debug:asset
This shows every asset that's exposed publicly through Asset Mapper. Right now it's just two: app.css and app.js.
If you download the course code from this page and unzip it, you'll find a tutorial/ directory with an images/ subdirectory. I'll cut this... then paste into assets/.
So now we have an assets/images/ directory with 5 files inside. And, by the way, you can organize the assets/ directory however you want.
But now, spin back over and run debug:asset again:
php bin/console debug:asset
The new files are there!
Rendering an Image
On the left, see this "logical path"? That's the path we'll use to reference that file in Asset Mapper.
I'll show you: let's render an img tag to the logo. Copy the starshop-logo.png logical path. Then head into templates/base.html.twig. Right above the body block - so it's not overridden by our page content - add an <img> tag with src="". Instead of trying to hardcode a path, say {{ and use a new Twig function called asset(). Pass this the logical path.
That's it! Ok, I'll add an alt attribute... to be a good citizen of the web.
| // ... line 1 | |
| <html> | |
| // ... lines 3 - 13 | |
| <body> | |
| <img src="{{ asset('images/starshop-logo.png') }}" alt="Starshop Logo"> | |
| {% block body %}{% endblock %} | |
| </body> | |
| </html> |
Let's try this. Refresh and... it explodes!
Did you forget to run
composer require symfony/asset. Unknown function "asset".
Remember: our app starts tiny. And then, as we need more features, we install more Symfony components. And often, if you try to use a feature from a component that's not installed, it'll tell you. The Twig asset() function comes from another tiny component called symfony/asset. All we need to do is follow the advice. Copy the composer require command, spin over to your terminal and run it:
composer require symfony/asset
When it finishes, move over and refresh. There's our logo!
Automatic Asset Versioning
The most interesting part? View the page source and check out the URL: /assets/images/starshop-logo- then a long string of letters and numbers, .png. This string is called the version hash and its generated based on the content of the file. That means that if we update our logo later on, this hash will change automatically.
That's super important. Browsers like to cache images, JavaScript, and CSS files, which is great: it helps performance. But when we change those files, we want our users to download the new version: not keep using the outdated, cached version.
But because the filename will change when we update the image, the browser is going to automatically use the new one! It looks like this:
- User goes to our site and downloads
logo-abc123.png. Their browser caches it. - On the next visit, their browser sees the
imgtag forlogo-abc123.png, finds the file in its cache and uses it. - Then we come along, update that file and deploy.
- The next time the user goes to our site, the
imgtag will be pointing at a different filename:logo-def456.png. And since the browser doesn't have that file in its cache, it downloads it fresh.
This is kind of a small detail, but it's also incredibly important to make sure our users are always using the latest files. And the best part? It just works. Now that I've explained it, you'll never need to think about this again.
Ok team, let's install & start using Tailwind CSS next.
15 Comments
Hi, I'm on Debian12 with Symfony7.1 I dont kow if that make any difference but
when I execute this command in terminal:
I recieve this error at the end of the recipe installer:
BUT, when I run:
everything goes well with this extra recipe (symfony/asset) as specified in:
https://symfonycasts.com/screencast/asset-mapper/install?playAt=28.188311
I hope this helps if sombody have the same problem
Hey Martin,
Thanks for this tip! Did you download the course code from this page and start from the start/ directory? I see we're using Symfony v7.0 in this course while you mentioned you're on 7.1 which means you may start a new project from scratch on the latest Symfony version. If so, yes, you need to bring that package as well as you did in your last command. That package was already pre-installed in the course project code, that's why it works out of the box. Though following our courses on a newer Symfony is OK and it's up to users, we do recommend to follow them by downloading the course code and start from the start/ dir.
Cheers!
I had not realized that I was using Symfony 7.1, I like to do the project from scratch, so I will understand it better, I am very new to this, also finding problems and solving them makes me learn :). I'm already on unit 18 and everything works fine. Thank you :) .
Hey Martin,
No problem :) Yeah, sure, it's up to you! You indeed can follow the course on a newer Symfony version. We usually add notes to the video and scripts when something is changed in a newer version that should help to users. But if you ever get stuck following our courses on a newer version - feel free to ask for help in the comments below the video and our support team will help you. You will miss some reconfiguration content this way that we prepared to for the tutorial start, we usually add some files to the empty Symfony project to make it nicer and save some times during the course, but with some little copy/paste I think you can easily bring that code into your empty project.
Cheers!
hello,
I have 2 questions about asset.
Hello,
assets/folder and then Symfony can process them and add versioning and so onCheers!
First of all - thank you very much for the great tutorial. It definitely makes me want to do more.
However, there is a problem with Twig and the asset maker. You can see this in the video at 03:54 (base.html.twig, line 15): asset() marks the file 'images/starshop-logo.png' as “Missing asset”, recognizable by the yellow background. Autocompletion does not work either, only “index.php” is suggested here. This can also be seen again and again in the following videos of the course.
I have already tried a few things, for example deleting the .idea folder and creating a new one, but the problem persists.
BUT! When I download your finished project and open it in PhpStorm, everything works perfectly (then it is base.html.twig, line 19), here I also have autocomplete available. What is different here?
Many thanks in advance!
Hey Thomas,
Hm, difficult to say, you would probably need to compare both projects locally to see the difference. It might be so that PhpStorm just didn't finish the indexing of your project yet? Follow that path in the public/ dir, i.e. make sure you have that public/images/starshop-logo.png file there. Also, you might need to compile your assets with
bin/console asset-map:compileto physically moved those files to the public/ dir. Also, make sure you have the Symfony PhpStorm plugin installed, enabled, and configured properly. But if those files are already in the public/ dir and it still does not autocomplete - try to restart your PhpStorm IDE maybe, not sure what else might be wrong.Cheers!
Hello Victor,
Thank you for your quick and detailed reply. I will probably invest a little more time and try to find out what the problem is. If I have any news, I'll let you know.
Cheers!
I also had the same error that was mentioned by user martinE.
Question about git reset:
Nevertheless I ran into another problem. Let say I only installed symfony/asset-mapper(without symfony/asset).
At this point my whole script with all the routes is completely broken and I can't even run php/bin console commands. I get cmd error:
and browser error:
I ran
git reset --hard HEADand
git clean -fdI also tried:
git reset --hard 14546d1(my previous safe save)It deleted all the 'asset mapper' files from staging area and project folder. My git head is at my previous commit before installing asset -mapper. Nevertheless my script is still broken. If I haven't googled the solution that i need to install symfony/asset i would be completely stuck at this point(with the previous 2 errors mentioned). It's a big problem in the sense that If I ran into the same problem in the future and can't google the solution my whole work will be broken.
Why didn't my git reset worked ?
Hey John-S,
If you rollback some files with Git, you still may need to clear the cache... also, you may need to rerun "composer install" and "yarn install --force" commands as well if you rollback some changes related to a new package installation. The reason is that some folders like Composer's vendor/ and NodeJS's node_modules/ are git-ignored, and so Git do not roll back files in there that were added/changed, so to keep them, in sync with the rollback-ed composer.lock and yarn.lock files you need to rerun those commands.
I hope that helps!
Cheers!
Hi there! Unfortunately the video cuts right after the Exception shows up at 6:17, I'm pretty sure we're missing 1 or 2 minutes of explanations according to the script.
Thank you again for this tutorial!
Hey @Adam-E
Are you talking about this chapter? I see it finishes where it should be and the next video continues exactly where this one ends.
Did I miss anything?
Hello @MolloKhan
I'm sorry, I don't know why yesterday my video ended right after the Exception "Did you forget to run composer require symfony/asset. Unknown function "asset"."
Everything seems to work perfectly now !
Thank you for reactivity
It could have been a Vimeo outage. That's where we store our videos :)
"Houston: no signs of life"
Start the conversation!