Drop-dead simple SASS builds in Symfony Flex with Webpack Encore
Before we go to details on how to use Webpack Encore, it worth noting that even though we use Symfony Flex in this example, it is not dependent on the Symfony version. You can use Symfony Encore with Symfony2 and Symfony3 like eZ Platform CMS. Actually, Encore is pure JavaScript - so it's not coupled to Symfony at all.
Symfony Flex is a new flavor (see comment) tool for Symfony, that will be the standard in for Symfony 4 projects from 2017 and forward. Underneath Flex will keep using Symfony Components, so it's not a radical departure for the Symfony philosophy, even though a big change for new projects using Symfony Framework.
Earlier this year I experimented with sharing a state object with Symfony and different front end tools. Recently I ported the Symfony 3 application to Symfony Flex. Now I will continue the evolution of the app by adopting Symfony Encore to the project.
Installing and configuring Encore
Installing Symfony Encore is well documented in the official documentation, so for details I recommend looking there. The documentation is currently showcasing Symfony 3 usage, so some directories will be different in Symfony 4 / Flex.
As Encore is a JavaScript application ran from the command line, you'll need to start by installing Node.js to your environment. You'll also need the a packet manager for the NPM repository to download dependencies. The Encore documentation uses Yarn, an alternative client for the NPM repository, but the standard NPM client is fine.
Start by installing the Encore package from the repository using Yarn:
yarn add @symfony/webpack-encore --dev
This will add a some files and a directory to your application root. As packet manager clients NPM/Yarn are essentially the same thing as Composer. If you're not familiar with using NPM, here are the files and their Composer equivalents:
- package.json: This contains list of dependencies in your project. The Composer equivalent is composer.json
- yarn.lock / package-lock.json: This contains the exact versions for your application dependencies. The Composer equivalent for this is composer.lock
- node_modules/: This contains your dependencies. The Composer equivalent is vendor/
The lockfile name depends on whether you use NPM or Yarn. It's because NPM didn't originally have a lockfile. Store both package.json and your lock file in version control. So add node_modules to your .gitignore, right next to vendor if you're using Git.
Setting up SASS and running builds
Next up create directories for your static assets. In this case we'll just add a SASS file to the root to form the following structure, starting from the root of your project:
- assets
- scss
- global.scss
- scss
The SCSS is a source file is a file that will be processed to a regular CSS file for browser consumption. To enable this, we'll install the SASS processor using Yarn:
yarn add sass-loader node-sass --dev
Next up we'll configure Encore (and consequently, Webpack) to pick up your files. This is done with a webpack.config.js file, which defines a number of things. The default example in the Encore documentation is a good start, but in Flex the web root directory is now public, so we'll need to make a small change to the configuration:
.setOutputPath('public/build/')
Once we've got this in place we can build our assets with Encore during development. Running with dev and watch options is optimal for development as files contain source maps for debugging are refreshed upon changes to the source files:
./node_modules/.bin/encore dev --watch
The above will run Webpack and place the output to the public directory. They are just static files, so will need to reference them. For this, I recommend using the Symfony asset component in your main template (e.g. templates/base.html.twig):
<link href="{{ asset('build/global.css') }}" rel="stylesheet">
You can also use NPM/Yarn to add CSS frameworks like described for Bootstrap in Encore documentation. I prefer the lightweight Milligram framework for my projects. As NPM is now used to distribute than JavaScript, I can install Milligram using Yarn:
yarn add milligram
The above won't do anything magical, it will just store the Milligram's SASS source files under the node_modules/milligram -directory. When using Webpack for SASS processing, I can reference the SASS source in my assets/scss/global.scss like this:
@import '~milligram/src/milligram';
If you are using Symfony 3.3+ you can also use the Webpack asset versioning, for automatic cache busting based on an automatically generated manifest file. You'll end up with a bunch of files over time, so it's not recommended to store generated files in version control, so you'll probably want to add public/build into your .gitignore file.
Finally, when running the build process in production environments be sure to run Encore with production settings for optimal filesizes with no debug data:
./node_modules/.bin/encore production
Conclusion
When you work Webpack, you'll quickly notice it's become quite the swiss army knife. Configuring it can be intimidating for a newcomer. This is where Encore can help.
Symfony Encore provides an opinionated way of adding Front End assets to Symfony projects. As Webpack has become a de-facto standard and Encore is a wrapper for it, using it will feel familiar to developers coming from other frameworks and languages.
The use of Encore is not enforced, so you can still continue to use any other methods. I like having a go-to method instead of yak shaving optimal configurations. If you prefer Post CSS, etc. over SASS, there are many good presets in the Webpack ecosystem. Likely no need to reinvent the wheel and if you need to, please share ;)
The code for this example is available on GitHub. It already includes using TypeScript as well, but I'll come back to that in another article. Hopefully sooner rather than later.
Related links:
- A Symfony Flex hybrid app sharing state object with Twig, React and Vue
- Introducing Webpack Encore for Asset Management
- Porting a Symfony 3 application to Flex
- Symfony and Asset Management
- A simple front end workflow for Symfony and Foundation frameworks