This article applies to Angular 2 and newer versions.

TL;DR

Using npm link when developing Angular plugins might give you some headaches when trying to import Angular modules from your linked package. It’s related to the node_modules directory.

npm link makes it easy to use a package you are actively working on in an other project without having to npm publish and npm update with every change. The npm documentation on it is very clear, basically it just comes down to sym-linking your plugin package into the node_modules folder from the other project.

The problem when developing Angular modules

I ran into this problem: VM6012:129 Uncaught Error: Unexpected value 'ExternalModule' imported by the module 'AppModule'

Screenshot of the actual error

My external Angular module (linked through npm link) could not be imported by my host application. Google did not turn up with much useful information on my problem, so I decided to dive into the Angular source code to get a clue.

Finding out why the external module is invalid

The specific error was thrown by the metadata_resolver class and indicates that Angular could not find the metadata for the module. The surrounding code led me to the ng_module_resolver class, the reflector class and the reflection_capabilities class.

The external module seemed to have the right decorator data, but ng_module_resolve told me there was not NgModuleMetadata available for my module. Stepping into the _isNgModuleMetadata method showed me that my metadata looked very much like an NgModule instance, but was actually not.

Diving into the DecoratorFactory method reminded me that decorators are just functions. So when the metadata of my module very much looks like an NgModule (created by the DecoratorFactory) but in fact isn’t, it might just be an instance of an NgModule created by another DecoratorFactory.

From there on it did not take me too long to figure out that the import { NgModule } from "@angular/core"; in my linked package was using the angular package from the node_modules folder at it’s original location, and not the ones from the host location.

Wrapping up

In hindsight this all makes sense.

This issue can be explained by the fact that my external package is a symlink and because of how Node modules are resolved. So two instances of NgModule were created, and this explains why the _isNgModuleMetadata method, returned false.

Still, it took me quite a while to fully figure this out. I don’t think we can blame Angular for the vague error message or npm link for the way it’s implemented. It’s just a stupid coincidence of symlinks and method instances (decorators).

I stopped using npm link for this specific project to fix this issue, i hope this explanation makes sense and can help a few people resolving similar issues when running into them.

The upside

I guess there is mostly always an upside on running into issues like this; I really learnt a lot on Angular 2.

I’m a big believer that knowing the internals of a framework can benefit you when using a framework.