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

[Template Instantiation] Layering and additional use cases #747

Open
cdata opened this issue Mar 13, 2018 · 20 comments
Open

[Template Instantiation] Layering and additional use cases #747

cdata opened this issue Mar 13, 2018 · 20 comments

Comments

@cdata
Copy link
Contributor

cdata commented Mar 13, 2018

At the face-to-face in Tokyo, @justinfagnani, @domenic and I shared a few of our goals related to the Template Instantiation proposal. I would like to document some of the use cases we imagined to facilitate continued discussion on the topic.

We have begun to think of this feature in terms of three levels (low to high), so the use cases have been organized into levels below. Feedback is anticipated and welcome here, but even if the layering is contentious we hope that the use cases can be considered on their own.

We intend to break this issue out into narrower use-case-specific issues after we have received feedback on this overview.

Please note that the use cases described below are intended to be additive or adaptive to what can already be found in the Template Instantiation proposal.

Please also note that code examples are intended to suggest the capabilities, not the shape of the API.

Level 1

We see the TemplatePart as the vital primitive at the core of Template Instantiation. It enables us to expressively update discrete spots in the DOM tree as state changes. At the lowest level, we would like to:

  1. Create TemplateParts (particularly its derivatives from the original proposal)
  2. (Dis)associate TemplateParts with nodes or node ranges in a tree
    • Example: NodeTemplatePart.attach(parts, parentNode, startNode, endNode);
    • Note: When attached, a NodeTemplatePart should subsume pre-existing nodes into its list of current nodes
  3. Access a list of TemplateParts associated with the cloned content of an HTMLTemplateElement
    • Example: const { content, parts } = template.cloneWithParts(...)

Level 2

Level 2 incorporates the concepts of the TemplateProcessor and TemplateInstance. In addition to what the current proposal describes, we would like to:

  1. Imperatively produce a TemplateInstance from an HTMLTemplateElement and a TemplateProcessor
  2. Perform some HTMLTemplateElement-related “preparation” work one time per HTMLTemplateElement per TemplateProcessor
  3. “Lazily” produce the DOM content associated with a hierarchy of TemplateInstances

Level 3

At the highest level we wield Template Instantiation from markup. The current proposal satisfies our perceived use cases at this level, assuming it also satisfies the use cases we described at levels 1 and 2. The topical use cases at this level including the desire to:

  1. Declare an HTMLTemplateElement and its associated TemplateParts in HTML with a default syntax
  2. Create a TemplateInstance with a standardized TemplateProcessor that is built into the browser
@annevk
Copy link
Collaborator

annevk commented Mar 14, 2018

Thanks for filing this!

What is NodePart?

One thing I'm missing above is attributes. I'd consider it a requirement that Level 1 works for both the node tree and attributes. I think another thing that was suggested is that cloneWithParts() might as well live on DocumentFragment, unless someone can explain the explicit win of only exposing it on HTMLTemplateElement.

The other thing I'd like is to explicitly reach out to frameworks about Level 1. Perhaps by trying to set up a one hour meeting or just emailing whoever we can think of and asking them to give us our thoughts somewhere.

cc @wycats

@cdata
Copy link
Contributor Author

cdata commented Mar 14, 2018

@annevk thanks for the feedback!

NodePart

This was a lazy abbreviation on my part. I intended to refer to a NodeTemplatePart. I will fix this in the original issue text.

One thing I'm missing above is attributes

As stated above, the intent here is to be additive to the original proposal. So, AttributeTemplatePart and InnerTemplatePart still apply at Level 1. Is there an attribute use case missing from the original proposal that you would like to see mentioned here?

cloneWithParts()

We don't have a rigid opinion here, and I can only speculate about what the best approach should look like given various hypothetical spec/implementation constraints.

Frameworks

Speaking on behalf of the Polymer team, we have experimentally confirmed that these features could satisfy the use cases of the Polymer and lit-html libraries (each of these takes a notably distinct approach to leveraging templates).

I have an on-going dialogue with Angular related to the Template Instantiation proposal. Some of the use cases described above came out of direct feedback from their team. I referred Angular to this issue shortly after it was filed, and I am hopeful that they will offer updated feedback soon.

I would appreciate hearing from Ember as well. I understand they may have met the initial proposal with some skepticism, but it would be good to hear if anything mentioned in this issue strikes at use cases they have.

I would also be happy to participate in a meeting or email discussion on this topic involving more framework representatives.

@caridy
Copy link

caridy commented Mar 15, 2018

@cdata at first glance, it LGTM.

@annevk thanks for kicking off the discussion with FW authors. I have discussed this topic with @wycats, also looped @sebmarkbage during the last tc39 meeting. I honestly believe that this proposal should be validated by attempting to demonstrate how existing template systems can be compiled down to a template instance.

@cdata
Copy link
Contributor Author

cdata commented Mar 15, 2018

@caridy thanks for the review!

I have already made some progress validating Polymer and lit-html in this way (repo here). I anticipate adding Angular to this list soon, as we have already shared a few code examples back and forth to test the relevance of this API to their use cases.

I am willing and able to research how this API might apply to Ember and JSX templating strategies. I am also interested in exploring additional strategies (assuming they are sufficiently novel; suggestions welcome). The plan would be to build reference implementations and share them here for further discussion.

Alternatively, if there are members of the various framework communities who are interested in taking on this research themselves, that would be even better.

@annevk
Copy link
Collaborator

annevk commented Mar 15, 2018

Will someone also work on a revised proposal that just covers Level 1? That'd make things a little easier to review.

@cdata
Copy link
Contributor Author

cdata commented Mar 15, 2018

@annevk we could possibly do that, but we were hoping to get a little more feedback on the layering (and possibly split this into a few breakout issues). WDYT?

@rniwa we would be grateful to get your feedback on this issue as well.

@JanMiksovsky
Copy link

In the layering described here, how would the wiring of event listeners be accommodated? Being able to update Shadow DOM in response to component state changes is one reason we currently have to manually scan a cloned fragment to reacquire nodes of interest — the other reason we do that is to find nodes in the cloned fragment so we can listen to events they raise.

During the Tokyo F2F, this notion of reacquiring nodes in a cloned fragment was touched upon several times. Perhaps that's a fundamental primitive, even more so than the notion of updatable parts. In other words, I have a template and a set of interesting nodes inside that template. When I clone the template, I want to find the corresponding set of interesting nodes in the resulting fragment.

Simple use case: I have an expand/collapse component whose template includes a button that should toggle the expand/collapse state of the component. When I clone the template, I want to find that button inside the cloned fragment so that I can listen to the button's click events. That seems related to, but somewhat different than, the notion of subsequently updating the nodes in the cloned fragment.

In our experiments, we found ourselves looking for an efficient way to find nodes in a cloned fragment that correspond to nodes in the original template. One simple technique is to calculate the address of a node in the template as a set of indices into the template tree, then apply that same address to the cloned fragment to acquire the corresponding node. I believe @cdata and @justinfagnani have used a similar technique.

Perhaps such a low-level facility should be part of the proposed Level 1, or an even more primitive Level 0. That is, a developer could mark the nodes in the template (or DocumentFragment) that they care about, and the enhanced cloneWithXXX operation would afford references to the location of those nodes in the resulting fragment. Those references would be used by the cloned parts, but could also be used directly — among other things, for listening to events.

@annevk
Copy link
Collaborator

annevk commented Mar 20, 2018

That is covered by item 3 of Level 1, right?

@cdata
Copy link
Contributor Author

cdata commented Mar 20, 2018

I think that what @JanMiksovsky is advocating for is to receive a list of nodes, rather than a list of parts. I think that this capability would be covered by Level 1 assuming that:

When attached, a NodeTemplatePart should subsume pre-existing nodes into its list of current nodes

which would allow for a NodeTemplatePart to include a reference to a node that is already in the cloned content tree.

@rniwa
Copy link
Collaborator

rniwa commented Mar 21, 2018

I think the layering makes sense although we might need to shuttle things in level 1 and level 2 around depending on how API and use cases shape up.

@robwormald
Copy link

From the Angular end: This approach is definitely in the right direction for us - while we're not interested in using the proposed high-level syntax (it's simply too different / doesn't cover the breadth of our API), the const { content, parts } = someTemplate.cloneWithParts() is an API I can reasonably see us building on top of.

I'd echo @JanMiksovsky's question as well - it would seem to me that AttributePart is a bit of a special case - unless you're going to provide PropertyPart and EventListenerPart(probably not!), everything could be implemented on top of NodeTemplatePart.

The exception to this is InnerTemplatePart - again, it feels a bit opinionated (instead of say, HoleInTheTemplatePart or something) - Angular inserts a comment node to fulfill this case today.

I recognize that the AttributePart is likely necessary for the high level declarative API in the original proposal, so I don't see it as a blocker or anything - in general, the layering proposal is pretty exciting!

@rniwa
Copy link
Collaborator

rniwa commented Mar 22, 2018

Just to echo the point, WebKit team's intention has always been to make this API pluggable as much as possible from the beginning since we knew there are many different approaches & implementations for templating on the Web. The goal is to provide flexible primitive API for libraries & frameworks to build on top, and then provide a nice high level API for developers who want to use native DOM API directly.

@cdata
Copy link
Contributor Author

cdata commented Mar 22, 2018

Thanks to everyone for your feedback on this issue. It sounds like the next step might be to describe a "Level 1" proposal in its entirety.

As I'm relatively new here, I'm not familiar with the process for suggesting changes or adaptations to existing proposals. Would it be to suggest a change directly to the existing proposal, or perhaps to craft a new document that can be compared side-by-side with the original?

I can suggest the changes myself or leave any such change suggestions to the original authors of the proposal if they already have something in mind. Let me know how you think we should proceed here!

Also, I'm happy to split this issue into a few constituent issues representing "Level 1" if it would help keep the discussions focused. Let me know if that would be preferred moving forward!

@annevk
Copy link
Collaborator

annevk commented Mar 22, 2018

Eventually L1 needs to be a PR against the DOM Standard given how intertwined it is with the DOM. Until that time anything goes really, although it would be good to clearly document decision decisions for future archeology. Given that, I think a new document and a set of (labeled) issues would be reasonable.

@rniwa
Copy link
Collaborator

rniwa commented Mar 26, 2018

It would be good to define semantics of the API and get a rough consensus on it before writing a PR. Reading the PR or even spec text isn't the best way to learn how the intended semantics of an API is.

@annevk
Copy link
Collaborator

annevk commented Mar 27, 2018

Well, the "best way" probably depends a whole lot on who is reading, but I agree that it seems a bit early to formalize still. Still need to gather design feedback from all the frameworks and such.

@robwormald
Copy link

@annevk I'd be happy to chat w/ you or whomever - feel free to drop me an email - robwormald at google dot com

@annevk
Copy link
Collaborator

annevk commented Mar 29, 2018

I suspect @cdata and @rniwa are driving this mostly. I think once we have a L1 outline we should try to schedule a call with all the framework stakeholders and hash things out a bit.

@rniwa
Copy link
Collaborator

rniwa commented Apr 1, 2018

I'm meeting with Google folks in SF on Friday to discuss this in person so hopefully we'll have something more concrete then.

@matthewp
Copy link

matthewp commented May 2, 2018

@cdata Thinking about Level 1, I understand a TemplatePart to represent some place in the DOM. In that way it is similar to a Range, except a part can be attached to some other tree. Am I right so far? If so, what is it that you will do with a TemplatePart after you've gotten them from cloneWithParts() (ignoring level 2/3). Will you change their values using part.value = 'new value';? And doing so will change a TextNode's nodeValue, or an attribute's value. Is this the intended affect of level 1?

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

No branches or pull requests

7 participants