DEV Community

loading...
Cover image for CustomElements / WebComponents live reload

CustomElements / WebComponents live reload

nicolalc profile image Nicola ・2 min read

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:

Watch on loom

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:

error duplicated definition

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:

Alt Text

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.

Discussion (0)

pic
Editor guide