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

Sass & Sourcemaps

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.

Our layout.js file requires main.css:

... lines 1 - 6
require('../css/main.css');
... lines 8 - 12

That's cool... I guess... if you like using boring old CSS. But I want to be more Hipster, so let's use Sass instead. Well, I could use Stylus to be super hipster... and Encore does support that, but let's use something a bit more familiar.

To start, rename the file to main.scss. Now, we can use a fancier syntax for these pseudo-selectors:

... lines 1 - 16
.btn-login {
... lines 18 - 26
&:hover,&:focus {
color: #fff;
background-color: #53A3CD;
border-color: #53A3CD;
}
}
... lines 33 - 77

OooooOoOooOooo.

Obviously, the build is failing because, in layout.js, that file path is wrong! Change it to main.scss:

... lines 1 - 6
require('../css/main.scss');
... lines 8 - 12

So... does it already work?

Activating Optional Features

No! On the watch tab of our terminal, it failed when loading main.scss. Out-of-the-box, Encore cannot process Sass files. But, it tells you how to fix this! We just need to enable it inside our config & install some extra packages. Remember: Encore is full of features. But to stay light, it doesn't enable everything automatically. Instead, you are in control: enable what you need, and Encore will tell you what to do. It's kinda cool!

Go back to webpack.config.js and add .enableSassLoader():

... lines 1 - 3
Encore
... lines 5 - 23
.enableSassLoader()
;
... lines 26 - 29

Then, back on your terminal, copy the yarn add line, stop Encore with Ctrl+C, and paste!

yarn add sass-loader node-sass --dev

Let it do its thing, then... restart Encore!

yarn run encore dev --watch

No errors! To prove it works, move over to your browser and... refresh! It still looks great! Well, most importantly, on the login page, when we hover of the button, it does have that styling.

Encore Versus Webpack Concepts

There's one thing I want you to notice: the name of this method: enableSassLoader():

... lines 1 - 3
Encore
... lines 5 - 23
.enableSassLoader()
;
... lines 26 - 29

"Loader" is a Webpack concept. Encore tries to make Webpack as easy as possible, but it reuses Webpack's language and terms whenever possible. And that's important! If you ever need to do something custom with Webpack, it's usually pretty easy to figure out how that fits into Encore.

Also, we're requiring bootstrap.css right now:

... lines 1 - 4
require('bootstrap/dist/css/bootstrap.css');
... lines 6 - 12

But, with Sass support, you could instead import Bootstrap's Sass files directly. The advantage is that you can override Bootstrap's Sass variables and take control of colors, sizes and other stuff. To do that with Bootstrap 3, you'll need the bootstrap-sass package. For Bootstrap 4, the Sass files are included in the main package.

Sourcemaps!

Let's fix one more problem quickly: sourcemaps! If you click on a row, we have some console.log() debugging code. But, where does that code come from? Well, if you click on the rep_log.js link, apparently it's coming from line 197. But, that's a lie! Well, sort of. This is the built rep_log.js file, not the source file.

And this highlights a classic problem: when you build many files into one file, debugging gets harder because error messages and other info don't point to the real line number or the original filename.

Let's fix that! Back in webpack.config.js, add .enableSourceMaps() with an argument: !Encore.isProduction():

... lines 1 - 3
Encore
... lines 5 - 24
.enableSourceMaps(!Encore.isProduction())
;
... lines 27 - 30

This enables extra debugging info - called sourcemaps - whenever we are creating a development build.

Because we just updated the Webpack config, restart Encore:

yarn run encore dev --watch

Thanks to this, all of our JavaScript and CSS files now have some extra content at the bottom that hints to our browser where the source content came from. This time, when I click a row, in the console, awesome! It's coming from RepLogApp.js line 104. That is the real spot.

Oh, by the way: if you don't enable sourcemaps, you may still see some sourcemap info at the bottom of your CSS files during development. That's just an internal quirk - it won't be there on production.

Leave a comment!

21
Login or Register to join the conversation
Kribo Avatar

Aha took what I learn't here and built an automated workflow using webpack-encore.
The project is called QuickStart_basic, with the intension to create different versions for different usages.
Quickstart_basic is for Html - Scss - Js projects.
Checkout the link .. And please comment your remarks.
https://github.com/ScorpioC...

1 Reply

Hey Kribo!

Ah, cool! It's skeleton for Encore - I love it! If you add a postcss.config.js file, you could also enable the postCss loader, which i really nice :).

Cheers!

Reply
Kribo Avatar

OMG nooooo what's a postcss oboy did I miss something in your tut

Reply

Haha, I don't think we talked about it, but it's a nice feature ;). Try enablePostCssLoader(). The error message will guide you through the rest. This biggest reason this is usually used is with autoprefixer, so you can get vendor prefixes, etc.

Cheers!

Reply
Kribo Avatar

aha .. So I like new features...
So here's the upgrade with Postcss & Autoprefixer
https://github.com/ScorpioC...

The only thing bothering me is the sequences within webpack.config.js
the order, which comes first is something I could use your advice on. Is there a general rule of thumb ??

1 Reply

Hey Kribo!

Do you mean the order of the addEntry() calls? Or the order of all of the functions inside of webpack.config.js? In either case, the order doesn't matter. For all of the functions, I typically put the outputPath & publicPath on top, then the entries, then the rest of the stuff, which typically configured extra features.

Btw, I usually try not to use addStyleEntry(), and instead require whatever CSS I need from inside app.js (or from inside other files required by app.js). That's a more "correct" way of doing things but... the style entry definitely works fine.

Cheers!

Reply
Kribo Avatar

Ryan I've got a question?
I've installed bootstrap 4.1.3 and now I need popper.js.
But how do integrate popper into webpack?
Do I do the following in webpack.config.js
`
.createSharedEntry('js/common', ['jquery', 'popper.js'])
`

Reply
Kribo Avatar

With the order I mean Do I first do PostCss and the styleEntry or the other way round. ?
Adding your 'app.css' file into your 'app.js' file is the webpack way but just feels sloppy so I prefer to add it to webpack-config.js file.

Reply

Hey Kribo!

> Do I first do PostCss and the styleEntry or the other way round.

It makes no difference :). Encore generates the same configuration either way.

> I've installed bootstrap 4.1.3 and now I need popper.js.
> But how do integrate popper into webpack?

Hmm. I'm not actually sure - as I haven't tried it yet. It depends on how Bootstrap's JavaScript is configured. Honestly, I would install jquery & popper.js (as you certainly have), and then just import only bootstrap. If that gives you an error, you may need to use autoProviderjQuery(), but we would have to see :).

Cheers!

1 Reply
Default user avatar

Greate course! Could you help me with the following question? I want to dynamicly load some styles depending on the required feature (let's say dropdown menu requires both dropdown.js and additional dropdown styles). Is there a way in the Webpack to ask for predifined scss mixins directly from a js module? Or should I add to the every js module "import" to its corrsponding scss file, which will have only 1 line, like "@include dropdown-styles"?

Reply

Hey Teo!

Well, thank you! :)

About your question... hmmm... In short, Webpack isn't aware of able to work directly with any scss mixins (and, full disclosure, I am NOT an expert on scss mixings specifically, os apologies if I say something dumb :p). Well, to be more specific, Webpack simply knows how to load ".scss" files. So, yes, I think you will need to "import" the corresponding scss file, because only a .scss itself can activate the mixin.

I don't know if that satisfies your answer or not :). There is this load - https://github.com/shakacod... - I'm not sure if that hits your issue, or if it's something different. It looks just like a shortcut to help not needing the "import" in multiple places.

Cheers!

Reply
Default user avatar

Thanks again! You did answer my question (only a .scss itself can activate the mixin).

I wanted to know if there is an easy way to control js and scss dependencies from one place (one file). Right now to activate the dropdown feature of Foundation framework, we need to attach the export from "dropdown-menu.js" module to our global Foundation class AND add to the same page's scss:`
@include foundation-dropdown-menu;`
That maybe not much to do/keep in your head, but it can become a problem if you're not so familar with the library or there a lot of them in your project. So it's not quite easy to turn different features on/off.

And thank you for the sass-resources-loader. It's not quite what I asked, but still very useful.

Reply
MolloKhan Avatar MolloKhan | SFCASTS | Teo | posted 5 years ago | edited

Hey Teo

I'm not sure if this is the best way to do it, but it may work well for you. You can create a "main.js" file that will include all the common imports of your site, so then you can include it on your "base" template

Reply
Default user avatar

Hi, Diego!
You're right. I can include all assets into every page (make everything shared). Taking into account the modern internet speeds and CPU powers, that, most likely, will not have any negative impact on the end-user expirience (at least in non highload enterprise solutions with millions visitors). It's just... for me that just defeats the whole idea of assets management.

On the one hand, I'm perfectionist. I want to have the perfect solution (the common flaw of all programmers). On the another hand, I'm a lazy man. I want to find the easiest solution. So I want to have the bare minimum of the required assets per each page, but make that as flexible and easy to manage as possible.

Reply

Haha, I got you, we all seek for the best but easiest solution. What you could do is to have a few "base" templates, one for your users common sections, another one for your admin area, and so on

Reply
Bertin Avatar
Bertin Avatar Bertin | posted 5 years ago | edited

I'm trying to install the sass-loader.
Added the .enableSassLoader() to webpack.config.js

After running this command:
yarn add sass-loader node-sass --dev
Both packages are installed


{
  "devDependencies": {
    "@symfony/webpack-encore": "^0.19.0",
    "bootstrap": "^4.0.0",
    "copy-webpack-plugin": "^4.5.1",
    "font-awesome": "^4.7.0",
    "jquery": "^3.3.1",
    "node-sass": "^4.8.3",
    "sass-loader": "^6.0.7",
    "webpack-notifier": "^1.6.0"
  },
  "dependencies": {}
}

When i run the command: yarn run encore dev --watch i get the following error


Webpack is watching the files…

 ERROR  Failed to compile with 2 errors                                                                                                                             21:47:56

 error  in ./assets/css/layout.scss

Module build failed: Error: Missing binding /Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/node-sass/vendor/darwin-x64-57/binding.node
Node Sass could not find a binding for your current environment: OS X 64-bit with Node.js 8.x

Found bindings for the following environments:
  - Linux 64-bit with Node.js 8.x

This usually happens because your environment has changed since running `npm install`.
Run `npm rebuild node-sass --force` to build the binding for your current environment.
    at module.exports (/Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/node-sass/lib/binding.js:15:13)
    at Object.<anonymous> (/Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/node-sass/lib/index.js:14:35)
    at Module._compile (module.js:652:30)
    at Object.Module._extensions..js (module.js:663:10)
    at Module.load (module.js:565:32)
    at tryModuleLoad (module.js:505:12)
    at Function.Module._load (module.js:497:3)
    at Module.require (module.js:596:17)
    at require (internal/module.js:11:18)
    at Object.<anonymous> (/Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/sass-loader/lib/loader.js:3:14)
    at Module._compile (module.js:652:30)
    at Object.Module._extensions..js (module.js:663:10)
    at Module.load (module.js:565:32)
    at tryModuleLoad (module.js:505:12)
    at Function.Module._load (module.js:497:3)
    at Module.require (module.js:596:17)
    at require (internal/module.js:11:18)
    at loadLoader (/Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/loader-runner/lib/loadLoader.js:13:17)
    at iteratePitchingLoaders (/Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/loader-runner/lib/LoaderRunner.js:169:2)
    at iteratePitchingLoaders (/Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/loader-runner/lib/LoaderRunner.js:165:10)
    at /Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/loader-runner/lib/LoaderRunner.js:173:18
    at loadLoader (/Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/loader-runner/lib/loadLoader.js:36:3)
    at iteratePitchingLoaders (/Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/loader-runner/lib/LoaderRunner.js:169:2)
    at iteratePitchingLoaders (/Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/loader-runner/lib/LoaderRunner.js:165:10)
    at /Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/loader-runner/lib/LoaderRunner.js:173:18
    at loadLoader (/Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/loader-runner/lib/loadLoader.js:36:3)
    at iteratePitchingLoaders (/Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/loader-runner/lib/LoaderRunner.js:169:2)
    at runLoaders (/Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/loader-runner/lib/LoaderRunner.js:362:2)
    at NormalModule.doBuild (/Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/webpack/lib/NormalModule.js:182:3)
    at NormalModule.build (/Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/webpack/lib/NormalModule.js:275:15)

 @ ./assets/css/layout.scss 4:14-201
 @ ./assets/js/layout.js

 error  in ./assets/css/layout.scss

Module build failed: ModuleBuildError: Module build failed: Error: Missing binding /Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/node-sass/vendor/darwin-x64-57/binding.node
Node Sass could not find a binding for your current environment: OS X 64-bit with Node.js 8.x

Found bindings for the following environments:
  - Linux 64-bit with Node.js 8.x

This usually happens because your environment has changed since running `npm install`.
Run `npm rebuild node-sass --force` to build the binding for your current environment.
    at module.exports (/Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/node-sass/lib/binding.js:15:13)
    at Object.<anonymous> (/Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/node-sass/lib/index.js:14:35)
    at Module._compile (module.js:652:30)
    at Object.Module._extensions..js (module.js:663:10)
    at Module.load (module.js:565:32)
    at tryModuleLoad (module.js:505:12)
    at Function.Module._load (module.js:497:3)
    at Module.require (module.js:596:17)
    at require (internal/module.js:11:18)
    at Object.<anonymous> (/Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/sass-loader/lib/loader.js:3:14)
    at Module._compile (module.js:652:30)
    at Object.Module._extensions..js (module.js:663:10)
    at Module.load (module.js:565:32)
    at tryModuleLoad (module.js:505:12)
    at Function.Module._load (module.js:497:3)
    at Module.require (module.js:596:17)
    at require (internal/module.js:11:18)
    at loadLoader (/Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/loader-runner/lib/loadLoader.js:13:17)
    at iteratePitchingLoaders (/Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/loader-runner/lib/LoaderRunner.js:169:2)
    at iteratePitchingLoaders (/Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/loader-runner/lib/LoaderRunner.js:165:10)
    at /Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/loader-runner/lib/LoaderRunner.js:173:18
    at loadLoader (/Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/loader-runner/lib/loadLoader.js:36:3)
    at iteratePitchingLoaders (/Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/loader-runner/lib/LoaderRunner.js:169:2)
    at iteratePitchingLoaders (/Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/loader-runner/lib/LoaderRunner.js:165:10)
    at /Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/loader-runner/lib/LoaderRunner.js:173:18
    at loadLoader (/Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/loader-runner/lib/loadLoader.js:36:3)
    at iteratePitchingLoaders (/Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/loader-runner/lib/LoaderRunner.js:169:2)
    at runLoaders (/Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/loader-runner/lib/LoaderRunner.js:362:2)
    at NormalModule.doBuild (/Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/webpack/lib/NormalModule.js:182:3)
    at NormalModule.build (/Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/webpack/lib/NormalModule.js:275:15)
    at runLoaders (/Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/webpack/lib/NormalModule.js:195:19)
    at /Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/loader-runner/lib/LoaderRunner.js:364:11
    at /Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/loader-runner/lib/LoaderRunner.js:170:18
    at loadLoader (/Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/loader-runner/lib/loadLoader.js:27:11)
    at iteratePitchingLoaders (/Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/loader-runner/lib/LoaderRunner.js:169:2)
    at iteratePitchingLoaders (/Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/loader-runner/lib/LoaderRunner.js:165:10)
    at /Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/loader-runner/lib/LoaderRunner.js:173:18
    at loadLoader (/Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/loader-runner/lib/loadLoader.js:36:3)
    at iteratePitchingLoaders (/Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/loader-runner/lib/LoaderRunner.js:169:2)
    at iteratePitchingLoaders (/Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/loader-runner/lib/LoaderRunner.js:165:10)
    at /Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/loader-runner/lib/LoaderRunner.js:173:18
    at loadLoader (/Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/loader-runner/lib/loadLoader.js:36:3)
    at iteratePitchingLoaders (/Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/loader-runner/lib/LoaderRunner.js:169:2)
    at runLoaders (/Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/loader-runner/lib/LoaderRunner.js:362:2)
    at NormalModule.doBuild (/Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/webpack/lib/NormalModule.js:182:3)
    at NormalModule.build (/Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/webpack/lib/NormalModule.js:275:15)
    at Compilation.buildModule (/Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/webpack/lib/Compilation.js:151:10)
    at moduleFactory.create (/Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/webpack/lib/Compilation.js:454:10)
    at factory (/Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/webpack/lib/NormalModuleFactory.js:243:5)
    at applyPluginsAsyncWaterfall (/Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/webpack/lib/NormalModuleFactory.js:94:13)
    at /Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/tapable/lib/Tapable.js:268:11
    at NormalModuleFactory.params.normalModuleFactory.plugin (/Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/webpack/lib/CompatibilityPlugin.js:52:5)
    at NormalModuleFactory.applyPluginsAsyncWaterfall (/Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/tapable/lib/Tapable.js:272:13)
    at resolver (/Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/webpack/lib/NormalModuleFactory.js:69:10)
    at process.nextTick (/Users/bertinvandenham/Documents/Development/newwayhoogeveen/node_modules/webpack/lib/NormalModuleFactory.js:196:7)
    at _combinedTickCallback (internal/process/next_tick.js:131:7)
    at process._tickCallback (internal/process/next_tick.js:180:9)

How could i solve this?

Fixed by running the following command: npm rebuild node-sass

Reply

Hey Bertin

Ohh, interesting. Did you change your OS

Cheers!

Reply
Bertin Avatar

@Diego Aguiar

I did not changed my os after running this command:
rebuild node-sass it works again.

1 Reply

Hey Bertin!

Hmm. I feel like I've gotten this error before too, but I can't remember exactly why it happened (though, I think it was because I was upgrading Node or something somewhat significant in the background). I can't explain what happened in this case :/. You'll notice that when you add node-sass (or even if you already have node-sass in package.json, but delete node_nodules and run yarn install again), you will see node-sass compiling a C binary. Actually, I'm not too familiar with this process - I think some operating systems may have binaries available that are quickly downloaded, while other OS's need to recompile. The point is this: whatever node-sass needs to do, should be done right after the node-sass library is installed. In your case, that didn't happen, but I'm not sure why.

So, I'm not sure that helps... but maybe the extra background info is useful :).

Cheers!

Reply
Kribo Avatar

This error sounds familiar. I've come across it also.
And I think it had something to do with Yarn not rebuilding node-sass.
I stopped using yarn, npm only and the issue was updated and everything turned out fine. Try installing via npm.

26 Reply

Hey Kribo,

Thanks for this suggestion! Hm, that's interesting, I'd say the reason is different than just stop using Yarn and use NPM only, because Yarn actually do use NPM. I think your dependencies were locked with outdated versions, so when you ran "npm install" - it installed latest versions and that's why you didn't see the error. I bet you would not see the error with "yarn upgrade" too.

Cheers!

Reply
Cat in space

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

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": "^7.2.0",
        "ext-iconv": "*",
        "composer/package-versions-deprecated": "^1.11", // 1.11.99
        "doctrine/doctrine-bundle": "^1.6", // 1.8.1
        "doctrine/doctrine-cache-bundle": "^1.2", // 1.3.2
        "doctrine/doctrine-fixtures-bundle": "~3.0", // 3.0.2
        "doctrine/doctrine-migrations-bundle": "^1.2", // v1.3.1
        "doctrine/orm": "^2.5", // v2.7.2
        "friendsofsymfony/jsrouting-bundle": "^2.2", // 2.2.0
        "friendsofsymfony/user-bundle": "dev-master", // dev-master
        "sensio/framework-extra-bundle": "^5.1", // v5.1.5
        "symfony/asset": "^4.0", // v4.0.4
        "symfony/console": "^4.0", // v4.0.4
        "symfony/flex": "^1.0", // v1.17.6
        "symfony/form": "^4.0", // v4.0.4
        "symfony/framework-bundle": "^4.0", // v4.0.4
        "symfony/lts": "^4@dev", // dev-master
        "symfony/monolog-bundle": "^3.1", // v3.1.2
        "symfony/polyfill-apcu": "^1.0", // v1.7.0
        "symfony/serializer-pack": "^1.0", // v1.0.1
        "symfony/swiftmailer-bundle": "^3.1", // v3.1.6
        "symfony/twig-bundle": "^4.0", // v4.0.4
        "symfony/validator": "^4.0", // v4.0.4
        "symfony/yaml": "^4.0", // v4.0.4
        "twig/twig": "2.10.*" // v2.10.0
    },
    "require-dev": {
        "symfony/debug-pack": "^1.0", // v1.0.4
        "symfony/dotenv": "^4.0", // v4.0.4
        "symfony/phpunit-bridge": "^4.0", // v4.0.4
        "symfony/web-server-bundle": "^4.0" // v4.0.4
    }
}

What JavaScript libraries does this tutorial use?

// package.json
{
    "devDependencies": {
        "@symfony/webpack-encore": "^0.19.0", // 0.19.0
        "bootstrap": "3", // 3.3.7
        "copy-webpack-plugin": "^4.4.1", // 4.4.1
        "font-awesome": "4", // 4.7.0
        "jquery": "^3.3.1", // 3.3.1
        "node-sass": "^4.7.2", // 4.7.2
        "sass-loader": "^6.0.6", // 6.0.6
        "sweetalert2": "^7.11.0", // 7.11.0
        "webpack-notifier": "^1.5.1" // 1.5.1
    }
}
userVoice