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

[templates] How featureful should the default processor be? #682

Open
domenic opened this issue Nov 2, 2017 · 26 comments
Open

[templates] How featureful should the default processor be? #682

domenic opened this issue Nov 2, 2017 · 26 comments

Comments

@domenic
Copy link
Collaborator

domenic commented Nov 2, 2017

From what I can tell the proposal includes the following features:

  • Stripping leading/trailing whitespace from expressions, so you can do {{ x }} instead of {{x}}.
  • Path searching with dots, so you can do {{x.y}}. (But not brackets, so you cannot do {{x["y"]}}.)
  • Fallback with ||. Doesn't appear to be in the formal spec. Does this use boolean semantics, so false or 0 trigger fallback? Or is it just undefined and null? Just undefined?

There's a lot of potential for scope creep here. I think the most minimal version omits all three of these so it's purely JavaScript property lookup. I'm not sure if that'd be too restrictive, or OK.

Note that Mustache doesn't allow any of these, I am pretty sure, and requires you to manipulate your data into an appropriate format beforehand. (Maybe it supports whitespace stripping?)

@rniwa
Copy link
Collaborator

rniwa commented Nov 2, 2017

Stripping the leading & trailing HTML whitespace is a feature of template parts themselves. Right now, I don't have a formal spec for the default processor. We're pretty much open to options. The only thing we ask is that we don't spend another six months debating & spec'ing the default processor's capability & semantics by making them too complicated.

@caridy
Copy link

caridy commented Nov 3, 2017

I think the most minimal version omits all three of these so it's purely JavaScript property lookup.

I will definitely favor that. Looking at this from the localization point of view, you could have the default message in english, or the key for the label, or both of them combined, or even a complex default ICU or Fluent message inside those {{...}} and the processor will give you the ability to produce the right value. This is a use-case from the far end of the spectrum for simple apps, but definitely important for complex apps.

@tclzcja
Copy link

tclzcja commented Nov 3, 2017

@domenic one concern about the not having {{ x["y"] }} part: what if the property name contains special characters? One case I can think about is i18n, a multi-language property/object may look like:

name["en-AU"]
lastname["zh-CN"]

and we can't use dot in that scenario - I mean, assuming name.en-AU is illegal either in the spec.

@domenic
Copy link
Collaborator Author

domenic commented Nov 3, 2017

You can create an object with the appropriate properties, like you would in Handlebars or Mustache.

@stramel
Copy link

stramel commented Nov 3, 2017

@domenic As I mentioned in #688 I often find myself needing index + 1 which doesn't appear it would be supported by the proposed feature subset.

@domenic
Copy link
Collaborator Author

domenic commented Nov 3, 2017

Yes, you would need to create an object such as const obj = { number: originalObj.index + 1 } and then use {{number}}. Just like in Handlebars.

@justinfagnani
Copy link
Contributor

I think that keeping expressions in the default processors just simple keys will be the best for the first version. Even simple expressions like a.b or a[b] will end up having to define semantics that might not match JavaScript, or JavaScript best practice idioms of any given time, so we'd end up with a not JavaScript, but JavaScript like, expression language in the platform.

Ultimately I think we want to find a way to somewhat safely allow real JavaScript in the expressions with a built-in processor, and until then I think user-space processors can explore the feature space here pretty well.

FWIW - since this proposal is very much like the internals of lit-html - when lit-html produces an HTML template it doesn't put any expressions inside the delimiter, they're all just {{}} and associated with values from the JS template by order. I think this might end up being a very common approach, where the expression are empty, or have a generated key used to lookup in another structure produced from the actual expressions that the developers write.

@rniwa
Copy link
Collaborator

rniwa commented Nov 4, 2017

I think a.b is fine because we can define that as regular [[Get]] on a. What's challenging for + 1, a["b"], etc... is the parsing of it needs to match ES2017 or whatever.

@domenic
Copy link
Collaborator Author

domenic commented Nov 4, 2017

The parsing for property references (a.b) is nontrivial and also needs to match the JS spec. Think about Unicode escapes, which characters are allowed as the first one after the dot, etc.

@rniwa
Copy link
Collaborator

rniwa commented Nov 4, 2017

@domenic : We can just limit to ASCII literals.

@domenic
Copy link
Collaborator Author

domenic commented Nov 4, 2017

That doesn't match the JS spec

@rniwa
Copy link
Collaborator

rniwa commented Nov 4, 2017

@domenic : Obviously not. But we don't have to support the full JS spec as long as it's a strict subset (and I know not all ASCII characters aren't allowed in property list, etc...). For that matter, we wouldn't match the spec regardless of what we spec. Even if we just supported {{~}}, we would have differences to the real JS behavior due to escaping, etc...

@rniwa
Copy link
Collaborator

rniwa commented Nov 4, 2017

I'm going to say that we're gonna insist pretty hard on supporting dot syntax because it's going to be very important for our declarative custom elements syntax.

@domenic
Copy link
Collaborator Author

domenic commented Nov 4, 2017

Ok, we can discuss this point of contention further in person. We'd prefer that to not be in the default processor. (Edit: but, are looking forward to working together and especially seeing the integration you allude to, which will surely add to the discussion.)

@caridy
Copy link

caridy commented Nov 4, 2017

@rniwa

it's going to be very important for our declarative custom elements syntax.

I'm very curious about this use-case. I might be having the wrong intuition here, but a declarative custom element syntax + the constrains imposed by HTML attributes (string values), how is that accessing property members will become an important use-case for declarative declarations? When do you plan to share the declarative syntax proposal?

@rniwa
Copy link
Collaborator

rniwa commented Nov 4, 2017

@caridy : Unfortunately, I'm behind on finalizing the proposal. I was hoping to post it by now but we've found a couple of design flows so we're going to do some reconciliation. We'll try to post it by the web components discussions on Friday at TPAC.

@justinfagnani
Copy link
Contributor

@rniwa I think having a brief summary as early as possible would help get us thinking about it before Friday.

@maxnordlund
Copy link

I imagine this would work like the template strings, so by default any JavaScript expression would be allowed, and by "prefixing" aka choosing which processor to run allow for anything else.

But that's a deep rabbit hole which is not very nice to dive into. What about not specifying a default processor to begin with and let the community try out difference sub-languages?

Kind like pythons format strings, and how date can implement its own language.

@tomalec
Copy link
Contributor

tomalec commented Nov 8, 2017

Speaking of "path syntax" - which would require separate definition, I believe.

Why can't we use JSON Pointer (RFC 6901) it already covers all the rules for escaping, characters allowed by JS, etc.

The downside of that would be the syntax for expressions that would look alien {{foo(/a/b, /c/d/e)}}, but expressions and dot-syntax could be delegated to libraries and frameworks.

But we would not have to bother about specing it and re-inventing the wheel.

@domenic
Copy link
Collaborator Author

domenic commented Nov 10, 2017

Resolved on simplest option for now: https://tc39.github.io/ecma262/#prod-IdentifierName (not https://tc39.github.io/ecma262/#prod-Identifier).

Error-handling behavior: we have options, either throw, output empty string, or just output the curlies as-is. We all want to be forward-compatible with future expansion of the default processor.

Whitespace stripping remains as currently proposed, as a feature of the template parts, not related to the processor.

@glen-84
Copy link

glen-84 commented Apr 14, 2018

Have you considered using Jinja/Twig syntax for conditionals and loops?

{% if condition %}
    <span>{{ val }}</span>
{% endif %}
{% for user in users %}
    * {{ user.name }}
{% else %}
    No users have been found.
{% endfor %}

The <template directive="foreach" expression="items"> syntax seems really verbose to me, and the Handlebars syntax is aesthetically unpleasing in my opinion.

It might also help to distinguish between expression output and control structures in this way.

@justinfagnani
Copy link
Contributor

@glen-84 I suspect that would add a lot of complexity to the parser, making it build a tree structure out of something other than Nodes. By using elements for directives is that the parser can reusing element parsing and tree-building. <template> is really the right element for this too, as it's only potential DOM, and to be interpreted by some other mechanism, in this case the default template processor.

@glen-84
Copy link

glen-84 commented Apr 21, 2018

Can it at least be made less verbose?

Aurelia:

<template repeat.for="item of items">

Vue:

<template v-for="item in items">

@dy
Copy link

dy commented Oct 22, 2020

Are literals supported? Eg. <p>Hello, {{ user || 'guest' }}.

Also − possible syntax for loops, conditionals:

<ul class="todo-list">
  <li class="todo-item" item:each-of="{{ items }}" :if-not="{{ item.done }}">{{ item.text }}
</ul>

@ByteEater-pl
Copy link

In my opinion JsRender is worth a look. It has Mustache style syntax, so familiar to many and aligned with most of what's been discussed for [templates]. It also has a judiciously selected and tuned span of functionality. Its developer Boris Moore originally wanted it to be a templating plugin for jQuery, it was created and contributed by Microsoft, but when it was decided not to move on with it, he split it into a separate project, independent of jQuery. So it seems very well suited for the goal at hand.

@taylor-hunt-kr
Copy link

We could compromise by reviving Netscape 4’s JavaScript Entities, which would appeal to everyone the same amount (i.e. not at all):

<template>
  <time datetime="&{input.iso8601};">&{input.forHumans};</time>
</template>

More seriously, are there specific features we want to avoid from the last time declarative templating was added to the Web in XSLT?

<xsl:template>
<xsl:for-each select="items">
  <xsl:choose>
    <xsl:when test="self.done"/> <!-- forgive my bad XPath -->
    <xsl:otherwise>
      <xsl:value-of select="item.text"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:for-each>
</xsl:template>

I assume the verbosity is undesirable, but accumulated knowledge from implementing/working with it seems like it would usefully inform how powerful this feature should be.

Additionally, the other existing API to compete with on convenience is one we don’t want to look more appealing:

<template>
  <ul class="todo-list">
    <script>
      items.forEach(item => if (!item.done) document.write(`<li class="todo-item">${item.text}</li>`))
    </script>
  </ul>
</template>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests