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

Initial draft of an explainer conversation around Declarative Custom Elements #1

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 73 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,73 @@
# declarative-custom-elements
Explainer draft for specifying an approach to Declarative Custom Elements
# Declarative Custom Elements
### A discussion...

## Problem
Imperative JS code is required to unlock the power of [Custom Elements](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements), [Shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM), and other "web components" APIs. This is particularly true when these APIs are used in concert with each other. A declarative API would open the door for things like:

- non-JS developers being given the power of custom elements
- having custom element definitions available as parse time without requireing the jump over to the JS thread early in the document parse
- others?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

leaving the multithreading/hydration/rendering optimization to the browser as no JS engaged.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • enabling CMS to expose its content and templates as DCE

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • enabling static site builders without JS yet with rich set of components. Requires external template, which is not in proposal level yet.


*Questions:* Have we come to a future where "web components" amount to _just_ Custom Elements and Shadow DOM? Could we benefit from including other specs in this conversation? Possibly:

- [constructible stylesheets](https://web.dev/constructable-stylesheets/)
- [adoptedStyleSheets](https://wicg.github.io/construct-stylesheets/#using-constructed-stylesheets)
- [aria delegation](https://leobalter.github.io/cross-root-aria-delegation/) (possibly implied but also not currently "spec", only proposal)
- [scoped registries](https://github.com/WICG/webcomponents/issues/716)
- others? see [current Web Components Community Group priorities](https://w3c.github.io/webcomponents-cg/)
Copy link

@sashafirsov sashafirsov Aug 14, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

listed features are needed for the concept of mature DCE libs, but even partial implementation of stack is quite powerful. The static site built purely with DCE is already there. In given sample DCE is expressed via external templates, but extending it to use custom element tags is just a syntax change.

To make the maturity level comparable to current JS stack still needed:

  • lib level scope (namespace) for CSS/JS/importmaps
  • scope definitions which would allow to override CSS internal rules. Do not confuse with complete "html inlude" proposal.
  • module loader. The DCE need ability to be loaded as module with all matching perks:
    • relative path to internally referenced resources. Otherwise all urls would be resolved relatively page baseURI
    • importmaps to be controlled by app AND sub-module, Current JS-centric implementation has a gap there.

Looking into future:

  • Declarative DAL/data island/Data binding. Including transformation of event source data to targets.
  • ability to insulate and override JS VM as in microapplication. Scoped registries and importmaps fits there naturally.


## Existing research
*NOTE:* It would be great to get someone with specific experience with these technologies to write up a demo outlining the declarative nature of components in their context.

- Vue
- Svelte
- [Declarative Shadow DOM](https://web.dev/declarative-shadow-dom/)
- [Declarative CSS modules](https://github.com/WICG/webcomponents/issues/939)
- [x-element](https://www.npmjs.com/package/astro-xelement) from Astro
- [decorate element](https://matthewphillips.info/programming/posts/decorate-element/)
- cons: much like DSD does not allow for scripting.
- others?

Previous conversation in this space have halted at "do we have enough coverage of exisiting paradigms in the room?", let's address that early and often!

## Dreams
I would could this as a smashing success if we were able to do something _like_ the following, but understand this is more of a starting place than necessarily the API that we should drive towards.

1. *External "module"*
```html
<import rel="customelement" href="my-element.html" tagname="my-element" />
<!-- ... -->
<my-element></my-element>
```

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure how to emphasize it, external DCE along with modules resolution is a requirement for mature libs. Without it there is no competition with current JS stack.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The "external" is not limited to URL. It could be the in-page reference. To make it valuable in complex encapsulation cases, a subject for scoping. I.e. reference shall be resolved in the "scope" accounting the namespace(s) and encapsulation.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don’t count elsewhere on the page as “external”. With server side tooling, you might not get “external” declarative custom elements in an initial draft, much like we didn’t with declarative shadow DOM. Where implementors draw the lines of shippable will not always be where we and consumers would.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are going away from server side tooling step by step. CDN became a host for many web components. Importmaps making the use of it. The client side caching and pre-compilation makes build time optimization obsolete. The next logical step is make externalized DCE module as a standard proposal.

2. *Inline "module"*
```
<customelement tagname="my-element">
<!-- ... -->
</customelement>
<my-element></my-element>
```

## Related research

### Import assertions
Can we assert that a file we import ins a"custom element" rather than JSON or CSS or in the future plain HTML? The graph created here may be secondary to a declarative "element" that encapsulated the definition and registration of a custom element.

### Declarative Shadow DOM
This technique upgrades an existing element, `<template>`, to have the side effect of attaching a shadow root the parent element within which is lives. Would we benefit from following this style of approach when addressing inline API as it seems to build on the inert nature of the `<template>` tag to begin with? This might presuppose that instead of a `<customelement>` style registration we coudl leverag something along the lines of `<template custom-element="my-tag">` for these properties when addressing a new specification.

### Module boundaries and scope
When leveraging the JS module graph either as `import ...` or as `<scropt type="module">` we are provided a new scope in which the code available therein is separate from teh rest of the JS scope. Would it make sense to allow for a custom element registered via either via import mechanism or via attribute rules to have such a boundary? In this way we could allow for techniques like scoped registries to be available as if for free with the new scope being create at these boundaries by default...

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo; scropt


### Inline modules (CSS or JS or CEs) tagged as URL
Declarative CSS module research has included inestigation into a sharing mechanism to [prevent multiple copies of the same CSS module](https://github.com/WICG/webcomponents/issues/939). The ability, and possible need, to do so would prevent duplication in a "bundled" context; whether that bundle was manual or built by tooling. ID references do not cross Shadow DOM boundaries, so a technique to cache and reference this content in those situations would be productive.

## Conciderations

### Polyfill/tooling to aid adoption
Any solution put forward here would benefit greatly by being paired as soon as possible with a bundler plug-in or polyfill that would make it possible for consumers to leverage the technique _today_. Previous attempts at larger scale quality of life improvements in this area have suffered greatly from low x-browser investment that has made developer exploration, let along developer adoption, of advances difficult, if not impossible. In the case that this tool the form of a polyfill, it would be important that the polyfill were small enough to inline within the `<head>` of a document in order to mitigate any potention FOUC.

### Is it possible to make components that are valuable to users with 0 JS?
An oft confused (or similarly highly important) topic when dicussing "declarative" APIs is "does it work with no JS?" and that is something that will come up often in any conversations here. If we bind this approach to a `<script>` tag, does that imply that the "declarative" API requires JS? Could a browser vendor speak to whether or not `<script>` is the boundary at which JS being turned off the parser turns back, or is it possible that `asserttype` would allow `customelement` content within a `<script>` tag to still be run in that context? IF that is not possible, then this may already start to shape the aboslutely possibilities of this addition and point us towards alternate choices. The `<template>` tag is certainly an option for inline techniques but we would still be lacking a graph mechanism by which we could build this code. Long term web component developers might lament the loss of HTML Imports in this case, and it might be worth revisiting that concept where actual 0 JS a requirment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we bind this approach to a <script> tag,

needs a sample or at least link to. It is unclear how SCRIPT tag would interact with DCE.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reality that I can to in this conversation with myself if that a declarative custom element and a declarative web component might be different things. Once you get not “declarative” and “web component” you are talking about a host of capabilities that may not be covered by declarative “custom element”. However, all cases seem to point to not having ANY <script> tags, which means you need to go all the way to declarative attributes, which puts a load of extra stress on a proposal here.


### Graph reliance and side effects
There are developers that rely on a single mass import of side effectful registrations of custom elements at the top of their application to coverall custom element usage across the rest of their application. This appears to be a side effect (get it?) of custom elements having a single global scope. If single file or single tag custom elements were to be "module scoped" this reliance could be seen as confusing when going back and forth between JS context. How can we manage this? JSON modules are just data. CSS modules only apply when adopted. CE modules should be handled how?