adobe / aem-core-wcm-components

Standardized components to build websites with AEM.
https://docs.adobe.com/content/help/en/experience-manager-core-components/using/introduction.html
Apache License 2.0
740 stars 747 forks source link

[CoreCmp] Modularize HTL markup #1893

Open gabrielwalt opened 2 years ago

gabrielwalt commented 2 years ago

As a developer, I want to have the HTML markup modularized into HTL templates so that changing the markup for a group of elements (atom) applies to all components that render those elements.

We should have a set of common HTL templates (data-sly-tempate) for things like:

The HTL of the teaser component would then mostly just call these templates (data-sly-call).

kwin commented 2 years ago

Why not rather including the resource type scripts directly in the teaser (proper composition pattern)? That way also things like in-place editing should work as usual.

fraudoudou commented 2 years ago

Having the resource types in the teaser sounds great! It's confusing for authors, that the title is not a title component and the button is not a button component. For example, our button has a style system to style it for primary and secondary action. It cannot be used for the teaser button atm, and that's some feature we get asked for frequently.

fraudoudou commented 2 years ago

Plus for Dynamic Media integration it would be super nice as well if the teaser was using the image component.

jkoebner commented 2 years ago

upvote! :) :+1:

gabrielwalt commented 2 years ago

Hi @kwin and @jkoebner,

Generally, I agree with you and like the idea. However, including Sling sub-components for component composition comes with a level of complexity that I'm not sure we want to get into. Let's take the simple example of the teaser component, a typical compound component, which could in theory be a composition of the title, text, image and button components.

A first issue is the edit dialog: to be efficient, authors shouldn't have to open 4-5 different dialogs to create a teaser, so we need to assemble these dialogs into one. That could be solved with dialog tabs that include the individual atomic dialogs, but the next issue is then for the recurring properties, like the link to the target page, which should be asked only once, and not separately for the title and the image. That could be solved with some advanced logic in the dialog, but authors could still select the individual atomic components and open their dialogs directly. At that point it starts to become really tricky: we cannot use virtual components, because some components require an actual JCR node with their resource type to function (e.g. the image component requires it for the image servlet to work). That means that we must extend the page editor to prevent the direct editing of child components on compound components like the teaser that want to prevent that behaviour. And finally, how do authors define the policy of the atomic components for the specific scope of the molecule component? That would require some capability for the template editor to allow a compound component to edit the policy of all the child components it's made of…

At that point, it's already a big undertake with a lot of additional complexity, which will also come at a price regarding performance. And we're not even considering the challenge this'd cause for the data layer, where we'd rather have one "teaser" entry, rather than an entry for each atomic component it's made out of.

I have the choice: either we try to solve that problem and do nothing else for 2 months, or we just modularise the HTL files and the dialogs where we see repetition, and also work on a really smooth authoring dialog along with many other improvements we want to do to those components. Or do you see a better way to solve that?

That said, for bigger component assembly, like molecule and organism components, I think that Sling component assembly often is the way to go. But those often happen at project level as such higher-level components are frequently more project-specific.

jckautzmann commented 2 years ago

Following options have been investigated as part of our innovation sprint (Garage Week) to support defining and accessing the specific policy of a sub-component (nested policies):

1) Use the delegation pattern: the teaser node is wrapped into a title resource (similar to the image delegation pattern) https://github.com/adobe/aem-core-wcm-components/pull/1906

2) Use a custom logic to access the nested policy of the sub-component:

3) Make the WCM policy manager support nested policies: in com.day.cq.wcm.core.impl.policies.ContentPolicyUtils#buildInitialContentPolicyMappingPath we could add a special handling if the resource is a sub-component. E.g. it could suffix the structure path (responsive grid) with a path containing the sub-component: "/conf/core-components-examples/settings/wcm/templates/content-page/policies/jcr:content/root/responsivegrid" + "/" + "core-components-examples/components/teaser/title"

ky940819 commented 2 years ago

Personally, I have often wondered why this isn't already a feature higher up in the stack (i.e. a core part of AEM)? There is already a system in AEM that sort of does this - editable templates.

With a bit of effort it seems like composite components could be a thing that follows a similar structure so that components could be composed simply by nodes/xml just as templates are. I would actually make it identical to templates in terms of how they are constructed such that if you know how to craft an editable template then you know how to craft a composite component.

In my vision every composite component would inherit from a common resource type (just like page components typically do), it would probably be very similar to (or extend from) the layout container component.

The top level of the structure would typically be "locked" so that components placed in side of the top layout container (e.g. image, text, title) could be edited, but not removed or added to. This pattern is also not uncommon in editable templates.

For dialogs, yes each atomic part of the composite component would have it's own dialog - this also improves the in-place editing experience. If you really want to, then the base composite component could have a special dialog that aggregates all the dialogs of it's children components.

Ideally, these composite components could be located in the /conf folder as editable components, but it might be nice to be able to add them under /apps as well (with a super resource type as the base composable component, so your implementation only needs the structure and initial nodes).

This still leaves policies as the big issue. Every atomic element should be able to have it's policy configured. For example, in a teaser I should be able to select a single CTA button and apply a "highlighted" style to it or something to emphasize that CTA button. The current policy system does not allow this because it doesn't allow nested policies.

The lack of nested policy support in AEM is already a frustration; for example, the policy for a component can not be configured inside of a container that is placed on the page by the user themselves. If a container component is allowed in the template, then you can configure the allowed components for that container - but not the policy mappings for those allowed components.

Allowing this would be a pretty major change in AEM, albeit a good one in my opinion. The way I envision this being implemented is to allow policy mappings to be children of policy definitions such that the structure of a template (or component) is mapped to a policy (which may be shared by multiple templates/components), and then inside that policy there are further mappings such that the policy resolution is to start by finding the proper policy from the template/component structure, and then follow the chain of mappings within that policy until you find the closest one.

This would also require some reworking of the template editor UI so that for layout containers the policy mappings for it's children can be configured inside the policy configuration dialog instead of (or in addition to) being presented on the page (as is currently the case and poses a UI limitation of sub-policies, even if the policy resolution system supported nested policies). This could either be an additional tab for sub-policy mappings, or an icon next to the allowed components so that the template editor can select the policy mapping to use for each allowed component.

Needless to say, this is a significant undertaking and would be well outside the scope of the Core Components. However, it would provide a solid framework for how to do any composite component, accelerating development time for many custom components (not all, because some complex custom components just can't be formed from the atomic units available), as well as facilitating configuration of some more complex/niche templates that might have multiple levels of nested containers.