3
votes

I have a CustomElement with the following constructor:

export default class SomeCustomElement extends HTMLElement {
    constructor(templateId) {
        super();
        this.insertTemplateInstance(templateId);
    }
    ...
}

I can register that Element in Chrome without any Problems.

But using Firefox with the polyfill loaded by webcomponents-loader.js from https://github.com/webcomponents/webcomponentsjs I get the ErrorMessage TypeError: Illegal constructor when calling super().

Does anybody know what is causing this?

Some more Background:

Registering of the custom Elements happens like this:

window.addEventListener("WebComponentsReady", function () {
    customElements.define(elementName, SomeCustomElement);
});
2
no. But I'm using rollup to be able to use es2015 modules / imports - treeno
You should try with webcomponents-lite. Here the error suggests that the polyfill is not loaded yet when the element is instanciated. Also, you should not call customElement.define in the WebComponentsReady callback. - Supersharp
where should i call define then? I thought calling it in WebComponentsReady would ensure that it is called after the polyfill has been loaded completely - treeno
After having loaded the polyfill, or in the imported file (with <link>). WebComponentReady ensures that the component is already defined and intanciated in order to invoke its methods. - Supersharp
The polyfill should be loaded synchronously. I've tested it with webcomponents-lite and it works fine with firefox. No event needed. Just put the <script> tag before your custom elements tags. - Supersharp

2 Answers

3
votes

Use webcomponents-lite.js instead of webcomponent-loader.js if you don't want to have this kind of error, which is caused by the fact that the polyfills will be loaded asynchronously if you use webcomponents-loader.js.

The example below works fine with Firefox (and every modern browser):

class SomeCustomElement extends HTMLElement
{
  constructor()
  {
    console.log( 'created' )
    super()
  }

  connectedCallback() {
    console.log( 'connected' )
    this.innerHTML = "Hello"
  }
}

customElements.define( 'c-e', SomeCustomElement ) 
<script src=https://rawgit.com/webcomponents/webcomponentsjs/master/webcomponents-lite.js></script>

<c-e></c-e>

However if you still want to use webcomponents-loader.js, you'll have to insert your custom element definition in an external file, and load it with HTML Imports:

<link rel="import" href="my-element.html">
0
votes

Caveat upfront: I'm not a huge fan of html imports. I stumbled across this trying to get ES 6 class-based custom elements to work in Firefox. For a conditional-polyfill-loading-no-html-import solution based on the accepted answer, read on...

To conditionally load the polyfills gets a little tricky. Per @Supersharp's answer/comments, for some reason the polyfill must be loaded synchronously (despite there being no mention of this in the official documentation). So now you have two unappealing options: include it unconditionally to get the necessary synchronous loading or...use document.write:

<script>
;(function() {
  var str = '';
  // You could make this more fine-grained if desired by doing
  // more feature detection and loading the minimal polyfill file 
  if (!window.customElements) str += '<script src="./node_modules/@webcomponents/webcomponentsjs/webcomponents-lite.js"></script>';
  str += '<script src="./elements.js"></script>';
  document.write(str);
})();
</script>
<foo-bar></foo-bar>

Then in elements.js:

class FooBar extends HTMLElement {
  constructor () {
    console.log("constructing");
    super();
  }

  connectedCallback () {
    console.log("connecting");
  }

  disconnectedCallback () {
    console.log("disconnecting");
  }
};
// Note that because of the synchronous loading we don't
// need to listen for the event
customElements.define('foo-bar', FooBar);

document.write is widely disliked for good reasons but this is IMHO a legitimate use case. Note that most of the objections here (no pre-fetch, etc.) can be ameliorated through use of service workers (for browsers that support them).