If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.
With a Subscription, click any sentence in the script to jump to that part of the video!
Login SubscribeOur app uses Webpack Encore to manage its frontend assets. It's not something we talked much about because, if you downloaded the course code from this page, it already included the final build/
directory. I did this so we didn't need to worry about setting up Encore just to get the site working.
But if you are using Encore, we can make a few improvements to how we're styling our emails. Specifically, we took two shortcuts. First, the assets/css/foundation-emails.css
file is something we downloaded from the Foundation website. That's not how we would normally do things with Encore. If we need to use a third-party library, we typically install it with yarn
instead of committing it directly.
The other shortcut was with this emails.css
file. I'd rather use Sass... but to do that, I need to process it through Encore.
Let's get to work! Over in the terminal, start by installing all the current Encore dependencies with:
yarn install
When that finishes, install Foundation for Emails with:
yarn add foundation-emails --dev
The end result is that we now have a giant node_modules/
directory and... somewhere way down in this giant directory... we'll find a foundation-emails
directory with a foundation-emails.css
file inside. They also have a Sass file if you want to import that and control things further... but the CSS file is good enough for us.
Before we make any real changes, make sure Encore can build by running:
yarn dev --watch
And... excellent! Everything is working.
Now that we've installed Foundation for Emails properly, let's delete the committed file: I'll right click and go to "Refactor -> Delete". Next, because I want to use Sass for our custom email styling, right click on email.css
, go to "Refactor -> Rename" and call it email.scss
.
Because this file will be processed through Encore, we can import the foundation-email.css
file from right here with @import
, a ~
- that tells Webpack to look in the node_modules/
directory - then foundation-emails/dist/foundation-emails.css
.
@import "~foundation-emails/dist/foundation-emails.css"; | |
... lines 3 - 39 |
This feels good! I'll close up node_modules/
... cause it's giant.
Now open up the email layout file: templates/email/emailBase.html.twig
. When we used inline_css()
, we pointed it at the foundation-emails.css
file and the email.css
file. But now... we only really need to point it at email.scss
... because, in theory, that will include the styles from both files.
{% apply inky_to_html|inline_css(source('@styles/foundation-emails.css'), source('@styles/email.css')) %} | |
... lines 2 - 30 | |
{% endapply %} |
The problem is that this is now a Sass file... and inline_css
only works with CSS files: we can't point it at a Sass file and expect it transform the Sass into CSS. And even if it were a CSS file, the @import
won't work unless we process this through Encore.
So here's the plan: we're going to pretend that email.scss
is just an ordinary CSS file that we want to include on some page on our site. Open up webpack.config.js
. Whenever we have some page-specific CSS or JS, we add a new entry for it. In this case, because we don't need any JavaScript, we can add a "style" entry. Say .addStyleEntry()
- call the entry, how about, email
, and point it at the file: ./assets/css/email.scss
.
... lines 1 - 2 | |
Encore | |
... lines 4 - 24 | |
.addStyleEntry('email', './assets/css/email.scss') | |
//.addEntry('page1', './assets/js/page1.js') | |
... lines 27 - 77 | |
; | |
... lines 79 - 80 |
To get Webpack to see the updated config, in the terminal, press Ctrl+C to stop Encore and restart it:
yarn dev --watch
And... it builds! Interesting: the email
entrypoint dumped two CSS files. Let's look at the public/build
directory. Yep: email.css
and also this vendors~email.css
.
This is thanks to an optimization that Wepback Encore makes when you use splitEntryChunks()
... which you can learn all about in our Encore tutorial. But the basic point is that if we want all of the CSS from the built email.scss
file, we need to include both email.css
and vendor~email.css
.
Ok, easy, right? In the template, we could load the source of vendor~email.css
and email.css
. The problem is that Webpack splits the files in a very dynamic fashion: if it finds a more efficient way to split the files tomorrow - maybe into three files - it will! Plus, when we do our production build, the files will include a dynamic hash in their filename - like email.123abc.css
.
So... we need to do a bit more work to reliably load this stuff through inline_css()
. Let's do that next with a custom Twig function.
"Houston: no signs of life"
Start the conversation!
// composer.json
{
"require": {
"php": "^7.1.3",
"ext-iconv": "*",
"aws/aws-sdk-php": "^3.87", // 3.110.11
"composer/package-versions-deprecated": "^1.11", // 1.11.99
"knplabs/knp-markdown-bundle": "^1.7", // 1.7.1
"knplabs/knp-paginator-bundle": "^2.7", // v2.8.0
"knplabs/knp-snappy-bundle": "^1.6", // v1.6.0
"knplabs/knp-time-bundle": "^1.8", // v1.9.1
"league/flysystem-aws-s3-v3": "^1.0", // 1.0.23
"league/flysystem-cached-adapter": "^1.0", // 1.0.9
"league/html-to-markdown": "^4.8", // 4.8.2
"liip/imagine-bundle": "^2.1", // 2.1.0
"nexylan/slack-bundle": "^2.1,<2.2.0", // v2.1.0
"oneup/flysystem-bundle": "^3.0", // 3.1.0
"php-http/guzzle6-adapter": "^1.1", // v1.1.1
"sensio/framework-extra-bundle": "^5.1", // v5.4.1
"stof/doctrine-extensions-bundle": "^1.3", // v1.3.0
"symfony/asset": "^4.0", // v4.3.4
"symfony/console": "^4.0", // v4.3.4
"symfony/flex": "^1.9", // v1.17.6
"symfony/form": "^4.0", // v4.3.4
"symfony/framework-bundle": "^4.0", // v4.3.4
"symfony/mailer": "4.3.*", // v4.3.4
"symfony/messenger": "4.3.*", // v4.3.4
"symfony/orm-pack": "^1.0", // v1.0.6
"symfony/security-bundle": "^4.0", // v4.3.4
"symfony/sendgrid-mailer": "4.3.*", // v4.3.4
"symfony/serializer-pack": "^1.0", // v1.0.2
"symfony/twig-bundle": "^4.0", // v4.3.4
"symfony/twig-pack": "^1.0", // v1.0.0
"symfony/validator": "^4.0", // v4.3.4
"symfony/web-server-bundle": "^4.0", // v4.3.4
"symfony/webpack-encore-bundle": "^1.4", // v1.6.2
"symfony/yaml": "^4.0", // v4.3.4
"twig/cssinliner-extra": "^2.12", // v2.12.0
"twig/extensions": "^1.5", // v1.5.4
"twig/inky-extra": "^2.12" // v2.12.0
},
"require-dev": {
"doctrine/doctrine-fixtures-bundle": "^3.0", // 3.2.2
"easycorp/easy-log-handler": "^1.0.2", // v1.0.7
"fzaninotto/faker": "^1.7", // v1.8.0
"symfony/browser-kit": "4.3.*", // v4.3.5
"symfony/debug-bundle": "^3.3|^4.0", // v4.3.4
"symfony/dotenv": "^4.0", // v4.3.4
"symfony/maker-bundle": "^1.0", // v1.13.0
"symfony/monolog-bundle": "^3.0", // v3.4.0
"symfony/phpunit-bridge": "^3.3|^4.0", // v4.3.4
"symfony/profiler-pack": "^1.0", // v1.0.4
"symfony/var-dumper": "^3.3|^4.0" // v4.3.4
}
}