Our platform is built on a micro-frontend architecture with web components. We are using Stencil for some of them, this means we have multiple Stencil apps within one web page. Additionally, we have a UI library, also built with Stencil, which we want to use in these microfrontend components.
We would like to use the Stencil UI library as build-time dependency to the Stencil micro-frontend components. But this currently not possible due to tag name collisions:
Theoretically, two micro-frontends could ship two different versions of the UI library. However, at runtime, they would collide, as they’re both trying to register their UI elements with customElements.define
. Of course, this doesn’t happen as Stencil checks for existing names before registering a new one – but the result is just as bad: The first loaded component always wins, and if it is an older version or has a different API, other components will break.
A solution would be namespacing/prefixing tag names at build or run time, but there is nothing in the web standards for this (yet). And while there is a namespace
config option in Stencil, that doesn’t seem to solve this kind of problem.
With pure ES6, we could at least do the following (i.e. register a custom element with a dynamic tag name):
export class InnerComponent extends HTMLElement
{
static register(prefix) {
customElements.define(`my-${prefix}-inner-component`, InnerComponent)
}
constructor() {
super()
this.shadow = this.attachShadow({ mode: "open" })
}
connectedCallback() {
this.shadow.innerHTML = `<span>this is some UI component</span>`
}
}
And I’m sure we could employ some sort of build-time solution with Webpack etc. to achieve the same.
But is something similar possible with Stencil? Or how else can this be solved?