Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

addStyleEntry(): CSS-Only Entrypoint

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.

There are only two files left in the public/ directory, and they're both CSS files! Celebrate by crushing your js/ directory.

We have two page-specific CSS files left. Open account/index.html.twig:

... lines 1 - 4
{% block stylesheets %}
... lines 6 - 7
<link rel="stylesheet" href="{{ asset('css/account.css') }}">
{% endblock %}
... lines 10 - 51

Yep, this has a link tag to the first... and in security/login.html.twig, here's the other:

... lines 1 - 4
{% block stylesheets %}
... lines 6 - 7
<link rel="stylesheet" href="{{ asset('css/login.css') }}">
{% endblock %}
... lines 10 - 37

Oh, and we also include login.css from register.html.twig:

... lines 1 - 28
{% block stylesheets %}
... lines 30 - 31
<link rel="stylesheet" href="{{ asset('css/login.css') }}">
{% endblock %}
... lines 34 - 78

This is kind of a tricky situation.... because what Webpack wants you to do is always start with a JavaScript entry file. And of course, if you happen to import some CSS, it'll nicely dump a CSS file. This comes from the single-page application mindset: if everything in your app is built by JavaScript, then of course you have a JavaScript file!

So... hmm. I mean, we could leave those files in public/ - we don't need them to go through Webpack. Though... I would like to use Sass. We could also create account.js and login.js files... and then just import each CSS file from inside. That would work... but then Webpack would output empty account.js and login.js files... which isn't horrible, but not ideal... and kinda weird.

In the Encore world, just like with Webpack, we really do want you to try to do it the "proper" way: create a JavaScript entry file and "import" any CSS that it needs. But, we also recognize that this is a legitimate situation. So, Encore has a little extra magic.

First, move both of the files up into our assets/css/ directory. And just because we can, make both of them scss files.

Next, in webpack.config.js add a special thing called addStyleEntry(). We'll have one called account pointing to ./assets/css/account.scss and another one called login pointing to login.scss:

... lines 1 - 2
Encore
... lines 4 - 22
.addStyleEntry('account', './assets/css/account.scss')
.addStyleEntry('login', './assets/css/login.scss')
... lines 25 - 75
;
... lines 77 - 78

Easy enough! Find your Encore build, press Control + C, and restart it:

yarn watch

Awesome! We can see that the account and login entries both only dump CSS files.

And this means that, back in index.html.twig, we can replace the link tag with {{ encore_entry_link_tags('account') }}:

... lines 1 - 4
{% block stylesheets %}
{{ parent() }}
{{ encore_entry_link_tags('account') }}
{% endblock %}
... lines 10 - 51

Copy that and do the same thing in login.html.twig for the login entry:

... lines 1 - 4
{% block stylesheets %}
{{ parent() }}
{{ encore_entry_link_tags('login') }}
{% endblock %}
... lines 10 - 37

And then in register.html.twig, one more time for login:

... lines 1 - 28
{% block stylesheets %}
{{ parent() }}
{{ encore_entry_link_tags('login') }}
{% endblock %}
... lines 34 - 78

Ok! Let's double-check that the site doesn't explode. Go to the /account profile page. Everything looks fine.

So... yea, addStyleEntry() is available for this. But... to pull it off, Encore does some hacking internally. Really, addStyleEntry() is the same as addEntry(), which means that Webpack does try to output an empty JavaScript file. Encore basically just deletes that file so that we don't have to look at it.

Next, oh, we get to talk about one of my favorite things about Webpack and Encore: how to automatically convert your CSS - and JavaScript - so that it's understood by older browsers. And how to control exactly which browsers your site needs to support.

Leave a comment!

4
Login or Register to join the conversation
CDesign Avatar
CDesign Avatar CDesign | posted 3 years ago | edited

Is it possible to set a link's 'media' attribute with the encore_entry_link_tags function?

I need to be able to create this link:

<link rel="stylesheet" type="text/css" media="print" href="{{ asset('build/print.css') }}"/>

with media set to 'print'.

Reply

Hey John,

Good question! Unfortunately, it's not possible to do it out-of-the-box with the encore_entry_link_tags() Twig function. There's an open issue about this, you can follow it to track the progress: https://github.com/symfony/...

P.S. The only way to do what you want for now is to get files as array using encore_entry_css_files() Twig function and and process it manually in a loop.

Cheers!

Reply
Dirk Avatar

I wonder, would it somehow be possible to add the entrytags for the css and/or js to twig components (bits of the page). For example, If I try to add a link inside of the block "stylesheet" and call the parent I get the error: "Calling "parent" on a template that does not extend nor "use" another template is forbidden.". This makes sense, but also I cannot extent another template, because my component is part of many different templates. If I simply add the 'encore_entry_link_tags' inside of the component, the css will be loaded, but not where I would want this (not inside <head>). I can fix this by adding the 'encore_entry_link_tags' if every single template that uses my component, but I am hoping there is a better solution.

Reply
sadikoff Avatar sadikoff | SFCASTS | Dirk | posted 3 years ago | edited

Hey Dirk
Probably for this you should have some very base layout, which you will extend from every template, than you will be able to use {{ parent() }}

Cheers!

Reply
Cat in space

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

This tutorial works great with Symfony5!

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": "^7.1.3",
        "ext-iconv": "*",
        "aws/aws-sdk-php": "^3.87", // 3.91.4
        "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-time-bundle": "^1.8", // 1.9.0
        "league/flysystem-aws-s3-v3": "^1.0", // 1.0.22
        "league/flysystem-cached-adapter": "^1.0", // 1.0.9
        "liip/imagine-bundle": "^2.1", // 2.1.0
        "nexylan/slack-bundle": "^2.0,<2.2.0", // v2.1.0
        "oneup/flysystem-bundle": "^3.0", // 3.0.3
        "php-http/guzzle6-adapter": "^1.1", // v1.1.1
        "sensio/framework-extra-bundle": "^5.1", // v5.3.1
        "stof/doctrine-extensions-bundle": "^1.3", // v1.3.0
        "symfony/asset": "^4.0", // v4.2.5
        "symfony/console": "^4.0", // v4.2.5
        "symfony/flex": "^1.9", // v1.17.6
        "symfony/form": "^4.0", // v4.2.5
        "symfony/framework-bundle": "^4.0", // v4.2.5
        "symfony/orm-pack": "^1.0", // v1.0.6
        "symfony/security-bundle": "^4.0", // v4.2.5
        "symfony/serializer-pack": "^1.0", // v1.0.2
        "symfony/twig-bundle": "^4.0", // v4.2.5
        "symfony/validator": "^4.0", // v4.2.5
        "symfony/web-server-bundle": "^4.0", // v4.2.5
        "symfony/webpack-encore-bundle": "^1.4", // v1.5.0
        "symfony/yaml": "^4.0", // v4.2.5
        "twig/extensions": "^1.5" // v1.5.4
    },
    "require-dev": {
        "doctrine/doctrine-fixtures-bundle": "^3.0", // 3.1.0
        "easycorp/easy-log-handler": "^1.0.2", // v1.0.7
        "fzaninotto/faker": "^1.7", // v1.8.0
        "symfony/debug-bundle": "^3.3|^4.0", // v4.2.5
        "symfony/dotenv": "^4.0", // v4.2.5
        "symfony/maker-bundle": "^1.0", // v1.11.5
        "symfony/monolog-bundle": "^3.0", // v3.3.1
        "symfony/phpunit-bridge": "^3.3|^4.0", // v4.2.5
        "symfony/profiler-pack": "^1.0", // v1.0.4
        "symfony/var-dumper": "^3.3|^4.0" // v4.2.5
    }
}

What JavaScript libraries does this tutorial use?

// package.json
{
    "devDependencies": {
        "@symfony/webpack-encore": "^0.27.0", // 0.27.0
        "autocomplete.js": "^0.36.0",
        "autoprefixer": "^9.5.1", // 9.5.1
        "bootstrap": "^4.3.1", // 4.3.1
        "core-js": "^3.0.0", // 3.0.1
        "dropzone": "^5.5.1", // 5.5.1
        "font-awesome": "^4.7.0", // 4.7.0
        "jquery": "^3.4.0", // 3.4.0
        "popper.js": "^1.15.0",
        "postcss-loader": "^3.0.0", // 3.0.0
        "sass": "^1.29.0", // 1.29.0
        "sass-loader": "^7.0.1", // 7.3.1
        "sortablejs": "^1.8.4", // 1.8.4
        "webpack-notifier": "^1.6.0" // 1.7.0
    }
}
userVoice