Chapters
Scroll down to the script below, click on any sentence (including terminal blocks) to jump to that spot in the video!
Our CSS setup is fine. We put files into the public/
directory and then... we point to them from inside our templates. We could add JavaScript files the same way.
But if we want get truly serious about writing CSS and JavaScript, we need to take this to the next level. And even if you consider yourself a mostly backend developer, the tools we're about to talk about will allow you to write CSS and JavaScript that feels easier and is less error-prone than what you're probably used to.
The key to taking our setup to the next level is leveraging a node library called Webpack. Webpack is the industry standard tool for packaging, minifying and parsing your frontend CSS, JavaScript, and other files. But don't worry: Node is just JavaScript. And its role in our app will be pretty limited.
Setting up Webpack can be tricky. And so, in the Symfony world, we use a lightweight tool called Webpack Encore. It's still Webpack... it just makes it easier! And we have a free tutorial about it if you want to dive deeper.
Installing Encore
But let's do a crash course right now. First, at your command line, make sure you have Node installed:
node -v
You'll also need either npm
- which comes with Node automatically - or yarn
:
yarn --version
Npm and yarn are Node package managers: they're the Composer for the Node world... and you can use either. If you decide to use yarn - thats what I'll use - make sure to install version 1.
We're about to install a new package... so let's commit everything:
git add .
And... looks good:
git status
So commit everything:
git commit -m "Look mom! A real app"
To install Encore, run:
composer require encore:1.14.0
Tip
If you're using version 2 or higher of symfony/webpack-encore-bundle
, be sure to also
run:
composer require symfony/stimulus-bundle
The recipe needed to integrate the Symfony UX libraries was moved to this new bundle.
This installs WebpackEncoreBundle. Remember, a bundle is a Symfony plugin. And this package has a recipe: a very important recipe. Run:
git status
The Encore Recipe
Ooh! For the first time, the recipe modified the .gitignore
file. Let's go check that out. Open .gitignore
. The stuff on top is what we originally had... and down here is the new stuff added by WebpackEncoreBundle. It's ignoring the node_modules/
directory, which is basically the vendor/
directory for Node. We don't need to commit that because those vendor libraries are described in another new file from the recipe: package.json
. This is Node's composer.json
file: it describes the Node packages that our app needs. The most important one is Webpack Encore itself, which is a Node library. It also has a few other package that will help us get our job done.
The recipe also added an assets/
directory... and a configuration file to control Webpack: webpack.config.js
. The assets/
directory already holds a small set of files to get us started.
Installing Node Dependencies
Ok, with Composer, if we didn't have this vendor/
directory, we could run composer install
which would tell it to read the composer.json
file and re-download all the packages into vendor/
. The same thing happens with Node: we have a package.json
file. To download this stuff, run:
yarn install
Or:
npm install
Go node go! This will take a few moments as it downloads everything. You'll probably get a few warnings like this, which are safe to ignore.
Great! This did two things. First, it downloaded a bunch of files into the node_modules/
directory: the "vendor" directory for Node. It also created a yarn.lock
file... or package-lock.json
if you're using npm. This serves the same purpose of composer.lock
: it stores the exact versions of all the packages so that you get the same versions next time you install your dependencies.
For the most part, you don't need to worry about these lock files... except that you should commit them. Let's do that. Run:
git status
Then:
git add .
Beautiful:
git status
And commit:
git commit -m "Adding Webpack Encore"
Hey! Webpack Encore is now installed! But... it's not doing anything yet! Freeloader. Next, let's use it to take our JavaScript up to the next level.
14 Comments
Hey @Digital-Pig!
You are totally right! This tutorial is a few years old now, which is why it includes Encore. In our Symfony 7 tutorial, we use AssetMapper: a way to be able to write modern JavaScript with zero build system. A refreshing "back to basics", for sure.
I hope that gives you some context about why Webpack was included here a few years ago: it was (debatably) a necessary evil. And now we've gotten rid of it! 🥳
Cheers!
Hi guys,
I set up a starter project using bootstrap and 1 file scss (app.scss)Then any time I changed app.scss, the yarn run dev-server
take too much long, about 3.8 ~ 4 second for compiling.
Then, I realize that, if I remove the @import "~bootstrap/scss/bootstrap";
now is fast.
Or, if I change app.scss to app.css and @import "~bootstrap
, it's also fast, just about 100 ms.
So, shortly say:
- scss alone -> fast
- css + bootstrap -> fast
- scss + bootstrap -> problem.
Here is my app.scss:@import "~bootstrap/scss/bootstrap"; html, body{ height: 100%; } h3{ color:blue; }
Is there any one face the same issue? I don't know where this problem came from, my webpack.config.js have .enableSassLoader() and there's nothing special with it.
Hi @Dang,
Honestly it's not a problem, you just compiling complete Bootstrap library which is pretty massive inside. So lets check your examples one by one
- scss alone - there is only your scss code which is really small and fast to compile
- css + bootstrap - if your main file is css then compiler will select precompiled BS library, and it will be faster because you will not compile everything
- SCSS + boostrap - here you will compile everything so literally your scss code, and all bootstrap scss code with all mixins and everything included that's why it will be slow
Basically if you want to use scss bootstrap you need to include only what you really need so it can be compiled faster and be lighter =)
Cheers!
Hi @sadikoff,
Thank you for pointing out the reason. I did change my app.scss to import the bootstrap css instead. @import "~bootstrap/dist/css/bootstrap.min.css";
. Webpack not compile the bootstrap so it's fast as expected. Then, I tried your method to import only some parts bootstrap scss that the page need. It works and reduce the time, but still. Because to make that simple page works as before, I have also to import many modules such as functions, variables, form, button, container ... And with hot reload, the latency still not make me happy :)).
So I would like to know if there are a way in Webpack, we can ignore the compile process for bootstrap scss? Or maybe compiling it only one time with cache ... ?
Sorry, but the only way to ignore bootstrap compiling is using precompiled css file. However IIRC webpack should have internal cache to speedup process, but I can't say if it works properly with bootstrap.
So as for me the only solution is for example on active development stage if you don't need to modify bootstrap styles is to use precompiled bootstrap css file
Cheers!
Can't get past a yarn watch error.
package.json
{
"devDependencies": {
"@hotwired/stimulus": "^3.0.0",
"@popperjs/core": "^2.10.2",
"@symfony/stimulus-bridge": "^3.0.0",
"@symfony/webpack-encore": "^4.1.1",
"axios": "^0.24.0",
"bootstrap": "^5.0.0",
"core-js": "^3.0.0",
"jquery": "^3.6.0",
"regenerator-runtime": "^0.13.2",
"webpack-notifier": "^1.6.0"
},
"license": "UNLICENSED",
"private": true,
"scripts": {
"dev-server": "encore dev-server",
"dev": "encore dev",
"watch": "encore dev --watch",
"build": "encore production --progress"
}
}
Errors are:
❯ yarn install
yarn install v1.22.19
[1/4] 🔍 Resolving packages...
warning @symfony/webpack-encore > css-minimizer-webpack-plugin > cssnano > cssnano-preset-default > postcss-svgo > svgo > stable@0.1.8: Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility
[2/4] 🚚 Fetching packages...
[3/4] 🔗 Linking dependencies...
warning " > @symfony/webpack-encore@4.1.2" has unmet peer dependency "@babel/core@^7.17.0".
warning " > @symfony/webpack-encore@4.1.2" has unmet peer dependency "@babel/preset-env@^7.16.0".
warning " > @symfony/webpack-encore@4.1.2" has unmet peer dependency "webpack@^5.72".
warning " > @symfony/webpack-encore@4.1.2" has unmet peer dependency "webpack-cli@^4.9.1".
warning "@symfony/webpack-encore > babel-loader@8.3.0" has unmet peer dependency "@babel/core@^7.0.0".
warning "@symfony/webpack-encore > babel-loader@8.3.0" has unmet peer dependency "webpack@>=2".
warning "@symfony/webpack-encore > css-loader@6.7.2" has unmet peer dependency "webpack@^5.0.0".
warning "@symfony/webpack-encore > mini-css-extract-plugin@2.7.0" has unmet peer dependency "webpack@^5.0.0".
warning "@symfony/webpack-encore > terser-webpack-plugin@5.3.6" has unmet peer dependency "webpack@^5.1.0".
warning "@symfony/webpack-encore > webpack-dev-server@4.11.1" has unmet peer dependency "webpack@^4.37.0 || ^5.0.0".
warning "@symfony/webpack-encore > @nuxt/friendly-errors-webpack-plugin@2.5.2" has unmet peer dependency "webpack@^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0".
warning "@symfony/webpack-encore > css-minimizer-webpack-plugin@4.2.2" has unmet peer dependency "webpack@^5.0.0".
warning "@symfony/webpack-encore > assets-webpack-plugin@7.0.0" has unmet peer dependency "webpack@>=5.0.0".
warning "@symfony/webpack-encore > clean-webpack-plugin@4.0.0" has unmet peer dependency "webpack@>=4.0.0 <6.0.0".
warning "@symfony/webpack-encore > style-loader@3.3.1" has unmet peer dependency "webpack@^5.0.0".
warning "@symfony/webpack-encore > webpack-dev-server > webpack-dev-middleware@5.3.3" has unmet peer dependency "webpack@^4.0.0 || ^5.0.0".
[4/4] 🔨 Building fresh packages...
success Saved lockfile.
✨ Done in 22.07s.
❯ yarn watch
yarn run v1.22.19
$ encore dev --watch
node:internal/modules/cjs/loader:1029
throw err;
^
Error: Cannot find module '@babel/core'
Require stack:
- /Users/markbateman/Documents/github/nc.ai.com/node_modules/@symfony/webpack-encore/lib/config/parse-runtime.js
- /Users/markbateman/Documents/github/nc.ai.com/node_modules/@symfony/webpack-encore/bin/encore.js
at Module._resolveFilename (node:internal/modules/cjs/loader:1026:15)
at Module._load (node:internal/modules/cjs/loader:872:27)
at Module.require (node:internal/modules/cjs/loader:1092:19)
at require (node:internal/modules/cjs/helpers:103:18)
at Object.<anonymous> (/Users/markbateman/Documents/github/nc.ai.com/node_modules/@symfony/webpack-encore/lib/config/parse-runtime.js:15:15)
at Module._compile (node:internal/modules/cjs/loader:1205:14)
at Module._extensions..js (node:internal/modules/cjs/loader:1259:10)
at Module.load (node:internal/modules/cjs/loader:1068:32)
at Module._load (node:internal/modules/cjs/loader:909:12)
at Module.require (node:internal/modules/cjs/loader:1092:19) {
code: 'MODULE_NOT_FOUND',
requireStack: [
'/Users/markbateman/Documents/github/nc.ai.com/node_modules/@symfony/webpack-encore/lib/config/parse-runtime.js',
'/Users/markbateman/Documents/github/nc.ai.com/node_modules/@symfony/webpack-encore/bin/encore.js'
]
}
Node.js v19.1.0
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
If I manually add @babel then I get
❯ yarn watch
yarn run v1.22.19
$ encore dev --watch
Running webpack ...
node:internal/modules/cjs/loader:1029
throw err;
^
Error: Cannot find module 'webpack/bin/webpack'
Require stack:
- /Users/markbateman/Documents/github/nc.ai.com/node_modules/@symfony/webpack-encore/bin/encore.js
at Module._resolveFilename (node:internal/modules/cjs/loader:1026:15)
at Module._load (node:internal/modules/cjs/loader:872:27)
at Module.require (node:internal/modules/cjs/loader:1092:19)
at require (node:internal/modules/cjs/helpers:103:18)
at Object.<anonymous> (/Users/markbateman/Documents/github/nc.ai.com/node_modules/@symfony/webpack-encore/bin/encore.js:69:12)
at Module._compile (node:internal/modules/cjs/loader:1205:14)
at Module._extensions..js (node:internal/modules/cjs/loader:1259:10)
at Module.load (node:internal/modules/cjs/loader:1068:32)
at Module._load (node:internal/modules/cjs/loader:909:12)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:82:12) {
code: 'MODULE_NOT_FOUND',
requireStack: [
'/Users/markbateman/Documents/github/nc.ai.com/node_modules/@symfony/webpack-encore/bin/encore.js'
]
}
Node.js v19.1.0
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
when I use the composer require I get the following: composer require encore
In BaseIO.php line 134:
Your github oauth token for github.com contains invalid characters: "[token ]"
Hey Joet,
Hm, it sounds like you have problems with the Composer setup on your laptop. I bet you cannot install any Composer package, not only "encore", right? Could you try to install something else and confirm that you see the same error?
I think you should try to upgrade your Composer to the latest first. Then probably try to run "composer diagnose" to check the system and of everything is ok - try install that package again.
Cheers!
It didn't work for me, I'm using yarn v. 1.22.15 but I got the next message after calling both npm run watch or yarn watch:
Error: Encore.isRuntimeEnvironmentConfigured is not a recognized property or method.
Hey daniel,
That's odd. did you install @symfony/webpack-encore
, double-check that your package.json and composer.json files matches to the tutorial's. If you debug the Encore
variable inside your webpack.config.js
file, what do you get?
Cheers!
Sorry, very very new to all of this, how does one debug the Encore variable?
Hey @Antirixas
Inside your webpack.config
file, write console.log(Encore.isProduction()
to see if it's running in production mode, or, you can print the whole config like this console.log(Encore.getWebpackConfig()
. You need to run webpack after each change
Cheers!
It didn't worked for me: I got the next message when executing yarn watch:
`Error: Encore.isRuntimeEnvironmentConfigured is not a recognized property or method`.
"Houston: no signs of life"
Start the conversation!
What PHP libraries does this tutorial use?
// composer.json
{
"require": {
"php": ">=8.1",
"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.4.5
"symfony/framework-bundle": "6.0.*", // v6.0.4
"symfony/monolog-bundle": "^3.0", // v3.7.1
"symfony/runtime": "6.4.3", // v6.4.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
}
}
What? Webpack, seriously?!
Webpack has nothing to do with writing professional CSS and JavaScript, and stating so just confuses a user about what webpack is. So, before webpack we didn't write professional CSS & JavaScript? When your audience is this large you need an editor, someone who will tell you to stop talking lala!
I don't use webpack because unless you understand webpack strategies, you'll end up loading JS and CSS files for pages that don't even use them. Or worse still, you'll end up loading ALL you CSS and JS on every page load.
Do yourself a favor, write 3 functions: injectCSS, injectJS, and injectFiles. Use the first 2 to store references to files you need and call them from functions or controller constructors. The last method gets called before your page is rendered and puts the files where they need to be, wrapped in the correct loader tags...you will only ever load the files you need when you need them.
Webpack is used by people who drives cars both don't know how to change the oil...get under the hood and learn something.