Logo

dev-resources.site

for different kinds of informations.

Handle your Symfony assets without WebpackEncoreBundle, ViteBundle or AssetMapper

Published at
1/8/2025
Categories
symfony
css
javascript
php
Author
Abdouni Abdelkarim
Categories
4 categories in total
symfony
open
css
open
javascript
open
php
open
Handle your Symfony assets without WebpackEncoreBundle, ViteBundle or AssetMapper

A little context

You actually need to handle assets in your Symfony application and you don't know how to do this ?

I'm gonna show you here one way, without using WebpackEncoreBundle, ViteBundle or AssetMapper.

However, this is not the best way to handle assets with Symfony, but maybe it's the easiest one.

So, why are you showing us this way ? 🤔

Because... sometimes, you can need to handle assets this way, for example:

  • you don't have many time and can't wait to learn AssetMapper
  • you are a young symfony developer and you don't want to spend too much time learning frontend tools like Webpack or Vite
  • you have a wonderful legacy project and need to migrate it step by step
  • you just have a few frontend assets and don't want to use a more robust solution

Create a Symfony project

Let's start by creating a fresh new Symfony project executing this command:

symfony new --webapp symfony-handle-assets

If you don't have the Symfony CLI binary, you can install it from here.
But if you don't want, you can also create a Symfony project by using Composer.

Remove Symfony AssetMapper files

We're gonna start by... removing some files.
Yeah, actually we don't need the files installed for AssetMapper, so we're gonna delete them.
But before, start by removing these libraries:

composer remove symfony/asset-mapper symfony/ux-turbo symfony/stimulus-bundle

Delete also the assets directory.
Congrats, you did it 🎉

Now, get back on our subject.💪

Our first Controller

Start the Symfony webserver by running:

symfony serve -d

Create now a new Symfony Controller by using the Symfony MakerBundle with this shiny command:

./bin/console make:controller

I named this controller FrontController, but you can name it whatever you want. I choose to not generate tests.
Thanks to the MakerBundle, we have this content:

<?php

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;

final class FrontController extends AbstractController{
    #[Route('/front', name: 'app_front')]
    public function index(): Response
    {
        return $this->render('front/index.html.twig', [
            'controller_name' => 'FrontController',
        ]);
    }
}

We also have the associated file front/index.html.twig, in templates directory, with this content:

{% extends 'base.html.twig' %}

{% block title %}Hello FrontController!{% endblock %}

{% block body %}
<style>
    .example-wrapper { margin: 1em auto; max-width: 800px; width: 95%; font: 18px/1.5 sans-serif; }
    .example-wrapper code { background: #F5F5F5; padding: 2px 6px; }
</style>

<div class="example-wrapper">
    <h1>Hello {{ controller_name }}! ✅</h1>

    This friendly message is coming from:
    <ul>
        <li>Your controller at <code>/Users/abdounikarim/Web/poc/poc-symfony-handle-assets/src/Controller/FrontController.php</code></li>
        <li>Your template at <code>/Users/abdounikarim/Web/poc/poc-symfony-handle-assets/templates/front/index.html.twig</code></li>
    </ul>
</div>
{% endblock %}

Start by updating our FrontController to go on / and remove the controller_name variable, we are not gonna use it:

<?php

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;

final class FrontController extends AbstractController{
    #[Route('/', name: 'app_front')]
    public function index(): Response
    {
        return $this->render('front/index.html.twig');
    }
}

Update also the associated template content, here front/index.html.twig:

{% extends 'base.html.twig' %}

{% block title %}Hello FrontController!{% endblock %}

{% block body %}
<style>
    .example-wrapper { margin: 1em auto; max-width: 800px; width: 95%; font: 18px/1.5 sans-serif; }
    .example-wrapper code { background: #F5F5F5; padding: 2px 6px; }
</style>

<div class="example-wrapper">
    <h1>Hello from Symfony without WebpackEncoreBundle, ViteBundle or AssetMapper ! 👋</h1>

    This friendly message is coming from:
    <ul>
        <li>Your controller at <code>/Users/abdounikarim/Web/poc/poc-symfony-handle-assets/src/Controller/FrontController.php</code></li>
        <li>Your template at <code>/Users/abdounikarim/Web/poc/poc-symfony-handle-assets/templates/front/index.html.twig</code></li>
    </ul>
</div>
{% endblock %}

The controller_name variable has been removed and the h1 tag has been updated.

Handle our assets

Get back to work, create now a app.css file in the css directory (create also this directory in the public existing one) with this content:

body{
    color: #F5F5F5;
    background-color: #999999;
}

I also added the link to this previous file on our base.html.twig template:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>{% block title %}Welcome!{% endblock %}</title>
        <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 128 128%22><text y=%221.2em%22 font-size=%2296%22>⚫️</text><text y=%221.3em%22 x=%220.2em%22 font-size=%2276%22 fill=%22%23fff%22>sf</text></svg>">
        {% block stylesheets %}
            <link href="{{ asset('css/app.css') }}" type="text/css">
        {% endblock %}

        {% block javascripts %}
        {% endblock %}
    </head>
    <body>
        {% block body %}{% endblock %}
    </body>
</html>

Do the same by creating a JavaScript file, I called it app.js and add it in a js directory in public with this wonderful content:

console.log('Hello Symfony from our JavaScript file!🚀');

Here, a simple console.log, but you can put here what you want. Don't forget to add the link in the base.html.twig template:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>{% block title %}Welcome!{% endblock %}</title>
        <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 128 128%22><text y=%221.2em%22 font-size=%2296%22>⚫️</text><text y=%221.3em%22 x=%220.2em%22 font-size=%2276%22 fill=%22%23fff%22>sf</text></svg>">
        {% block stylesheets %}
            <link rel="stylesheet" href="{{ asset('css/app.css') }}" type="text/css">
        {% endblock %}

        {% block javascripts %}
            <script src="{{ asset('js/app.js') }}"></script>
        {% endblock %}
    </head>
    <body>
        {% block body %}{% endblock %}
    </body>
</html>

If you try to access to your homepage, you should have a wonderful ugly design 🤮

Symfony handle assets - design base

Here, we just add CSS and JavaScript files on our base.html.twig template. It means that these files are gonna be used in all of our application, you can put in here all of your common application code.

Yeah, but if I want to have CSS and JavaScript files which contains only code used in specific page, how can I do this ?

Follow the guide 😅

Start by creating a new index.css file, in our css directory(in public) :

ul{
    list-style-type: none;
}
code{
    color: #FFFFFF;
    background-color: #000000 !important;
}

Nothing special here, just a boring CSS code, free to you to add your own code.

Open now your index.html.twig template, and override the stylesheets block and add a link to our fresh CSS file:

{% extends 'base.html.twig' %}

{% block title %}Hello FrontController!{% endblock %}

{% block stylesheets %}
    <link rel="stylesheet" href="{{ asset('css/index.css') }}" type="text/css">
{% endblock %}

{% block body %}
<style>
    .example-wrapper { margin: 1em auto; max-width: 800px; width: 95%; font: 18px/1.5 sans-serif; }
    .example-wrapper code { background: #F5F5F5; padding: 2px 6px; }
</style>

<div class="example-wrapper">
    <h1>Hello from Symfony without WebpackEncoreBundle, ViteBundle or AssetMapper!👋</h1>

    This friendly message is coming from:
    <ul>
        <li>Your controller at <code>/Users/abdounikarim/Web/poc/poc-symfony-handle-assets/src/Controller/FrontController.php</code></li>
        <li>Your template at <code>/Users/abdounikarim/Web/poc/poc-symfony-handle-assets/templates/front/index.html.twig</code></li>
    </ul>
</div>
{% endblock %}

Refresh your browser page, and... we broke our wonderful design 😭.

Symfony handle assets - design index

How can we do now, we lost the previous style ? Are you kidding us ? 😠

Don't panic, there is a simple way to get back the parent style, you just have to use the {{ parent() }} function:

{% extends 'base.html.twig' %}

{% block title %}Hello FrontController!{% endblock %}

{% block stylesheets %}
    {{ parent() }}
    <link rel="stylesheet" href="{{ asset('css/index.css') }}" type="text/css">
{% endblock %}

{% block body %}
<style>
    .example-wrapper { margin: 1em auto; max-width: 800px; width: 95%; font: 18px/1.5 sans-serif; }
    .example-wrapper code { background: #F5F5F5; padding: 2px 6px; }
</style>

<div class="example-wrapper">
    <h1>Hello from Symfony without WebpackEncoreBundle, ViteBundle or AssetMapper!👋</h1>

    This friendly message is coming from:
    <ul>
        <li>Your controller at <code>/Users/abdounikarim/Web/poc/poc-symfony-handle-assets/src/Controller/FrontController.php</code></li>
        <li>Your template at <code>/Users/abdounikarim/Web/poc/poc-symfony-handle-assets/templates/front/index.html.twig</code></li>
    </ul>
</div>
{% endblock %}

Try again to refresh your browser page, the design must be almost the same as before, but don't dream, it's still wonderfully ugly.😅

Symfony handle assets - design index - add parent

Do the same for JavaScript now, create an index.js file in the js directory(in public):

console.log('Hello Symfony from our index.js file!🚀');

Don't forget to add the link in the index.html.twig template:

{% extends 'base.html.twig' %}

{% block title %}Hello FrontController!{% endblock %}

{% block stylesheets %}
    {{ parent() }}
    <link rel="stylesheet" href="{{ asset('css/index.css') }}" type="text/css">
{% endblock %}

{% block body %}
<style>
    .example-wrapper { margin: 1em auto; max-width: 800px; width: 95%; font: 18px/1.5 sans-serif; }
    .example-wrapper code { background: #F5F5F5; padding: 2px 6px; }
</style>

<div class="example-wrapper">
    <h1>Hello from Symfony without WebpackEncoreBundle, ViteBundle or AssetMapper!👋</h1>

    This friendly message is coming from:
    <ul>
        <li>Your controller at <code>/Users/abdounikarim/Web/poc/poc-symfony-handle-assets/src/Controller/FrontController.php</code></li>
        <li>Your template at <code>/Users/abdounikarim/Web/poc/poc-symfony-handle-assets/templates/front/index.html.twig</code></li>
    </ul>
</div>
{% endblock %}

{% block javascripts %}
    {{ parent() }}
    <script src="{{ asset('js/index.js') }}"></script>
{% endblock %}

You see, we can handle assets easily with our Symfony application 😉

Again, it's not the best way to do this, but... you now the drill.

And... please, don't ever deliver a project with a terrible design like this. And if you do it, whatever is the situation, never talk about this article 🤐

Happy coding 😀

Featured ones: