Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

Twig Helpers, entrypoints.json & yarn Scripts

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.

Encore is outputting app.css and app.js thanks to the app entry:

... lines 1 - 2
Encore
... lines 4 - 19
.addEntry('app', './assets/js/app.js')
... lines 21 - 66
;
... lines 68 - 69

And we successfully added the <link> tag for app.css and, down here, the <script> for app.js:

<!doctype html>
<html lang="en">
<head>
... lines 5 - 8
{% block stylesheets %}
<link rel="stylesheet" href="{{ asset('build/app.css') }}">
... lines 11 - 14
{% endblock %}
</head>
<body>
... lines 19 - 90
{% block javascripts %}
<script src="{{ asset('build/app.js') }}"></script>
... lines 93 - 105
{% endblock %}
</body>
</html>

The Twig Helper Functions

But when you use Encore with Symfony, you won't render script and link tags by hand. No way! We're going to be way lazier, and use some helper functions from WebpackEncoreBundle. For the stylesheets, use {{ encore_entry_link_tags() }} and pass it app, because that's the name of the entry:

<!doctype html>
<html lang="en">
<head>
... lines 5 - 8
{% block stylesheets %}
{{ encore_entry_link_tags('app') }}
... lines 11 - 14
{% endblock %}
</head>
... lines 17 - 107
</html>

At the bottom, replace the script tag with almost the same thing: {{ encore_entry_script_tags('app') }}:

Tip

In new Symfony projects, the javascripts block is at the top of this file - inside the <head> tag. Also, Encore will render a defer attribute on each script tag. To follow this tutorial, in config/packages/webpack_encore.yaml, comment-out the defer: true key to avoid this. For more info about defer and its performance benefits, check out https://symfony.com/blog/moving-script-inside-head-and-the-defer-attribute

<!doctype html>
<html lang="en">
... lines 3 - 17
<body>
... lines 19 - 90
{% block javascripts %}
{{ encore_entry_script_tags('app') }}
... lines 93 - 105
{% endblock %}
</body>
</html>

Move over and refresh to try this. Wow! This made absolutely no difference! The <link> tag on top looks exactly the same. And... if I search for "script"... yep! That's identical to what we had before.

So... why? Or maybe better, how? Is it just taking the app and turning it into build/app.js? Not quite... it's a bit more interesting than that.

In the public/build/ directory, Encore generates a very special file called entrypoints.json. This is a map from each entry name to the CSS and JS files that are needed to make it run. If you were listening closely, I just said two strange things. First, we only have one entry right now. But yes, we will eventually have multiple entries to power page-specific CSS and JS. Second, for performance, eventually Webpack may split a single entry into multiple JavaScript and CSS files and we will need multiple script and link tags. We'll talk more about that later.

The important thing right now is: we have these handy helpers that output the exact link and script tags we need... even if we need multiple.

Using --watch

Ok, back to Encore. Because it's a build tool, each time you make a change to anything, you need to rebuild:

./node_modules/.bin/encore dev

That's lame. So, of course, Webpack also has a "watch" mode. Re-run the same command but with --watch on the end:

./node_modules/.bin/encore dev --watch

Encore boots up, builds and... just chills out and waits for more changes. Let's test this. In app.js, I think we need a few more exclamation points:

15 lines assets/js/app.js
... lines 1 - 13
console.log('Hello Webpack Encore! Edit me in assets/js/app.js!!!');

Save, then check out the terminal. Yea! It already rebuilt! In your browser, refresh. Boom! Extra exclamation points. If that doesn't work for some reason, do a force refresh.

Shortcut "scripts"

But even that is too much work. Press Ctrl+C to stop Encore. Instead, just run:

yarn watch

That's a shortcut to do the same thing. You can even see it in the output: encore dev --watch. But there's no magic here. Open up package.json. We got this file from the recipe when we installed the WebpackEncoreBundle via Composer. See this scripts section?

15 lines package.json
{
... lines 2 - 8
"scripts": {
"dev-server": "encore dev-server",
"dev": "encore dev",
"watch": "encore dev --watch",
"build": "encore production --progress"
}
}

This is a feature of Yarn and npm: you can add "shortcut" commands to make your life easier. yarn watch maps to encore dev --watch. Later, we'll use yarn build to generate our assets for production.

With all this done, let's get back to the core of why Webpack is awesome: being able to import and require other JavaScript. That's next.

Leave a comment!

24
Login or Register to join the conversation
Deuklyoung K. Avatar
Deuklyoung K. Avatar Deuklyoung K. | posted 3 years ago

Using Encore in a Virtual Machine

https://symfony.com/doc/mas...

1 Reply
Frédéric H. Avatar
Frédéric H. Avatar Frédéric H. | posted 10 months ago

getting an error when compliling

Running webpack ...

ERROR Failed to compile with 1 errors 8:31:03 PM

error in ../../##DEV/covinated/assets/app.js 8:31:03 PM

Module build failed (from ../../##DEV/covinated/node_modules/babel-loader/lib/index.js):
Error: Cannot find module 'C:\##DEV\covinated\node_modules\babel-loader\lib\index.js'
Require stack:
- C:\##DEV\covinated\node_modules\loader-runner\lib\loadLoader.js
- C:\##DEV\covinated\node_modules\loader-runner\lib\LoaderRunner.js
- C:\##DEV\covinated\node_modules\webpack\lib\NormalModule.js
- C:\##DEV\covinated\node_modules\@symfony\webpack-encore\lib\webpack-manifest-plugin\index.js
- C:\##DEV\covinated\node_modules\@symfony\webpack-encore\lib\plugins\manifest.js
- C:\##DEV\covinated\node_modules\@symfony\webpack-encore\lib\config-generator.js
- C:\##DEV\covinated\node_modules\@symfony\webpack-encore\index.js
- C:\##DEV\covinated\webpack.config.js
- C:\##DEV\covinated\node_modules\webpack-cli\lib\webpack-cli.js
- C:\##DEV\covinated\node_modules\webpack-cli\lib\bootstrap.js
- C:\##DEV\covinated\node_modules\webpack-cli\bin\cli.js
- C:\##DEV\covinated\node_modules\webpack\bin\webpack.js
- C:\##DEV\covinated\node_modules\@symfony\webpack-encore\bin\encore.js
at Function.Module._resolveFilename (node:internal/modules/cjs/loader:933:15)
at Function.Module._load (node:internal/modules/cjs/loader:778:27)
at Module.require (node:internal/modules/cjs/loader:1005:19)
at require (node:internal/modules/cjs/helpers:102:18)
at loadLoader (C:\##DEV\covinated\node_modules\loader-runner\lib\loadLoader.js:19:17)
at iteratePitchingLoaders (C:\##DEV\covinated\node_modules\loader-runner\lib\LoaderRunner.js:182:2)
at runLoaders (C:\##DEV\covinated\node_modules\loader-runner\lib\LoaderRunner.js:397:2)
at NormalModule._doBuild (C:\##DEV\covinated\node_modules\webpack\lib\NormalModule.js:812:3)
at NormalModule.build (C:\##DEV\covinated\node_modules\webpack\lib\NormalModule.js:956:15)
at C:\##DEV\covinated\node_modules\webpack\lib\Compilation.js:1367:12

Entrypoint app 13.3 KiB = runtime.js 10.7 KiB app.js 2.61 KiB
webpack compiled with 1 error

Reply

Hey Frédéric H.!

Hmm, I'm not sure why this would be happening. It's failing because it can't find a vendor file (i.e. a file in node_modules) but that file *should* be there. Specifically, it seems like it can't find node_modules\babel-loader\lib\index.js.

Try removing your node_modules directory and re-running yarn install to install them fresh... perhaps there was some problem downloading those dependencies. If that doesn't work, try a yarn upgrade in case some old dependency is causing weird issues.

Let me know if any of this helps!

Cheers!

Reply
Frédéric H. Avatar

non still the same :( i'm using php 8.0 and the file is indeed there

Reply

Hey Frédéric H.!

Hmm. I just downloaded this course code and tried running webpack: I'm not having any problems :/. Did you also try running yarn upgrade? Do you have any custom config for webpack or babel? It's definitely a strange error...

Cheers!

Reply
Frédéric H. Avatar

i even tried with a blank project, and not even adding your course.

Reply
Frédéric H. Avatar

ok let's try that :)

Reply

Hello all. I'm mostly sure this comment should go not to this topic - but you're my last chance :D How could i use a twig macro function recursive for a multilevel dropdown menu? was trying to find some info on google, stackoverflow - and shamefully it was meaningless for me. I have builded a multidimensional array with parents and children that I'm sending to a twig template - but i don't know how to use it well :/ Would appreciate any comments or resources

Reply

Hey Andrejus,

Unfortunately, we don't have anything specific about this on SymfonyCasts. But I'll try to give you some tips :) First of all, you should create a template where declare that macro, and then import your macro on another template where you're going to print that menu. I suppose you did that already, and it should work well, because it's simple and we do this in your Twig tutorial. If you're not sure how to import the macro into a template and render it - watch that tutorial first. And then, I believe the trick will be in importing the macro in the same macro file, i.e. in your your template where is your macro definition, you can call this "{% import _self as macros %}" on the first line of the file. And this will give you an ability to call any macro on the same macro definition page via "macro.%yourMacroNameHere%", here's a little example:


{# path-to-your-macro/menu-macro.twig.html #}

{% import _self as macros %}

{% macro renderMenu() %}
{# Render your menu here... #}

{% if %yourExpressionThatChecksIfWeNeedToRenderNestedLevel% %}
{# Render your submenu here, i.e. just call that renderMenu() recursively #}

{{ macros.renderMenu() }}
{% endif %}
{% endmacro %}

Well, you have to think about arguments, as you will need to path what you're going to render as an argument, but the general idea is that simple.

I hope this helps!

Cheers!

Reply

Hey, sorry for a late response. I managed to google it out - still a big thanks for a response, it will be more than useful for future projects)

Reply
Keryx Avatar

Thanks for the great tutorial :)

The encore_entry_link_tags('app') and encore_entry_script_tags('app') functions return empty strings for me. The asset function worked fine before. Im running the code on an nginx docker if this is a reason for this? I don't get any 404 errors or errors in general.

Reply

Hey Keryx,

Are you sure you have "app" entry point in your webpack.config.js file? When you run encore "./node_modules/.bin/encore dev --watch" in your terminal, do you see "app.js" and "app.css" files in the output? Are they exist in the public/build/ directory?

Btw, any chance you're trying to render multiple times in the same request? Because it will be rendered only once when you run it the first time, and render empty output for all further times, see this for more info: https://github.com/symfony/...

Cheers!

Reply
Keryx Avatar

Thanks so much I thought the multiple rendering wouldn't be the problem in my code. But watching the twig debug data showed me that this was the case. I got a symfony docker environment from a git repository (because I wanted to save setup time ^^° and also want to work with docker later on) . There were some basic examples in it and probably some kind of packages and configurations that caused this. I now set up a completely new symfony 5 project and followed the instructions again and now it works all fine. Also I now no for sure that I don't have any unnecessary packages in my project. Thanks for leading me to my solution :). I guess I tried to save time in the wrong place :D.

Have a wonderful day thanks :)

Reply

Hey Keryx,

You're welcome, I'm happy you solved this problem! :)

Cheers!

Reply
Beis Avatar

Hi there! Thanks for these tutorials!
If anybody is using npm (like me) just type "npm run watch"

Regards!

Reply

Hey Alex,

Thanks for this tip! ;)

Cheers!

Reply
Montassar H. Avatar
Montassar H. Avatar Montassar H. | posted 3 years ago

after run" ./node_modules/.bin/encore dev "
I 4 files written to public/build
Entrypoint app [big] = vendors~app.css vendors~app.js app.css app.js

Reply

Hey HAMMOUDA,

Great!

Cheers!

Reply
Montassar H. Avatar
Montassar H. Avatar Montassar H. | victor | posted 3 years ago

but i have problem app.js and app.css 404 not found

Reply

how are you importing them in your template?

Reply
Montassar H. Avatar
Montassar H. Avatar Montassar H. | MolloKhan | posted 3 years ago

{{ encore_entry_script_tags('appt') }}

Reply

it should be "app" but I believe you have this right on your code

Reply
Montassar H. Avatar

i think my problem in my container nginx

Reply

Oh, yes, that may be the problem. Nginx must serve the file if it exists, if not, it should pass the request into the front controller (public/index.php)

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
    }
}