Problem/Motivation
SDC documentation is currently promoting using Twig's include function and & embed tag to call components from template. And it seems to be a popular way of using SDC components (for now, let's hope it will disappear as soon as SDC components are becoming usable directly from the render API and the display builders)
There is a big issue about include and embed: they don't pass through the SDC render element and don't trigger the Render API mechanisms.
So, SDC is currently doing a complex workaround.
ComponentsTwigExtension is adding 2 twig functions:
add_component_contextwhich is adding the attribute Attribute object if missingvalidate_component_propswhich is executing the JSON schema validator
They are not supposed to be used by templates owner, there exists because ComponentNodeVisitor is printing those Twig functions on every template, which will be executed on rendering in this order:
- attach_library
- add_component_context
- validate_component_props
In order to make the use of "template to template" Twig functions or tags (include and embed) more similar to the use of the Render API, leveraging the render element. For example, attach_library is used here because #attached is not executed.
This is a mess which can be fixed.
Proposed resolution
- Add asset library attachments (
#attached) and prop validation to the render element itself - Override Twig native
includeandembedto return the SDC render element when the "template" is a full component plugin ID instead of a template path. - Remove everything but
::getNodeVisitors()in ComponentsTwigExtension and most of ComponentNodeVisitor
So, people using SDC from the Render API and people using SDC from templates will have the exact same behaviour and experience, implemented in a cleaner way.
API changes
If done right, this may be free of breaking changes.
Comments
Comment #2
pdureau commentedFor information, UI Patterns 2.x team is also looking for such solution: #3449653: [2.0.0-beta5] Replace component() function by native include() function
Comment #3
pdureau commentedIt would also be the opportunity to also remove ComponentElement::generateComponentTemplate() and to simply render:
Comment #4
quietone commentedChanges are made on on 11.x (our main development branch) first, and are then back ported as needed according to our policies.
Comment #5
pdureau commentedIt was tied by UI Patterns team in #3449653: [2.0.0-beta5] Replace component() function by native include() function
includefunctionembedtagWe can't visit EmbedNode because it doesn't know about:
blockssection)Maybe we can introduce our own EmbedTokenParser which will know:
$parent->getAttribute("value")[$variables, $only, $ignoreMissing] = $this->parseArguments();$module = $this->parser->parse($stream, [$this, 'decideBlockEnd'], true);But working at the parser level is way harder and risker than working at the AST level.
So, let's not do that. The current rendering method is not perfect but work well anyway.