RVP RVP - 2 months ago 18
TypeScript Question

Angular2 & TypeScript importing of node_modules

I had a very simple 'hello world' Angular2 app. I also made the apparently unreasonable decision to work with different directory structures between my dev project and the final deployment folder on my spring backend.

Because of this difference, I had an issue with the TypeScript imports, and this line ended up producing 404 errors (unable to find /angular2/core library) when I tried to open the actual app in my browser:

import {Component, View} from 'angular2/core';

So long story short, I ended up adding back the /app folder to make everything work, but I ended up modifying my import statements as follows:

import {Component, View} from '../node_modules/angular2/core';

This, however, turned out to cause some weird behavior. For some reason specifying
in the library paths is causing the JS to actually load ALL Angular2 files from scratch using ajax calls to retrieve each and every individual file from the
folder even though this was part of my HTML header:

<script src="/node_modules/angular2/bundles/angular2.dev.js"></script>

When I finally realized what's going on I reverted the import statement back to

import {Component, View} from 'angular2/core';

and it all worked. Angular2 was now completely loaded from the script tag above and there were no files getting loaded by extra ajax calls.

Can someone please explain what is causing this? I assume it's normal behavior but I don't understand how the importing works and why specifying a more detailed path makes such a difference.


The import rules of TypeScript follow the same convention as node.js. If an import begins with a dot:

import {Something} from './some/path';

Then it is treated as a relative path from the file that declares the import. If however it is an absolute path:

import {Component} from 'angular2/core';

Then it is assumed to be an external module, so Typescript will walk up the tree looking for a package.json file, then go into the node_modulesfolder, and find a folder with the same name as the import, then looks in the package.json of the module for the main .d.ts or .ts file, and then loads that, or will look for a file that has the same name as the one specified, or an index.d.ts or index.ts file.

Wow that seems complex when written out, and there are still some exceptions there... But all in all, if you have worked with node.js before then this should behave exactly the same way.

One thing to note is that there is a TypeScript compiler option that should be set for typing resolutions to work in this way

in tsconfig.json

"moduleResolution": "node"

Now the second part of your question was how does this get loaded without using ajax calls. This is a feature of System.js. The script tag that is loaded in the index.html file imports a bundle which registers the angular2 bundle with System. Once this has happened System knows about these files and correctly assigns them to their references. It's a pretty deep topic but a lot of information can be found either in the README of systemjs, or systemjs-builder.