question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Support scoped custom element registries

See original GitHub issue

Which @angular/* package(s) are relevant/releated to the feature request?

compiler, core, elements

Description

When using microfrontends, you can have the following setup:

  • app-shell
  • microfrontend A (implemented using lit.dev + web component design system)
  • microfrontend B (implemented using angular elements + web component design system)

So the app shell dynamically loads a microfrontend javascript bundle and instantiates the web component and appends it to the DOM in the correct location.

Microfrontend B is implemented using angular elements so the entire angular app is wrapped in a custom element and it won’t conflict with any other microfrontends built using Angular (possibly with a different angular version)

Now the problem arises when A & B use different versions of the design system npm package. Say you have <x-button> versions 1 and 2 in the design system. The first one who registers the custom element via window.customElements.define('x-button', Button) “wins”. The second one who attempts that gets an exception.

Even if you detect if x-button is already defined, you still have issues because A & B expect a specific version of the custom element.

Proposed solution

There is a proposal to handle this, written by @justinfagnani https://github.com/WICG/webcomponents/blob/gh-pages/proposals/Scoped-Custom-Element-Registries.md

This basically comes down to custom elements having a “local” CustomElementRegistry and children of that customElement using that local version instead of the global window.customElements one.

I would propose @angular/elements having an option to use the above proposal. And then having any web component children not using document.createElement, but somehow using a local CustomElementRegistry to instantiate the elements.

In plain web components, every shadowRoot basically “inherits” the local CustomElementRegistry. In Angular however you can have a mix of angular & web components. So not every web components has a parent web component. So you would probably have some sort of CustomElementRegistry injectable that Ivy/Renderer3 then uses to create the element instead of document.createElement.

Alternatives considered

The only workaround I see so far is to use an <iframe> to host the angular microfrontend. That way all web components are isolated to the iframe.

I would love the ability to handle this myself, but I don’t see how you could change Ivy/Renderer3 to not use document.createElement to instead use an injected local CustomElementRegistry?

Issue Analytics

  • State:open
  • Created 2 years ago
  • Reactions:26
  • Comments:6 (2 by maintainers)

github_iconTop GitHub Comments

2reactions
jpzwartecommented, Nov 29, 2021

@gkalpak So this isn’t really hard to do as it turns out; I have it working by providing my own RendererFactory2 implementation.

Some highlights:

  • Creates a new CustomElementRegistry for every component with ShadowDom encapsulation
  • Uses element.getRootNode().createElement(...) instead of document.createElement(...)
  • Added a custom @ElementDefinitions decorator for defining any web components that are used in a component
  • When creating the renderer, check if the component type has any elementDefinitions and register them with the closest registry (either document or the nearest shadowRoot)

See https://gist.github.com/jpzwarte/6dacea6a51a4e7afca9b80014b376e3f for more info

My guess is that it would be pretty easy to add this to Angular in such as way that it would be non-breaking for people not using it.

1reaction
sijakretcommented, Nov 20, 2021

practical support for web components is also related and discussed here https://github.com/angular/angular/issues/12045

Read more comments on GitHub >

github_iconTop Results From Across the Web

webcomponents/Scoped-Custom-Element-Registries ... - GitHub
This proposal allows for multiple custom element definitions for a single tag name to exist within a page. This is accomplished by allowing...
Read more >
@webcomponents/scoped-custom-element-registry - npm
Start using @webcomponents/scoped-custom-element-registry in your project by running `npm i @webcomponents/scoped-custom-element-registry`.
Read more >
Development: Scoped Elements - Open Web Components
Scoped Custom Element Registries is a proposal that will solve this problem, but until it is ready, or a polyfill becomes available, we...
Read more >
Scoped custom elements - RFC
This is where implementation of scoped custom element registries can ... The custom element used in an LWC has to support a way...
Read more >
Intent to Prototype: Scoped Custom Element Registry
This is achieved by allowing user code to create multiple custom element registries and associate them with shadow roots that function as ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found