RichardZ
RichardZ

Reputation: 355

Angular Element: DOMException: Failed to execute 'define' on 'CustomElementRegistry'

I've created two custom elements using Angular Elements.

I load <capp-customtag1> with <script type="text/javascript" src="assets/customtag1.js"></script>.

Similarly, for <capp-customtag2>.

Separately, they work as intended. However, if I try to use both of them in the same project (an Angular 6 project), when I attempt to load the second script, I get the following error:

ERROR DOMException: Failed to execute 'define' on 'CustomElementRegistry': this name has already been used with this registry.

The calls to CustomElementRegistry are made in customtag1.js and customtag2.js.

This is the code I use to create capp-customtag1 in the Angular Element AppModule constructor:

const el = createCustomElement(CustomTag1Component, {injector: this.injector});
customElements.define('capp-customtag1', el);

This is the code to create capp-customtag2 in the second project's AppModule constructor:

const el = createCustomElement(CustomTag2Component, {injector: this.injector});
customElements.define('capp-customtag2', el);

Why do both elements have the same custom element name? And, how can I fix the problem?

Upvotes: 5

Views: 12434

Answers (4)

doubleya
doubleya

Reputation: 539

I kept running into this error and I added a check to make sure the customElement was not already defined. Simply adding the following before defining the element should fix this error:

if (!customElements.get('webtest')) {  
    customElements.define('webtest', e3);
}

Upvotes: 6

Abhishek Tewari
Abhishek Tewari

Reputation: 425

I know this is quite late to answer but I faced the issue last night and these are my observations. Hope it helps others with this problem ahead.

The error is because of webpack conflict between the various angular applications on your page.

The solution is to change the jsonpFunction name in webpack.config.js of each of your web component applications.

Example:

module.exports = {
  //...
  output: {
    jsonpFunction: '<unique name for your application's json function>'
  }
};

Do this for both of your projects related to capp-customtag1 and capp-customtag1.

Upvotes: 4

Sunil Kashyap
Sunil Kashyap

Reputation: 2984

As suspected, it's a bundling issue. The root cause is that webpack (which drives the CLI) uses a runtime: webpackJsonp global, and you're overwriting that each time you load another bundle (which also defines webpackJsonp) - See webpack/webpack#3791 (comment). The CLI doesn't expose this option (things like this are why angular are not supporting this use case yet). You could (though I don't recommend it) manually rename that global webpackJsonp in each bundle to something unique.

You're also duplicating all the polyfills, which is likely to cause all kinds of unexpected results, as they're shimming native APIs and overwriting them at various times. Further, bundling a copy of all the angular packages into each bundle seems suboptimal.

For the moment, if you want to do this sort of use case, your likely best option is going to be to use something like rollup to build UMD bundles, that rely on angular's UMD bundles and exclude the angular source from each element's package. It's going to take some manual work.

Alternately, don't use the CLI to build the individual elements into binaries, treat them as libraries and bring them into the build properly, so you only have one webpack runtime.

Upvotes: 7

Hardik Vyas
Hardik Vyas

Reputation: 500

I am facing similar kind of issue, what I have done is I put a hyphen in between the selector name.

my element selector name webtest to web-test

in app.module.js

before

const e3 = createCustomElement(WebelementTestComponent, { injector: this.injector });
customElements.define('webtest', e3);

after

const e3 = createCustomElement(WebelementTestComponent, { injector: this.injector });
customElements.define('web-test', e3);

then my problem has been solved.

Upvotes: 1

Related Questions