DEV Community

Cover image for CustomElements / WebComponents live reload
Nicola
Nicola

Posted on

1 1

CustomElements / WebComponents live reload

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');
}
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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');
}
Enter fullscreen mode Exit fullscreen mode

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.

Heroku

Build apps, not infrastructure.

Dealing with servers, hardware, and infrastructure can take up your valuable time. Discover the benefits of Heroku, the PaaS of choice for developers since 2007.

Visit Site

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay