Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sharing Twig components #2003

Closed
javiereguiluz opened this issue Jul 23, 2024 · 13 comments · Fixed by #2019
Closed

Sharing Twig components #2003

javiereguiluz opened this issue Jul 23, 2024 · 13 comments · Fixed by #2019

Comments

@javiereguiluz
Copy link
Member

javiereguiluz commented Jul 23, 2024

Hi folks,

I've been using Twig components for some time, but I mostly used them to code some dynamic UI features.

Lately I'm using more and more Twig components to create UI "building blocks" that later I use to create interfaces. I mostly learned this from this nice blog series by @WebMamba: How to integrate Component Architecture into Symfony?

Now, I need to share those UI components with other applications. But, it looks like this is not possible yet.

The use cases:

(1) ACME company uses the same UI in many apps and want to share these Twig components
(2) A third-party bundle (e.g. SonataAdmin or EasyAdmin) defines components to ease the building of custom features with the same UI

For your consideration, this is how I imagine this feature in practice. Let's use the first use case about ACME company:

(1) Create a new AcmeUiBundle
(2) Define your PHP-based and anonymous Twig components as usual:

acme-ui-bundle/
    src/
        Search/
            SearchComponent.php
    templates/
        Alert/
            Success.html.twig
            Warning.html.twig
        UserAvatar.html.twig
        Search.html.twig

(3) Configure the bundle to tell Symfony that it provides Twig components:

namespace Acme\Bundle\AcmeUiBundle;

use Symfony\Component\HttpKernel\Bundle\Bundle;
// ...

final class AcmeUiBundle extends Bundle
{
    // ...

    public function addTwigComponents(SomeConfigurator $configurator): void
    {
        $configurator
            // these arguments are the same as in:
            // https://symfony.com/bundles/ux-twig-component/current/index.html#configuration
            ->add(fqcn: __DIR__.'/src', templatesDir: 'templates/', namePrefix: 'Acme')
        ;
    }
}

(4) When you install this bundle in a Symfony app with Symfony UX Twig Component installed, you can start using those imported components like this:

<twig:Acme:Search />
<twig:Acme:Alert:Success> ... </twig:Acme:Alert:Success>

Open questions:

  • What to do if you import Twig components with a namePrefix that collides with an existing prefix in your app? Possible solutions: encourage bundles to not use generic name prefixes (e.g. use <twig:Sonata ... instead of just <twig:Admin ...)
  • Twig components usually require their own CSS/JS assets ... how can we include them automatically when using a component? If not automatically, how can we ease the integration of those bundle assets when using the components?
  • ...

Thanks!

@javiereguiluz javiereguiluz added the Feature New Feature label Jul 23, 2024
@dkarlovi
Copy link
Contributor

Use the Symfony\Component\DependencyInjection\Extension\ExtensionInterface::getAlias to select the prefix, it's already forced to be unique in the app so bundles make sure to make it unique.

@JoppeDC
Copy link
Contributor

JoppeDC commented Jul 23, 2024

Seems like a solid proposal.

Usecase also looks valid.

Extra example:
We currently have a shared component lib with Vue components used in all our apps. This would be the Symfony/Twig alternative to that :)

@smnandre
Copy link
Member

So, here we are right now:

☑️ Key points:

  • importing such components is really something we'd like to offer
  • they have to be "namespaced" (exactly like the templates are today)
  • it should (and can) be the most "automatic way" possible (like the bundle templates are today)
  • the namespace must be the bundle name (like bundle namespaces today...)

☑️ Several aditional points:

  • this should only be for TwigComponent (at least at first) due to security risks/implications
  • users should be able to overrite the templates (like with bundle templates)

😃 Good news: we can do almost all of this for anonymous components, easily (and with some form of configuration for PHP-class-based ones)

And make things work really smootly like this

{{ ux_component('@EasyAdmin:User:Avatar') }}

⚠️ The only thing missing right now is some way to indicate "namespaces" in HTML syntax

<twig:@EasyAdmin:User:Avatar /> 

Something like this ? But it's not valid in the IDE's


📑 Some resources:

@yceruto
Copy link
Member

yceruto commented Jul 24, 2024

the namespace must be the bundle name (like bundle namespaces today...)

it's actually the bundle extension alias; the bundle name is just the fallback if not specified.

@smnandre
Copy link
Member

Regarding assets, any assets provided by a bundle is installed in the public directory during install https://symfony.com/doc/current/bundles.html#bundle-directory-structure

And with AssetMapper, the path of your bundle is automatically mapped: https://symfony.com/doc/current/frontend/asset_mapper.html#third-party-bundles-custom-asset-paths

@smnandre
Copy link
Member

Twig components usually require their own CSS/JS assets ... how can we include them automatically when using a component?

Before we start to handle this in UX, i think this should start with some adjustments into AssetMapper, no ?

As of today, TwigComponent have no concept of "page" or "body", so that would be a entirerly new feature i guess.

First idea: a lazy stimulus controller + CSS imports ?

@smnandre
Copy link
Member

(personal note: this is precisely one of the reason i'd like to release a UXBundle .. make the link between framework bundle and the different ux components, handle configuration, check dependencies / enabled stuff, ...)

@CMH-Benny
Copy link

CMH-Benny commented Jul 26, 2024

(personal note: this is precisely one of the reason i'd like to release a UXBundle .. make the link between framework bundle and the different ux components, handle configuration, check dependencies / enabled stuff, ...)

This sounds like a cool idea, it could build the bridge to AssetMapper and WebpackEncore by offering the needed tools to make the asset imports easier, I think automatic handling is cool, but a very simple installation step could also be fine, that then could be automated by flex :)

The only thing missing right now is some way to indicate "namespaces" in HTML syntax

Personally I would love to see the twig: prefix replacable at some point and especially with bundles, which brings a unique Identifier anyway, it would improve readability so much if you could just do:

<MyUXBundle:Button>MyButton</MyUXBundle:Button>

Not sure if this is possible, but if I imagine a quite complex component structure we will otherwise see code like this:

<twig:MyUXBundleBundle:Table:ActionColumn :foo="bar">MyAction</twig:MyUXBundleBundle:Table:ActionColumn>

@smnandre
Copy link
Member

<MyUXBundle:Button>MyButton</MyUXBundle:Button>

This is not planned right now, and i'm personally not in favor to do so right now.. as it would be mixed with HTML, custom tags, etc.

t if I imagine a quite complex component structure we will otherwise see code like this [...]

Couple of reactions:

  • it would be "@myux" or "MyUX", not "MyUxBundleBundle"
  • not sure when a user would need to call from their template an Foo:Table:ActionColum ... this would probably be in a embeded / overwritten template no ?

As I see it, common IRL usage would look like this:

<twig:Bootstrap:Alert message="{{ message }}" type="error" />

Or

<twig:Bootstrap:Modal title="Update Post">

    {#  Defining default block exposed by this component #}
    {{ form(update_form) }}

</twig:Bootstrap:Modal>

@yceruto
Copy link
Member

yceruto commented Jul 29, 2024

Now, I need to share those UI components with other applications. But, it looks like this is not possible yet.

I gave it a try, and while there are some improvements to be made, everything proposed (in the initial description) is currently possible. No hacks needed—perhaps a bit of magic! The analysis and explanation are too lengthy for a single comment, so I decided to cover it in a blog post.

@CMH-Benny
Copy link

<MyUXBundle:Button>MyButton</MyUXBundle:Button>

This is not planned right now, and i'm personally not in favor to do so right now.. as it would be mixed with HTML, custom tags, etc.

Yeah, I agree on one hand, on the other hand it would be nice to kinda mimic having custom tags, but of course that is a matter of taste and I can follow your argument. I also see that it's not an easy task, it was just something I thought to make it even more immersive when working with symfony ux, it's not the end of the world if people have to learn this <twig:{whatever} ...> syntax

t if I imagine a quite complex component structure we will otherwise see code like this [...]

Couple of reactions:

* it would be "@myux" or "MyUX", not "MyUxBundleBundle"

* not sure when a user would need to call from their template an `Foo:Table:ActionColum` ... this would probably be in a embeded / overwritten template no ?
  • Yes, that was a typo, scrap one of the "Bundle" of the names, still quite long. But if Bundle will be omitted anyway it probably isn't a big issue then 👍
  • Probably yes, but inside of those overridden templates it will still look kinda crazy, but you're right form themes are also not straigt forward when it comes to al its blocks and hirachy, so having longer tag names isn't the biggest deal. Good point 👍

As I see it, common IRL usage would look like this:

<twig:Bootstrap:Alert message="{{ message }}" type="error" />

Or

<twig:Bootstrap:Modal title="Update Post">

    {#  Defining default block exposed by this component #}
    {{ form(update_form) }}

</twig:Bootstrap:Modal>

Okay, in that case I think it looks pretty cool, thanks for clarifying <3

@smnandre
Copy link
Member

I also see that it's not an easy task, it was just something I thought to make it even more immersive when working with symfony ux

That's something i've been thinking a looot about these last months too.. but i really think we first need to make some internal changes in the Twig/Live implementation. To summarize very roughly, Twig component do things "for" LiveComponents that make them less agile/performant when used "massively" in a template.

So let's focus here on the short-term "sharing component" objective, and open another issue for this with a more "middle/long term" goal ?

@yceruto
Copy link
Member

yceruto commented Jul 31, 2024

See #2019 as the first step. Loading anonymous components from the bundle following a convention

@kbond kbond closed this as completed in dec76be Aug 13, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants