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

[scoped-registries] How does customElements.upgrade() work? #1001

Open
justinfagnani opened this issue Apr 18, 2023 · 2 comments
Open

[scoped-registries] How does customElements.upgrade() work? #1001

justinfagnani opened this issue Apr 18, 2023 · 2 comments

Comments

@justinfagnani
Copy link
Contributor

Right now the global registry's customeElemets.upgrade() is the only way to upgrade a disconnected tree. With scoped registries, we will now have different registries each with an upgrade() method. We have to define how they work.

First, some goals:

  • We can't break existing code
  • We want existing calls to .upgrade() to do the "right" thing if elements in the subtree start using scoped registries.

This brings up a question of user intent. There are potentially two ways to interpret the current intent of a customElements.upgrade(tree) call:

  1. Upgrade all the elements that are defined in the global registry
  2. Upgrade all the elements that are defined in any registry

These are ambiguous at the moment because there is currently only the one global registry.

There seem to me to be a couple of options of how to handle upgrade(). Let's consider how they work on a tree structure like this:

<div>
  <x-a>
    #shadowroot (global registry)
      <x-b>
        #shadowroot (scoped registry)
          <x-c>
            #shadowroot (global registry)
              <x-d>
</div>

And let's assume that this structure is create in such a way that <x-a>, <x-b>, and <x-d> are defined in the global registry after the tree is created, and somehow <x-c> is defined in <x-b>'s scoped registry after <x-b>'s shadow root is created.

This might be contrived and a very rare way to build a tree, but it's possible and I think shows the limit of the question we have to answer.

The question is what happens if someone calls:

customElements.upgrade(x_a);
  1. Upgrade only the elements defined in the global registry.

    This may seem like the simplest approach, but it could break some cases where x-c and other elements need to interact (via events, etc). I would presume it would upgrade nested shadow roots using the global registry, including those nested in scoped-registry using roots like x-c's.

    Presumably with this option, a scoped upgrade call (ie, this.shadowRoot.customElements.upgrade(this.shadowRoot)) would only upgrade definitions in that registry, in any shadow root in the tree using that registry, and not elements defined in the global registry.

  2. Upgrade all elements.

    This might capture the intent of the call better, and results in a maximally functioning subtree.

    One way to do this would be to say that all registries have the same behavior for .upgrade() - that it's roughly equivalent to having a static CustomElementRegistry.upgrade() method.

It might be rare to be in a situation where the answer here matters. I think generic code that needs to call .upgrade() is also probably creating the disconnected subtree, and in order to use scoped registries must already be creating the subtree with one of the scoped element creation APIs.

Still, I think option 2 probably matches user intent better. I'm trying to think of a case where that behavior isn't what you want - where you only want definitions from a single registry to upgrade.

@justinfagnani justinfagnani changed the title [scoped-registries] How does customElement.upgrade() work? [scoped-registries] How does customElements.upgrade() work? Apr 18, 2023
@rniwa
Copy link
Collaborator

rniwa commented Sep 13, 2023

2023 TPAC F2F Resolution: We go with option (2), upgrading all elements across custom element registries. We would only expose upgrade function only on the global custom element registry for clarity.

@trusktr
Copy link
Contributor

trusktr commented Sep 18, 2023

If the upgrade call happens before the definition of x-c in x-b's shadow root, then upgrade needs to be called again after that, right? F.e. imagine x-b is fetching the JS for x-c while the first upgrade() call happens.

Or, will the scoped registry be marked as "upgraded" such that as soon as the definition for x-c is defined, x-c will be upgraded even if the tree is disconnected?

About the ordering (acknowledging that option 2 is already chosen), it shouldn't matter, because if consumers needing to interact with other elements use whenDefined to robustly know when elements are ready to be interacted, upgrade order won't matter.

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

3 participants