WICG / webcomponents

Web Components specifications
Other
4.36k stars 370 forks source link

Functionally complete declarative templating #997

Open sashafirsov opened 1 year ago

sashafirsov commented 1 year ago

Part of Declarative Web Application stack proposals. Following discourse thread Fully functional declarative template.

Proposing the templating engine which would fit into "classic" template definition.

template as reusable resource

Once declared, the template could be used as is. Unlike TEMPLATE in custom element, it can be reused without the need to be cloned on each instance.

For example, template could comprise just SVG image. This image would be reused without re-instantiation on each template use.

ways to define

As the TEMPLTE element does not fit into requirements, it can not be used without significant update comparable with switching from SCRIPT to script type="module". But the use of templating spread far beyond the inline template definition and as such the TEMPLATE alone is not sufficient. Here are some of template uses:

complete functionality

full data access

including data and input traversing as loop and in the depth, conditions, constants, and custom functions.

rendering

data injection as into final DOM and attributes. as into owned data layer.

data injection

The data slice is outlined separately. Its internal presentation is hidden, exposed over (XPath) selector inside of template. slice samples:

slot

is a backward-compatible with SLOT in TEMPLATE. Internal implementation would treat named SLOT as own slice

modular development with namespace insulation

has to be supported by template engine in order to be sufficient for "mature" platform which would include parts from different vendors and versions. XSLT does fit the bill with XML namespaces, modularity, custom functions, etc.

asynchronous & streaming

for embedded, low-RAM, or low-CPU is critical to be able to

XSLT 3.0 fits the bill with streaming on import of template and streaming the transformation output while the template is still loading.

no side effects

is the principle of Declarative Web Application itself and its components. The template should NOT bring external JavaScript and any another script which is capable to interact (change the state) with page and external elements. Only its content is subject for processing/modification.

POC

Most of proposed features can be polyfilled with current browser stack. You can try it withing the Declarative Custom Element proof of concept @epa-wg/custom-element Is based on native in browser XSLT implementation, backward compatible with TEMPLATE+SLOTS, no shadow DOM. Does provide DX transparency on data layer and dev tools for debugging.


This description is going to be modified to reflect the input. The clone of previous content will be added to the thread for reference.

keithamus commented 1 year ago

I wonder if <template id="foo">Content</template> and <template ref="foo">Fallback content</template> would be better here. Would allow better incremental adoption perhaps?

bahrus commented 1 year ago

Quite a bit of this overlaps with similar proposals, of which this is one, but syntax wise this is as good as if not better than that one. I like the way the url can be added to the include tag as an alternative to the template tag. That puts it more in line with this proposal. So supporting both would make us both happy.

But I do want to chime in that the ability to declaratively make the loading lazy, like images, and iframes, would be quite beneficial (loading="lazy"). Also, streaming support is crucial, but perhaps it should be optional (I don't have a strong reason for preferring opt-in vs opt-out). The reason being that unless a way is provided to adjust the content as it streams (which XSLT 4 might provide), then there would be some circumstances where we would optionally want to insert dynamic data before it lands in the live DOM. Also, the ability to specify different "sandboxing" levels, similar to iframes (maybe using the syntax of the setHTML/parseHTML options?)

I also wonder if it makes sense to allow the include tags to reference id's of templates within the ShadowDOM, or even traverse up the ShadowDOM hierarchy for a matching id, rather than all such definitions be in the head or body tags?

I assume with your mention of slots, that this proposal would allow us to specify whether the streamed/downloaded include should go into the light children / shadow DOM?

Would this proposal be meant as a very useful "side-effect" of HTML Modules, or be treated independently? In my view, getting something like this going without delay could potentially be one of the most significant ways we can help developers achieve acceptable performance as the application grows, so should be priority uno (if reducing carbon emissions / poverty is of any interest to the powers that be :-) ). Not to mention the other apparent side-effect of making the barrier to entry for new developers easier, it seems.

sashafirsov commented 1 year ago

@bahrus , templ-mount, as I see it, the all-in-one POC: shadow DOM, loading, custom element, etc. It is not a proposal yet. This proposal is leaving the insulation and scoping, loading props, custom components, etc. out of equation. Those aspects would be addressed in separate proposals. Now about aspect which is not in scope of this proposal.

Shadow root The proposal is leaving the scoping with or without shadow root. POC gives the non-shadow root solution but could be altered to support various scopes once those clearly defined. I do not see the comprehensive proposal so far.

No JS. This proposal is about pure declarative syntax of template, no JS involved. The declarative-first approach would allow to hook JS up but not be driven by JS, rather by browser engine. It would allow to run the page or microapplication inside with JS disabled option. The JS insulation and scoping would come as a part of microapplication container proposal separately.

Custom Element syntax would come in separate proposal, it is a part of POC though. The syntax seems to be aligned with previous discussions but quite different from templ-mount.

remote request props. Are not addressed in this proposal, good idea though as in dependent WICG proposal. In http-request part of POC for this proposal it is addressed in different declarative-first manner, i.e. via attributes without JSON kind syntax. But I agree that request parameters have to be configurable for all kind of content, not just for data layer as in POC. It worth a separate proposal. Would be glad to join the discussion or pair on creation.

sashafirsov commented 1 year ago

@keithamus , great idea, adding the fallback to proposal.

loading and fallback. The "loaded" attribute by @bahrus is also a good idea. I would refer to the lifecycle of script | iframe | img as the part of proposal for loading and fallback behavior. The "loading=eager | lazy" though have to be aligned with modern hydration proposals, same as "preemptive downloading" from templ-mount.

sashafirsov commented 1 year ago

@keithamus

I wonder if

<template id="foo">Content</template> and <template ref="foo">Fallback content</template> 

would be better here.

The ref concept with the fallback as separate/sibling element is not a part of this proposal. The inline fallback as a body in addition to src=URL is straight. Implementation-wise the separate template and its fallback would create extra burden on parser and loading life cycle. Unless it has a significant advantage to inline fallback, it would not be welcomed by vendors.

<template src="url"> fallback</template>
sashafirsov commented 1 year ago

@bahrus ,

Would this proposal be meant as a very useful "side-effect" of HTML Modules, or be treated independently?

HTML modules are about the loading and content type. This proposal is about templating functionality and some syntax. They do not overlap much. HTML module can be used as template but also as string or a DOM. And template from this proposal could import (via XSLT or src ) the HTML module and use it as template or its part.

In case the HTML module would be capable of DOM and DOM streaming, it can be utilized efficiently by template. Have to review the related proposals to confirm or interfere.

sashafirsov commented 1 year ago

@bahrus

I also wonder if it makes sense to allow the include tags to reference id's of templates within the ShadowDOM, or even traverse up the ShadowDOM hierarchy for a matching id, rather than all such definitions be in the head or body tags?

could you, please elaborate, perhaps with little sample? Not sure what you mean.

bahrus commented 1 year ago

Apologies, @sashafirsov , for jumping to the conclusion that I was addressing similar concerns as you with my POC link. I think I latched on to the little piece of your proposal that I thought I understood, without grasping the larger context.

On a closer reading of your proposal, I think you are proposing something quite novel, with your desire to share a common reference to a template DOM node -- you envision being able to create something like "symbolic links" for DOM nodes, so that multiple DOM nodes that appear throughout the document can be "shared"? If I programmatically alter one "instance", it affects them all, because they are all one instance, really? If I'm understanding that correctly (probably not), that does seem like it could provide some radical performance improvements (but seems like a rather deep change with how the DOM works, but I'm no expert on that question).

For the record, I jumped to the conclusion that this proposal was a bit less ambitious -- just laying out a formal mechanism for including HTML content from an external source. Within that context, the reason I think supporting having a separate template element that can be used to coordinate a client-side include (but ideally, the other link I provided, where the src/href is attached to the actual element where the include happens, would also be supported) is far more mundane -- I think it could make the decision whether to bundle or not to bundle much less of an ordeal going back and forth, in some scenarios where that question makes sense (in particular, when multiple DOM nodes are instantiated from the same template). So I agree, we were discussing apples and oranges.

Anyway, thanks for presenting your ideas.

sashafirsov commented 1 year ago

@bahrus

you envision being able to create something like "symbolic links" for DOM nodes, so that multiple DOM nodes that appear throughout the document can be "shared"?

yes, template DOM can and should be reused across multiple instances. The rendering can be optimized not to inject the whole DOM tree and re-render on each occasion instead of preserving between rendering cycles. The hydration of web components assumes that there is no guarantee the DOM would be constant say during the scroll, templating is another aspect of such dynamic behavior. Programming of web page in such highly dynamic DOM would be different than before as there is no such thing as "final DOM" and stable state.

From another side it is not a dictated by the template semantics and syntax and would be up to platform to follow which would make an adoption easier.

keithamus commented 1 year ago

WCCG had their spring F2F in which this was discussed. Present members of WCCG identified an action item to take the topic of DOM Parts and break it out into extended discussions. You can read the full notes of the discussion (https://github.com/WICG/webcomponents/issues/978#issuecomment-1516897276) in which this was discussed, heading entitled "DOM Parts API".

As this issue pertains to DOM parts, I'd like to call out that https://github.com/WICG/webcomponents/issues/999 has been raised for extended discussions and this topic may be discussed during those sessions.

sashafirsov commented 1 year ago

As this is conceptual and integral story, referencing particular issues with current templating

sashafirsov commented 1 year ago

Proposal related to relative and remote template loading: SRC attribute for Declarative Custom Element

sashafirsov commented 1 year ago

Alternative syntax proposal https://github.com/WICG/webcomponents/pull/1023

I have listed the drawbacks of such syntax in comment