Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

Installing 3rd Party Code into our JS/CSS

Video not working?

It looks like your browser may not support the H264 codec. If you're using Linux, try a different browser or try installing the gstreamer0.10-ffmpeg gstreamer0.10-plugins-good packages.

Thanks! This saves us from needing to use Flash or encode videos in multiple formats. And that let's us get back to making more videos :). But as always, please feel free to message us.

We now have a nice new JavaScript and CSS system that lives entirely inside of the assets/ directory. Let's move our public styles into this. Open public/styles/app.css, copy all of this, delete the entire directory... and then paste into the new app.css. Thanks to the encore_entry_link_tags() in base.html.twig, the new CSS is being included... and we don't need the old link tag anymore.

Go check it out. Refresh and... it still looks great!

Installing 3rd Party JavaScript/CSS Libraries

Go back to base.html.twig. What about these external link tags for bootstrap and FontAwesome? Well, you can totally keeps these CDN links. But we can also process this stuff through Encore. How? By installing Bootstrap and FontAwesome as vendor libraries and importing them.

Remove all of these link tags... and then refresh. Yikes! It's back to looking like I designed this site. Let's... first re-add bootstrap. Find your terminal. Since the watch command is running, open a new terminal tab and then run:

yarn add bootstrap --dev


If you're using NPM run:

npm add bootstrap --include=dev

This does three things. First, it adds bootstrap to our package.json file. Second it downloads bootstrap into our node_modules/ directory... you would find it down here. And third, it updated the yarn.lock file with the exact version of bootstrap that it just downloaded.

If we stopped now... this wouldn't make any difference! We downloaded bootstrap - yay - but we're not using it.

To use it, we need to import it. Go into app.css. Just like in JavaScript files, we can import from inside CSS files by saying @import and then the file. We could reference a file in the same directory with ./other-file.css. Or, if you want to import something from the node_modules/ directory in CSS, there's a trick: a ~ and then the package name: bootstrap.

@import '~bootstrap';
... lines 2 - 34

That's it! As soon as we did that, Encore's watch function rebuilt our app.css file... which now includes Bootstrap! Watch: refresh the page and... we're back! So cool!

The two other things we're missing are FontAwesome and a specific Font. To add those, head back to the terminal and run:

yarn add @fontsource/roboto-condensed --dev

Full disclosure: I did some searching before recording so that I knew the names of all the packages we need. You can search for packages at https://npmjs.com.

Let's also add the last one we need:

yarn add @fortawesome/fontawesome-free --dev

Again, this downloaded the two libraries into our project... but doesn't automatically use them yet. Because those libraries both hold CSS files, go back to our app.css file and import them: @import '~' then @fortawesome/fontawesome-free. And @import '~@fontsource/roboto-condensed'.

@import '~bootstrap';
@import '~@fortawesome/fontawesome-free';
@import '~@fontsource/roboto-condensed';
... lines 5 - 34

The first package should fix this icon... and the second should cause the font to change on the whole page. Watch the font when we refresh... it did change! But, uh... the icons are still kind of broken.

Importing Specific Files from node_modules/

To be totally honest, I'm not sure why that doesn't work out-of-the box. But the fix is kind of interesting. Hold command on a Mac - or ctrl otherwise - and click this fontawesome-free string.

When you use this syntax, it goes into your node_modules/ directory, into @fortawesome/fontawesome-free... and then if you don't put any filename after this, there's a mechanism where this library tells Webpack which CSS file it should import. By default, it imports this fontawesome.css file. For some reason... that doesn't work. What we want is this all.css.

And we can import that by adding the path: /css/all.css. We don't need the minified file because Encore handles minifying for us.

@import '~bootstrap';
@import '~@fortawesome/fontawesome-free/css/all.css';
@import '~@fontsource/roboto-condensed';
... lines 5 - 34

And now... we're back!

The main reason I love Webpack Encore and this system is that it allows us to use proper imports. We can even organize our JavaScript into small files - putting classes or functions into each - and then import them when we need them. There's no more need for global variables.

Webpack also allows us to use more serious stuff like React or Vue: you can even see, in webpack.config.js, the methods to activate those.

But usually, I like using a delightful JavaScript library called Stimulus. And I want to tell you about it next.

Leave a comment!

Login or Register to join the conversation
Kaizoku Avatar
Kaizoku Avatar Kaizoku | posted 1 year ago

Hi Ryan,
I wrote a comment on Stackoverflow about why fontawesome is not working out of the box
it's here : https://stackoverflow.com/a...
And fun fact this is actually you that explained why in one of your video, so all the credit is on you ;)

1 Reply

Hey Kaizoku!

Haha, OMG, did I really? I have a famously bad memory 😆. I wish FontAwesome would fix that to make things easier! And thanks for posting that answer on Stackoverflow for others - that's very cool of you.



I knoooow I'm early - But my `~bootstrap` isn't working and throws an error on compiling (not found).
If I use `import "../node_modules/bootstrap"` anything works well.

Do you have any hint to fix this?

1 Reply


Ha! That's ok that you're early :). Hmm, that is super odd. You have this inside of assets/styles/app.css?

@import '~bootstrap';

Let me know :).


1 Reply

yeah... my fault, i added it to the app.js 🤦🏻‍♂️

The good thing in making mistakes - you learn something!
The more mistakes you make, the smarter you get :D

Thanks for your answer and these great tutorials!



Ah, awesome! Np. Bootstrap is a weird one... since it provides both JavaScript AND CSS. If you put that import in app.js, it knows to import the Bootstrap JavaScript. But then that SAME import in a CSS file tells Webpack to import the CSS. Pretty cool and pretty smart. But also, a bit magical ;).

Cheers and thanks for the nice words!

CindySymf Avatar
CindySymf Avatar CindySymf | posted 1 month ago | edited

Hi I'm running yarn add bootstrap --dev and I get the error below. I'm running this just after running composer require encore:1.14.0 (and yarn watch, both ran fine). I'm backtracking steps as in the next lecture when I add <div data-controller="hello"></div> to homepage.html.twig it does not show up on my site.

Error when running yarn add bootstrap --dev

WAIT  Compiling...                                                                                          12:20:11 pm

 ERROR  Failed to compile with 2 errors                                                                      12:20:11 pm

 error  in ./node_modules/css-loader/dist/runtime/cssWithMappingToString.js                                  12:20:11 pm

Module build failed: Error: ENOENT: no such file or directory, open 'C:\Users\sbhe0002\mixed_vinyl\node_modules\css-loader\dist\runtime\cssWithMappingToString.js'

 error  in ./assets/styles/app.css                                                                           12:20:11 pm

Module build failed (from ./node_modules/mini-css-extract-plugin/dist/loader.js):
ModuleBuildError: Module build failed: Error: ENOENT: no such file or directory, open 'C:\Users\sbhe0002\mixed_vinyl\node_modules\css-loader\dist\runtime\cssWithMappingToString.js'
    at processResult (C:\Users\sbhe0002\mixed_vinyl\node_modules\webpack\lib\NormalModule.js:764:19)
    at C:\Users\sbhe0002\mixed_vinyl\node_modules\webpack\lib\NormalModule.js:866:5
    at C:\Users\sbhe0002\mixed_vinyl\node_modules\loader-runner\lib\LoaderRunner.js:400:11
    at C:\Users\sbhe0002\mixed_vinyl\node_modules\loader-runner\lib\LoaderRunner.js:221:19
    at C:\Users\sbhe0002\mixed_vinyl\node_modules\webpack\lib\NormalModule.js:836:24
    at Array.eval (eval at create (C:\Users\sbhe0002\mixed_vinyl\node_modules\tapable\lib\HookCodeFactory.js:33:10), <anonymous>:9:1)
    at runCallbacks (C:\Users\sbhe0002\mixed_vinyl\node_modules\enhanced-resolve\lib\CachedInputFileSystem.js:43:15)
    at ReadFileContext.<anonymous> (C:\Users\sbhe0002\mixed_vinyl\node_modules\enhanced-resolve\lib\CachedInputFileSystem.js:249:5)
    at ReadFileContext.callback (C:\Users\sbhe0002\mixed_vinyl\node_modules\graceful-fs\graceful-fs.js:123:16)
    at FSReqCallback.readFileAfterOpen [as oncomplete] (node:fs:327:13)
Entrypoint app [big] 697 KiB = runtime.js 14.6 KiB vendors-node_modules_symfony_stimulus-bridge_dist_index_js-node_modules_core-js_modules_es_da-03e5c3.js 644 KiB app.js 38.8 KiB
webpack compiled with 2 errors

Hey @CindySymf!

Well that is not a fun error! Honestly, it looks like something failed to download - it's super odd. One of the node vendor packages you downloaded is referring to another vendor file... which doesn't appear to be there! That just... shouldn't happen - I can't think of how this could be something that your code is causing.

Try these 2 things:

1) Remove the node_modules/ directory by hand. Then run yarn install again. Then try it again.
2) If that doesn't work, then try yarn upgrade to upgrade the dependencies. It's possible things are just out-of-date enough that it's causing some weird issue.

And let me know how it goes :)


Sahetmyrat Avatar
Sahetmyrat Avatar Sahetmyrat | posted 9 months ago

Hello, I've imported Quilljs text styling library: @import "~quill"; But it didn't build.
(16:3) node_modules\quill\dist\quill.js Unclosed bracket

How can I solve that? Or isn't Quill compatible with Symfony? Thanks!


Hey Sahetmyrat,

I don't know that library, but it has nothing to do with Symfony, although it may not be compatible with NodeJS. Try importing the JS and CSS files from a JS file. In your app.js file (or any other) add this

import 'quill';
import 'quill/dist/{the-css-file}';


akincer Avatar
akincer Avatar akincer | posted 1 year ago

Hey folks, has there been a change in recent Symfony/Twig versions that would cause variables passed to a Twig template not to be updated on calling render() after a form submit?

That's what I'm seeing when trying to use CraueFormFlowBundle and the lack of variables sent to Twig updating is breaking things. I've validated using logging and {{ dump() }} that the value being sent on render() SHOULD be updated but isn't.

I'm guessing disabling caching might fix this but surely that isn't the best solution.

Yactouat Avatar
Yactouat Avatar Yactouat | posted 1 year ago

thanks that was a great course, wishful thinking => can we have the js part in typescript ? :)

Santosh kalwar Avatar
Santosh kalwar Avatar Santosh kalwar | posted 1 year ago

Hey @weaverryan

Awesome stuff. Can I use this material to teach my students about introducing Symfony 6?

I am looking forward to your answer.


Hi Santosh kalwar!

Absolutely! This tutorial is totally free and open to anyone. Feel free to use it for your students in any way that you want - that would be great :). If you have any questions, let us know.


Santosh kalwar Avatar
Santosh kalwar Avatar Santosh kalwar | weaverryan | posted 1 year ago

Thank you!


Hey there,

I'm not sure why but when using SCSS, if you import vendors in your scss files, vendor styles get compiled into the app.css file instead of in a vendor file. I've been having this problem since the first versions of Encore. The easy fix was to import these vendor scss file from javascript instead but I was wondering if there was a way to do that from the scss files and still get that nice vendor css file?

<br /># app.scss<br />@import '~bootstrap';<br />@import '~@fortawesome/fontawesome-free/scss/fontawesome';<br />@import '~@fontsource/roboto-condensed';<br />


Hey julien_bonnier!

Oh really, that's very interesting! This is not something I've noticed before. So, to make sure I understand correctly, when you import from app.scss, Webpack does NOT split the vendor CSS into some node_modules~bootstrap~fortawsome...css type of file, but instead of compiles it straight into app.css with your custom JavaScript. Correct? Hmm. If that's the case, that sounds like some weird, deep behavior: something that would be difficult to track down. My guess is that the SCSS system imports all of that vendor stuff BEFORE webpack becomes aware of it. So by the time Webpack sees all of the content, it's all "coming from app.scss", which is incorrect.

So, unfortunately, I don't have an answer. My best advice is to stick with your workaround, but that's unfortunate!


Cat in space

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

What PHP libraries does this tutorial use?

// composer.json
    "require": {
        "php": ">=8.0.2",
        "ext-ctype": "*",
        "ext-iconv": "*",
        "symfony/asset": "6.0.*", // v6.0.3
        "symfony/console": "6.0.*", // v6.0.3
        "symfony/dotenv": "6.0.*", // v6.0.3
        "symfony/flex": "^2", // v2.1.5
        "symfony/framework-bundle": "6.0.*", // v6.0.4
        "symfony/monolog-bundle": "^3.0", // v3.7.1
        "symfony/runtime": "6.0.*", // v6.0.3
        "symfony/twig-bundle": "6.0.*", // v6.0.3
        "symfony/ux-turbo": "^2.0", // v2.0.1
        "symfony/webpack-encore-bundle": "^1.13", // v1.13.2
        "symfony/yaml": "6.0.*", // v6.0.3
        "twig/extra-bundle": "^2.12|^3.0", // v3.3.8
        "twig/twig": "^2.12|^3.0" // v3.3.8
    "require-dev": {
        "symfony/debug-bundle": "6.0.*", // v6.0.3
        "symfony/stopwatch": "6.0.*", // v6.0.3
        "symfony/web-profiler-bundle": "6.0.*" // v6.0.3