YET ANOTHER: Uncaught Error: Unexpected value 'UserDialogComponent' declared by the module 'AppModule'. Please add a @Pipe/@Directive/@Component annotation.
Current behavior
summary: Including an external library that uses reflect-metadata
causes an error like this one: https://github.com/angular/angular/issues/15890
Expected behavior
Adding an external library that uses the same polyfill doesn't have to cause errors.
Minimal reproduction of the problem with instructions
Error description: There are two components:
AppComponent and UserDialogComponent
As I see UserDialogComponent behave as if was not decorated with @Component
but that's not true. The problem relies on reflect metadata polyfills I think. If I remove decorators added by kaop-ts
library everything goes well. But it worked before adding UserDialogComponent :\
repo with error: https://github.com/k1r0s/angular2-aop-showcase/ branch: iss-angular-reflection steps to reproduce: clone repo, git checkout origin/iss-angular-reflection, npm install, ng serve
aditional info (images with error trace): https://i.stack.imgur.com/zxxQH.jpg
Attached images: With Chrome dev tools if you set "pause on exception", then you go up on callstack two times and then you evaluate: meta.declarations[1]
You should get UserDialogComponent constructor reference, and then you can execute: Reflect.getMetadata("annotations", meta.declarations[1])
in order to retrieve component metadata but it returns undefined whereas Reflect.getMetadata("annotations", meta.declarations[0])
will successfuly return AppComponent's medatada ... this is kinda bizarre..
What is the motivation / use case for changing the behavior?
By removing third party decorators Angular components mantain their metadata
Environment
Angular version: 4.0.0
package.json (project was generated with angular-cli)
"dependencies": {
"@angular/animations": "^4.0.0",
"@angular/cdk": "^2.0.0-beta.8",
"@angular/common": "^4.0.0",
"@angular/compiler": "^4.0.0",
"@angular/core": "^4.0.0",
"@angular/forms": "^4.0.0",
"@angular/http": "^4.0.0",
"@angular/material": "^2.0.0-beta.8",
"@angular/platform-browser": "^4.0.0",
"@angular/platform-browser-dynamic": "^4.0.0",
"@angular/router": "^4.0.0",
"core-js": "^2.4.1",
"kaop-ts": "^1.4.0",
"rxjs": "^5.4.1",
"zone.js": "^0.8.14"
},
Browser:
- [x] Chromium (desktop) version `Version 59.0.3071.109 (Developer Build)`
For Tooling issues:
- Node version: v6.11.2
- Platform: Linux
Thanks!
as @yurzui pointed, reflect-metadata package overrides global references so it conflicts with, for example core-js.
The solition, in my case, was replace
reflect-metadata
package forcore-js
and then, include in my build an scoped polyfill reflect from core-js.The correct explanation about why with one component wasn't any problem is because decorators are evaluated when class is declared, so when angular decorators are evaluated, it is painless to evaluate third party decorators, as javascript has already stored metadata within memory and can be accessed. Problem was with another component because after first component was declared, typescript evaluates following method decorators from third party libraries which use
reflect-metadata
by reasigning current globalReflect
object... (polluting global namespace.. ) and then, angular try to load second component but @component can no longer store metadata where it needs to be placed, so angular complains about 2nd component has no@component
declaration which is annoying and bizarre in first hand.