Angular Element: DOMException: Failed to execute 'define' on 'CustomElementRegistry'
Asked Answered
F

4

5

I've created two custom elements using Angular Elements.

  • <capp-customtag1> is defined in customtag1.js
  • <capp-customtag2> is defined in customtag2.js

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?

Filterable answered 6/7, 2018 at 20:33 Comment(8)
Could you post your .js files and your NgModule?Dustydusza
As I understand, you are registering each custom element in each .js file, then you are including them in an Angular 6 project and then registering each customtag again in the NgModule. Is that correct?Dustydusza
I am not registering the customtag again. I don't believe this is required. I simply use that customtag and load the js via a script tag. This works fine when only using one of the customtags. thanks.Filterable
I think your custom elements are not the problem. Check this issue someone else had with Polymer: github.com/Polymer/polymer/issues/5194Dustydusza
Seems like a similar issue. However, I'm not sure what that means as a solution for my problem? Independently created Angular Elements should coexist without a hack.Filterable
I agree with you, but it seems that there is something under the hood when importing multiple angular bundles. Have you debugged your code in order to find when it crashes?Dustydusza
It seems like this is a known problem that is unresolved: github.com/angular/angular/issues/23732Filterable
variant of the same problem at #54212349Lakshmi
L
7

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.

Limber answered 14/6, 2019 at 12:20 Comment(1)
I'd be keen to hear more about this approachMatabele
O
6

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);
}
Onomatology answered 3/2, 2020 at 21:38 Comment(2)
Worked for me.But i get warning as below DOMException: Failed to execute 'define' on 'CustomElementRegistry': the name "webtest" has already been used with this registry.Etiology
I was able to make use of the get method to prevent the error and didn't receive a DOM Exception.Rockweed
T
4

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.

Trombone answered 20/11, 2019 at 5:28 Comment(0)
P
1

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.

Philoprogenitive answered 21/2, 2019 at 10:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.