Ga door naar de hoofdinhoud

Migrating a web app from VueJS to Symfony UX: retrospective

The last couple of weeks, I have been refactoring the frontend of dikdikdik, one of my pet projects, that we use to track the scores when we play the card game 'wiezen'.

twig and class for DelaerSelectComponent

The release of version 3.0, in which I threw out VueJS in favour of Symfony Turbo and Symfony Live Components was announced yesterday, and in this blog post I look back on the refactoring, making some kind of roundup on what I like and dislike about the new frontend I created with those new symfony-ux tools.

So the idea of Symfony Turbo is to create modern interactive webpages, with php and twig, while using as little JavaScript as possible. I see two big advantges here:

First advantage: I can drop VueJS. Now don't get me wrong, I think VueJS is a great framework, and it helped me a lot when I needed my frontend to directly react on user actions.

But I wrote my original frontend with VueJS 2.6. And the current version of VueJS is version 3.2. VueJS 3 probably has a lot of cool features. And probably some ways of doing things in VueJS 2 are now deprecated. But I don't know those things, and I have little free time to study frontend frameworks for a hobby project. Keeping up with the current PHP and Symfony versions is hard enough already.

Second advantage: I don't have to convert my PHP value objects to json and back.

When I write software, I put a lot of effort in creating value objects. I try to create nice classes that enforce domain rules. And the IDE I use understands those classes, and helps me with code completion and static analysis.

The VueJS frontend I initially created, got its information from the backend by means of api calls. So the api converted the objects I put so many effort in, into json.

Then the JavaScript front-end code then needs to work with those json-objects, but the IDE doesn't know anything about the structure of these objects. So there's no autocompletion, no static analysis, and so my code ends up full of bugs.

Probably there are serveral solutions for this problem. With Symfony Turbo, where the html on the frontend are just rendered twig files, is certainly a viable one. By using {# @var-annotations in the twig files, the IDE knows the type of the used twig-variables, which helps me a lot.

autocomplete in twig files

So that's already a lot of coolness you get from Symfony Turbo. But Symfony Turbo alone didn't solve all my issues.

The score-app I am refactoring, has a lot of input fields and buttons. Initially, when moving over to Symfony Turbo, I had created a good deal of Symfony forms, because that's how Symfony Turbo handles user input, just like in a traditional Symfony application. But this lead me to a single controller action that was building and handling all those different forms, so it triggered the 'Single Responsibility Principle'-alarm in my head.

screenshot of dikdikdik, the score app

Luckily there's also something called Symfony Live Components.

Symfony Live Components are cool because they allow you to isolate the code and twig for a single component in one class and one twig file. E.g. I wrote a dealer select component, that shows the list of active players, letting the user indicate the player who deals the cards. For this, I need one php class, DealerComponent, and one twig file, components/dealerComponent.html.twig. The cool thing is that when the user selects a player, the live component can call the code in that php class. This is because the live component class is actually a controller. In the case of the DealerSelectComponent, when a change-event is fired for the drop-down, the JavaScript magic of the live components calls the controller action (the live action) DealerSelectComponent::selectDealer().

Dealer select: component and twig

So combining Symfony Turbo and Symfony Components, I managed to remove all VueJS, and still have a nice and rather readable codebase.

But of course it is not perfect. There are still some things I'm not 100% happy with.

  • I don't really like the way I combine the event sourced back-end with the re-rendering of the symfony components in the frontend, see also my previous post.
  • I had to introduce a new event RenderingRequested, to work around the problem that the frontend was re-rendered based on read models that weren't up to date.
  • I still have Symfony forms in place for the actual score logging and for logging corrections. I think it would be better to convert those to live components as well.

We'll see what the future brings; this application is always a work in progress. I'll keep you posted if something interesting happens to the project in the future. But I also want to remind you that dikdikdik is just a hobby project, and I don't always have a lot of time to work on it.

If I raised your interest for the project, you might want to take a look at the source code; it's available on gitlab under the conditions of the GNU AGPL.


Comments powered by Disqus