Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine
This tutorial has a new version, check it out!

Publish Fonts to web

Keep on Learning!

If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.

Start your All-Access Pass
Buy just this tutorial for $6.00

Even though I look like lunch to them, I love dinosaurs. So on the dinosaur page, I want to show my affection with a little heart icon, using Font Awesome. In the h1, add <i class="fa fa-heart"></i>:

... lines 1 - 10
<h1>{{ dino.name }} the {{ dino.type }} <i class="fa fa-heart"></i></h1>
... lines 12 - 23

When I refresh, no love for my dinosaurs. That's because I don't have the Font Awesome CSS inside of my project. Let's see if bower can fetch it for us! At the command line, say bower install font-awesome --save - that's similar to the --save-dev option with npm.

When that's done, we can find it in vendor/bower_components/font-awesome. And our bower.json file has a new entry in it:

21 lines bower.json
... lines 2 - 15
"dependencies": {
"bootstrap": "~3.3.2",
"font-awesome": "~4.3.0"

Thanks bower!

Including the font-awesome.css

Our first job is to get that font-awesome.css into our site. We know how to do that - just add it to our main.css file. I'll copy the bootstrap line then update it to font-awesome/css/font-awesome.css. Done.

72 lines gulpfile.js
... lines 1 - 39
], 'main.css');
... lines 46 - 72

Refresh! Hearts for dino friends! So we're done right?

Well, actually, it shouldn't work. In the inspector, I've got 404 errors for the fontawesome font files. The only reason the heart shows up is that I happen to have the fontawesome font file installed on my computer. But this will be a broken heart for everyone else in the (Jurassic) world.

Font Awesome goes up one level from its CSS and looks for a fonts/ directory. Since its code lives in main.css, it goes up one level and looks for fonts/ right at the root of web/. If you bring in the Font Awesome Sass package, you can control where it's looking. But even then, we have a problem. The FontAwesome fonts/ directory is buried deep inside vendor/bower_components. Somehow, we need to copy this stuff into web/.

The copy Function

Copying files around sounds pretty handy. So lets go straight to making a new function app.copy with two arguments srcFiles and outputDir. We'll read in some source files and copy them to that new spot:

72 lines gulpfile.js
... lines 1 - 33
app.copy = function(srcFiles, outputDir) {
... lines 35 - 36
... lines 38 - 72

Great news! You already know how to copy files in Gulp! Just create the normal pipe chain, but without any filters in the middle: gulp.src(srcFiles), then pipe that directly to gulp.dest(outputDir):

72 lines gulpfile.js
... lines 1 - 33
app.copy = function(srcFiles, outputDir) {
... lines 38 - 72

So nice!

Publish those Fonts!

Next, add a new task called fonts. The job of this guy will be to "publish" any fonts that we have into web/. Right now, it's just the FontAwesome stuff. Use the app.copy() and for the path, start with config.bowerDir. I'll scroll up so we can see the path. Now, font-awesome/fonts/* to grab everything. For the target, just web/fonts:

72 lines gulpfile.js
... lines 1 - 58
gulp.task('fonts', function() {
... lines 65 - 72

We'll want this to run with our default task, so add fonts down there:

72 lines gulpfile.js
... lines 1 - 70
gulp.task('default', ['styles', 'scripts', 'fonts', 'watch']);

But I don't really care about watch - it's not like we'll be actively changing these files.

Ok, restart Gulp!


Yes, it is running the fonts task. Inside web/, we have a shiny new - and populated - fonts/ directory. And since FontAwesome is looking right here for them, we can refresh, and those nasty 404's are gone.

Don't Commit the Fonts!

We don't want to commit this new web/fonts directory - it's got generated files just like the css/ and js/ folders. To avoid the humiliation of accidentally adding them to your repo, add this path to .gitignore.

18 lines .gitignore
... lines 1 - 15
... lines 17 - 18

That's it! And if there's anything else you need to move around, just use our handy app.copy().

Leave a comment!

Login or Register to join the conversation
Default user avatar

Hi, thank you for great tutorial!!! I am having some issues... With bower I installed bootstrap and font-awesome but after running gulp and open page in browser I get Failed to parse SourceMap in console. What I am doing wrong? Tnx!


Hi Gasper!

Hmm, interesting! When you run gulp, do you see files that end in .map in your web/js and web/css directories? Your browser knows to load these - e.g. for site.js, it will look for site.js.map. So, either these map files are missing (in this case, you should also see a 404 in your browser network tools) or they are corrupt in some way.

Let me know what you find out!

Default user avatar

I just found out I have to delete old *.js.map and *.css.map files when running gulp and than gulp --production. Now it works fine. Tnx!

Nicolas-S Avatar
Nicolas-S Avatar Nicolas-S | posted 5 years ago

Hi Ryan, thanks for the great tutorial !

I was wondering if you have a best practise for css url rewriting. I have found gulp plugins but I am running into issues at the moment.


Hi Nicolas!

My approach is basically to avoid this :). What I mean is - like in this chapter - if bootstrap is looking for fonts in ../fonts, I just publish them there, relative to where the bootstrap CSS is published (of course, in bootstrap, there is another solution by changing less/sass variables to control the fonts directory). And the same goes for my code - I'm purposefully trying to *not* change the directory organization when I publish things into web so that I can avoid needing to rewrite.

But, I have played with this a little, and for me, I think if you *do* run into this problem and can't avoid it, I like something like gulp-replace to modify the URLs. It's not automatic or fancy, but it's very easy to understand in those cases where you need it. I haven't used a replace method extensively, but that's what I like ... other than avoiding the problem altogether ;)


Nicolas-S Avatar

I agree, if the path makes sense, a good option is to publish the assets accordingly. In some cases, I prefer to change it tho. Thanks for pointing to gulp-replace, it worked perfectly !

Kaizoku Avatar
Kaizoku Avatar Kaizoku | posted 5 years ago

The copy function doesn't work with folders.
I'm using flag icon and this wsn't working.

app.copy(config.bowerDir+'/flag-icon-css/flags/*', config.assetDir+'/flags');

I had to use

app.copy(config.bowerDir+'/flag-icon-css/flags/1x1/*', config.assetDir+'/flags/1x1');
app.copy(config.bowerDir+'/flag-icon-css/flags/4x3/*', config.assetDir+'/flags/4x3');

It's ok in this case as there is only 2 folders.
just to mention.


Hi there!

Hmm, does it work if you copy /flags/**? Often, the ** is used to be recursive.

Either way, thanks for the note!

Kaizoku Avatar

yep the /** does work ! Thank you.


That's awesome! Thanks for the great comment/question!

Cat in space

"Houston: no signs of life"
Start the conversation!

What PHP libraries does this tutorial use?

// composer.json
    "require": {
        "php": ">=5.3.3",
        "symfony/symfony": "2.6.*", // v2.6.4
        "doctrine/orm": "~2.2,>=2.2.3", // v2.4.6
        "doctrine/doctrine-bundle": "~1.2", // v1.2.0
        "twig/extensions": "~1.0", // v1.2.0
        "symfony/assetic-bundle": "~2.3", // v2.5.0
        "symfony/swiftmailer-bundle": "~2.3", // v2.3.7
        "symfony/monolog-bundle": "~2.4", // v2.6.1
        "sensio/distribution-bundle": "~3.0", // v3.0.9
        "sensio/framework-extra-bundle": "~3.0", // v3.0.3
        "incenteev/composer-parameter-handler": "~2.0", // v2.1.0
        "hautelook/alice-bundle": "~0.2" // 0.2
    "require-dev": {
        "sensio/generator-bundle": "~2.3" // v2.4.0