Open fabpot opened 8 months ago
We could drop TwigExtraBundle and move all integrations to TwigBundle.
Not sure if that would be a BC break, but i indeed would love to use html_classes without any extra bundle / package :)
Having all extensions (filters, functions etc) lazy loaded by default (RuntimeExtension ?) would remove a performance footgun. Combined with this increasing the "Twig Standard Library" by moving usuful features from TwigExtraBundle to TwigBundle would be great.
I second the call for a components. I know the UX team is doing good work, but tighter integration into Twig would be helpful. I like what Blade is doing with components, and Phoenix (Elixir).
This one is more tooling rather than Twig, but if PhpStorm could reliably detect what objects I'd passed into my template - and even better that I'm iterating over inside a {% for %}
loop it would be a massive productivity boost.
Re the talk around twig.js et al:
Selfishly a grammar for Twig would be great because I'm sick of using alternative template engines in other languages (Liquid, Nunjucks etc) and finding them all inferior to Twig. It's a testament to how good we have it that Twig is a gold standard template engine.
I love Twig Components. If they were integrated directly in Twig, we could deprecate macros, or at least strongly encourage components over macros. Between wrapping a call to a block with a with: {} and Twig Components, I think I've removed all macros from my projects.
Based on @smnandre comment about html_classes
I think that twig extension maybe could be removed when we have something native in Twig for PHP match
Syntax.
I forgot about my biggest request in this genre:
The |raw
filter, instead of being magic, should convert its input into a TwigMarkup
object. You should be able to do {% set var = var|raw %}
or provide { var: var|raw }
to an include
or embed
without doing |raw
again on the receiving end.
Perhaps there are security concerns with this? But I can't see how those would be valid, because you can always just do this:
{% set var %}{{ var|raw }}{% endset %}
...which is identical in function but way too many characters.
I would like that twig supports comments inside twig expressions.
{% set class = [
'border border-greys-200 h-9 text-greys-500 rounded py-2 px-3 block w-full text-sm shadow-sm focus:outline-none focus:ring-1 ring-secondary-300 focus:border-secondary-300 rounded bg-greys-100',
'disabled:text-greys-200',
type != 'search' ? '' : 'pl-9', {# same as w-5 + 2x mr-2 #}
]|join(' ') %}
Other examples:
{% if someCondition {# some comment #}
or otherCondition {# some comment more #}
%}
{% endif %}
{% set object = {
key: someValue, {# some comment #}
%}
{{ include('some.html.twig', {
key: someValue, {# some comment #}
}) }}
Just another wish on comments: A quick way to comment out many lines (that may contains comments themselves), e.g. by wrapping them inside {##
... ##}
. I already suggested this at https://github.com/twigphp/Twig/issues/2897
What did come to my mind that I could think about that @VincentLanglet would have maybe some important Input abouts Twig Tokenizer be more reusable for awesome tools like https://github.com/VincentLanglet/Twig-CS-Fixer, which currently if I remember have to recreate there own Tokinizer.
What did come to my mind that I could think about that @VincentLanglet would have maybe some important Input abouts Twig Tokenizer be more reusable for awesome tools like VincentLanglet/Twig-CS-Fixer, which currently if I remember have to recreate there own Tokenizer.
In https://github.com/VincentLanglet/Twig-CS-Fixer I wrote my own
For the tokenizer/token, I'm more specific than the default Twig Lexer, for instance
Block name
are a specific type different from name
If I want to use the default Lexer with some changed, I would need
pushToken
method, since I need more information in a Token (the line position, the filename, sometime a "related token")SPREAD_TYPE = 13
; if people are now able to modify the lexer and create their own token, this wouldn't have been possible cause people could have use this constant for something else (like I did before https://github.com/VincentLanglet/Twig-CS-Fixer/blame/271faaaeb71ee52173436e9df41c3f298d376a3f/src/Token/Token.php#L28 ; now I decided to use string for my custom constants, and int for twig default ones)Thanks for thinking about it @alexander-schranz but I'm not sure it would something easy to change in twig code.
But one great step would be to split the Lexer into smaller services/methods reusables. For instance the getOperatorRegex
method or other similar regex constants/methods could be in separate service or provide static methods. This way I wouldn't need to duplicate them.
I would love to see a test for array_is_list instead of just iterable.
This would simply return the php array_is_list function result: https://www.php.net/manual/en/function.array-is-list.php
testing is object would (I think) be the same as is not array_is_list, and object / associative array in php/twig are really the same. But knowing that a value is a list would be very helpful.
I am the maintainer of chyrp-lite, which uses Twig for templating. I'd like to be able to use Twig 4.x without having to pull in many additional dependencies. Mention of the Symfony mono-repo concerns me, because having to pull in big chunks of Symfony to use Twig 4.x would make it unsuitable for my project.
I am the maintainer of chyrp-lite, which uses Twig for templating. I'd like to be able to use Twig 4.x without having to pull in many additional dependencies. Mention of the Symfony mono-repo concerns me, because having to pull in big chunks of Symfony to use Twig 4.x would make it unsuitable for my project.
Moving Twig to the Symfony mono-repo would not change anything (just the package name).
Mention of the Symfony mono-repo concerns me,
As I understand it, the monorepo publishes each component / bundle in its own repo, with its own minimal dependencies. So it shouldn't make any difference for users of the twig package, only the twig developers.
At the end twig currently requires the packages which are currently defined in its composer.json: https://github.com/twigphp/Twig/blob/594c548b9224b06683806806875d1583dcb7a59b/composer.json#L28-L31. So when move twig, twig-extra, ... into monorepository twig core would still have the same dependencies as it is build on top of them, so the dependencies for twig are unrelated if twig is maintained over a monorepository or not.
So instead of twig/twig
it maybe symfony/twig
nothing will force you to install the whole symfony/framework to use twig.
I'd love to see full unrestricted arrow function support as per: https://github.com/twigphp/Twig/issues/3402
This would be especially useful for Laravel, Craft, Drupal and other frameworks that use Twig & Collections, but it would be useful in non-Collections use-cases as well.
It would also eliminate the need for work-arounds like Craft Closure
I'd like to see an Empty Coalescing operator added to Twig as well.
Empty Coalesce adds the ???
operator to Twig that will return the first thing that is defined, not null, and not empty. This is particularly useful when you're dealing with a number of fallback/default values that may or may not exist, and may or may not be empty.
The ???
Empty Coalescing operator is similar to the ??
null coalesce operator, but also ignores empty strings (""
), 0, 0.0, null, false, and empty arrays ([]
) as well.
Because this is an Empty Coalesce Operator, it functions identically to the PHP empty()
function in terms of return values.
Example:
{% set bar = null %}
{% set foo = '' %}
{% set baz = [] %}
{% set foobar = woof ??? bar ??? foo ??? baz ??? 'bark' %}
{{ foobar }}
This will output:
bark
...because:
woof
is undefinedbar
is null
foo
is an empty stringbaz
is an empty arrayThere is precedence for this operator in languages such as Swift:
@khalwat there is already a |default
filter that does almost that: it uses the twig definition of "empty" rather than the PHP one (so that the string '0'
is not considered empty)
@stof I'm aware of the |default
filter, but it's the same argument as before as to why it isn't a good solution for the above example.
Try writing this:
{% set foobar = woof ??? bar ??? foo ??? baz ??? 'bark' %}
...using the |default
filter.
@khalwat by genuine curiosity, when would you use a chain of defaults like that ?
it would be great if twig had an up-to-date formatter (maybe with a prettier plugin maintained by core team)
An up-to-date formater for vsCode would be really, really welcome.
@smnandre
curiosity, when would you use a chain of defaults like that ?
In case of project I did review with @sulu there are some cases people require different fallbacks for optional fields in the system. Example like seo.title|default(excerpt.title)|default(content.title)
, is something which appeared there from time of time. You mostly don't need this in typical applications but for CMS based systems with dynamic content where such data isn't provided by a PHP class you require more usage of |default
currenlt instead of have helper methods on your domain models.
@khalwat by genuine curiosity, when would you use a chain of defaults like that?
I have used the ???
from Andrew for years now and I would say it has much better readability and DX.
i would love to see multiline comments but i am not sure if we can speak of a BC break. it is more of a "language break" as fabien mentionent in the PR (https://github.com/twigphp/Twig/pull/3986)
update the signature of getFilters(): array
to getFilters(): iterable
same for others extensions points
see https://github.com/twigphp/Twig/blob/3.x/src/Extension/ExtensionInterface.php#L47-L49
@lyrixx I don't see how this would help actually. Twig is doing array_merge
on those return values IIRC, so returning a generator would not provide any benefit.
One think come to my mind for getFilters
, getFunctions
that this requires that all twig extensions services are created.
I was thinking if we make this methods maybe static
methods, we could maybe make all twig extension lazy in Symfony and only extension services are instantiated which were really used in that twig file, for getting the available function and filters no instiation is required.
Currently a lot of twig extension are created and the current workaround https://symfony.com/doc/current/templates.html#creating-lazy-loaded-twig-extensions is something every devs would require additional work which nobody doing in the projects.
@alexander-schranz using attributes would be a solution for lazy-loading the extensions by default (see https://github.com/twigphp/Twig/pull/3916). The ExtensionSet
mecanism would need some deep changes to split the configuration from the runtime (see https://github.com/symfony/symfony/issues/53403 for Yaml configuration example) in a way that still invalidate cache when the configuration is modified.
@alexander-schranz Twig already has the runtime loader system to allow lazy-loading the implementation of filters and functions. That's available since Twig 2.x
@stof As linked I'm aware of the Runtime way, but that something every devs need to take care of and is so not done by the developers I did review projects with @sulu. It would be nice if the lazyness of Extensions work out of the box atleast for Symfony based application where lazy services exists that additional work by the devs is not required.
@GromNaN that sounds kind of interesting.
I would like to see support for theme in different dirs. Something like:
@ddimoia-wt you maybe interestd in using https://github.com/Sylius/SyliusThemeBundle
@ddimoia-wt isn't it just a matter of changing the filesystem loader root path?
I would appreciate some syntactic sugar to simplify arrow functions. They're quite awkward when you first meet them - then you get used to it, ok, but it would be great to make them more friendly to start with.
I am not suggesting to remove the current syntax - it's fine. I am suggesting adding an alternative way to write it.
The part that I would like to get rid of is what lies before the =>
. The reason that part is there is to establish the names that will be used in the function code. But for the simplest cases, mere convention could establish that, and there would be no arrows.
{{ sizes|filter(v => v > 38) }}
could be written as (several alternatives for your consideration, pick only one):
{{ sizes|filter(value > 38)}}
(well-known names value
- and also key
if it's a mapping){{ sizes|filter(x > 38)}}
or {{ sizes|filter(size > 38)}}
(not well-known values, but compiler figures that an unknown identifier is the variable name - would work only for a single variable){{ sizes|filter(> 38)}}
(compiler figures that the missing operand is the variable we want - would only work with a single variable){{ sizes|filter($1 > 38)}}
(a numbered argument would allow multiple variables and more complex expressions)This other example from the docs:
{% for k, v in sizes|filter((v, k) => v > 38 and k != "xl") -%}
{{ k }} = {{ v }}
{% endfor %}
could be written with:
{% for k, v in sizes|filter($1 > 38 and $2 != "xl") -%}
or
{% for k, v in sizes|filter(value > 38 and key != "xl") -%}
which is much more readable.
I am sure that some of my suggestions are crap, and possibly even all of them, but I trust one of you who knows more than me can come up with a useful and feasible improvement for arrow functions.
What about named arguments for macros? See here https://github.com/twigphp/Twig/issues/929
@aszenz mentioned it already a bit:
I would like to see a focus on component based templating over overriding/inheritance.
What I miss most with a background from Svelte as frontend developer is Single File Components and the easy way you can develop with them, typehinting, etc. (I develop for Craft CMS now). A small example, it's just easy and everything is pre-defined:
https://github.com/twigphp/Twig/assets/777278/277edcbb-cfc6-4161-b9fe-e5594d9fe966
Setting your own Components Pattern from scratch in Twig is not that hard to be fair, but you need to learn about Includes vs. Embeds vs. Macros, Scoping, etc. etc. And then you need your build steps around it for .scss and .js files, etc. etc.
Big ask, I know - and also very CMS-specific of course + also a question of IDE support.
But a pre-defined, ready-to-use components pattern would be awesome for developers getting started with Twig imho. Thanks very much for providing Twig!
@pgorod The issue is that your proposal creates an ambiguous syntax. {{ sizes|filter(value > 38)}}
is already a valid syntax that calls a filter
filter with a boolean argument being the result of evaluating value > 38
. We cannot make the parsing of the syntax be dependent on the signature of filters and static analysis of the expression (anyway, static analysis generally requires having an AST, and so being done with parsing).
@stof I see your point.
Do you think some simplified arrow function syntax would be possible? Something you come up with, not something directly found in my suggestions.
But one great step would be to split the Lexer into smaller services/methods reusables. For instance the
getOperatorRegex
method or other similar regex constants/methods could be in separate service or provide static methods. This way I wouldn't need to duplicate them.
At least what would be great is to introduce more Interface to allow easily overriding some behavior in the tokenization.
For instance https://github.com/twigphp/Twig/blob/b46e93c7257fb01b7c77768210997b1e00643b91/src/Environment.php#L476 https://github.com/twigphp/Twig/blob/b46e93c7257fb01b7c77768210997b1e00643b91/src/Environment.php#L493 https://github.com/twigphp/Twig/blob/3.x/src/Environment.php#L512 could become
public function setLexer(LexerInterface $lexer)
public function setParser(ParserInterface $parser)
public function setCompiler(CompilerInterface $compiler)
{% block foo %}
,{% style %}<link whatever />{% endstyle%}
then when serving the page, twig accumulate all the styles and remove duplicate ones (for example I have 10 buttons on a given page, so the style will be called 10 times, but this twig function knows that only one is OK).{%-
or {{~
..) stuff and just align on standards,<div data-foo="whatever" />
Annd that's a nice list! I may have some other little things, but I think those 3 blocks are awesome directions to take. Append/style syntax is a perfect teammate for assetmapper, component oriented helpers are perfect teammates for symfonyUX, post processor helps a lot template designers.
My 2 cents are component oriented twig is futur, as anything you can do with twig to embrace this paradigm is future-proof. Major JS libs (angular react vue etc..) bring components to the world, official standards with web components are taking this path also, and CSS nesting and container queries follow this way either. Next 5 10 years are here.
A shorter version for translation would be great. Like {{ foo|trans('domain')}}
. So that the domain is the second argument and not the last one. Mostly you need the domain, but no arguments/replacements.
@dknx01 As I remember correctly twig supports named arguments so you can do {{ foo|trans(domain = 'domain')}}
mayb, but for the domain you mostly just want to define it once and not for all your trans
calls so you can use the trans_default_domain block: {% trans_default_domain 'domain' %}
. See here: https://symfony.com/doc/current/translation.html#translations-in-templates
@Nayte91
An append syntax that may come along with components, for example if I have a button template/component, I have a CSS file to style my buttons; So I could put on top of my component something like {% style %}{% endstyle%} then when serving the page, twig accumulate all the styles and remove duplicate ones (for example I have 10 buttons on a given page, so the style will be called 10 times, but this twig function knows that only one is OK).
You maybe interesting in some kind of Portal
mechanism which is example common in react. See our Portal Twig Extension: https://github.com/sulu/web-twig/blob/2.5/docs/portal.md
@alexander-schranz
You maybe interesting in some kind of
Portal
mechanism which is example common in react. See our Portal Twig Extension: https://github.com/sulu/web-twig/blob/2.5/docs/portal.md
That's very interesting! Does your portal deal with duplications? I'm not sure it fits my example with CSS-for-components, but it definitely represents a interesting addition to Component-Oriented-Twig.
Funnily I worked few months ago on React, on modal components, and I spent some time on the portal render API; Quite a bad practice on the React side, but definitively an interesting tool, maybe the Twig side get rid of the bad practice to keep the shiny tool.
It would be great if named arguments in filters/functions would not be converted to snake case (see https://github.com/twigphp/Twig/issues/3475) - this could be an easy fix for a new version, as it is clearly a BC break to change the behavior, but it is also a seemingly "undocumented" and surprising "feature" and changing it would improve Twig in general in my opinion. Introducing a deprecation error in Twig 3.x when a named argument is converted to snake case could also make upgrading a lot easier, so people who are affected could fix those issues before switching to Twig 4.x.
This issue acts as a community wish list for things you want to see in the next major version that could lead to BC breaks
I don't know if it is a BC, but a support for promises would be great. I have some ideas how it would be possible to work without making another HTTP call (as I do now), but the implementation is beyond my skills.
Another wish would be Twital syntax like:
<ul t:if="users">
<li t:for="user in users">
{{ user.name }}
</li>
</ul>
@zmitic how would your syntax proposal work exactly?
For example, how would you use it there?
{% for index in 1..10 %}
.foo-{{ index }} {
z-index: {{ index }};
}
{% endfor %}
Not a BC break, I would like to have the template path to be rendered in dev mode in the source code so that when inspecting the code in the browser, I can see the template of the block, similar to what Drupal does."
<div>.....
<!-- @twig templates/components/button.html.twig -->
<button>
My button
</button>
......
</div>
I know there is the toolbar, but I think it is more convenient to have this information when inspecting.
Thanks
@twig templates/components/button.html.twig
you can use <!-- {{ _self }} -->
@twig templates/components/button.html.twig
you can use <!-- {{ _self }} -->
Does that mean adding this manually to all files? And then remembering to remove it before committing to git, as I only want to display it in the development environment.
We've started working on the next major Twig release. As announced last year, this new version will probably land under the Symfony mono-repository.
For the first time in Twig history, I'd like to fix the major issues that would be BC breaks and that we've never done.
This issue acts as a community wish list for things you want to see in the next major version that could lead to BC breaks (hint: like operators precedence).
Feel free to comment and vote.