Premise
This is an experimental project, the described case will not happen in a "normal" custom element use.
Background
I'm creating an orchestrator for MicroFrontend called AVE to learn MicroFrontends and how they work.
This application has the goal to create and manage different applications/custom elements for Microfrontend development:
As you can see in the video, when I create a custom element and save it, the render on the right side of the application re-define the custom elements.
That's cool right? But how it is done? And why?
The problem
According to html spec you can only define and get a custom element, you cannot update it at runtime.
If you try to define twice the same custom element you'll get the following error:
So you cannot define the same custom element twice. You need to reload the entire page to get the updated definition.
But I don't want (in my project) to reload the entire page
Because I need to edit and update the custom element at runtime, I need to find a solution to edit and update the target custom element.
Solution - using a nested document with iframe
The solution is to put the element definition into an incapsulated iframe:
const iframe = document.createElement("iframe");
document.body.appendChild(iframe);
const nestedWindow = iframe.contentWindow;
const nestedDocument = this.nestedWindow.document;
if (!nestedWindow.customElements.get('customElementName')) {
const s = nestedDocument.createElement("script");
s.type = "text/javascript";
s.innerHTML = "myCustomElementDefinitionScript"
nestedDocument.body.appendChild(s);
nestedDocument.createElement('customElementName');
}
This script will create an iframe and encapsulate into it a script with the custom element class definition (i.e):
myCustomElementDefinitionScript
class CustomElementClass extends HTMLElement {
[...]
}
window.customElements.define('customElementName', CustomElementClass);
Ok fine, our custom component will be rendered once:
Upload the iframe at runtime
How can we re-define the custom element definition when updated?
We can destroy the iframe, create a new one and proceed with a new definition:
// clear our wrapper
document.body.innerHTML = '';
// and re-create the iframe
const iframe = document.createElement("iframe");
document.body.appendChild(iframe);
const nestedWindow = iframe.contentWindow;
const nestedDocument = this.nestedWindow.document;
if (!nestedWindow.customElements.get('customElementName')) {
const s = nestedDocument.createElement("script");
s.type = "text/javascript";
s.innerHTML = "myCustomElementDefinitionScript"
nestedDocument.body.appendChild(s);
nestedDocument.createElement('customElementName');
}
And that's all! The custom element is updated and the iframe re-created!
Notes
- document.body is an example wrapper, you can use any html element.
- putting a custom element into an iframe will remove any wrapper-defined stylesheet (like using a shadowDom), so you will not see the result as using the same custom element in the document directly
- this is just an experiment, in a normal use case you might reload the main page instead of using live update, so it will upload the modified script.
Resources
Reviewers
Thanks to @pzzdvd for reviewing my post.
Top comments (0)