I'm serving up independent angular apps in different subdirectories with dotnet core. It's been a blast seeing this thing in action, but I'm running into something that I just don't understand.
My app lives here:
wwwroot/
pap/
admin/
boot.ts
admin.component.ts
The MVC route for this app is /pap/admin/. There are two ways I would expect Angular2 routing to work in this situation. The first is to build all of my Angular routes to match the MVC routes. This works, but it feels cheap. The second way is to set the base tag like so:
<base href="/pap/admin/">
Both of these ways allow me to use server-side and client-side routes independently and without prepending every single route with /panel/admin/. E.g.,
@RouteConfig([
{ path: '/menu', name: 'Menu', component: MenuComponent, useAsDefault: true },
{ path: '/panels/:id', name: 'Panel', component: PanelComponent }
])
My issues are with SystemJS. I've experimented, read, searched, and I still don't know what is going on. In the quickstart, the Angular libraries are included in script tags. If I understand it correctly, the app doesn't need to be told where Angular and Rxjs are to be loaded from because they are already included in the document.
The libraries are in node_modules and are being served as if they live in wwwroot/. With , naturally my app starts looking for the files in /pap/admin/angular2/ instead of where they are. If I use this configuration,
System.config({
baseURL: '/',
defaultJSExtensions: true,
packages: {
format: 'register',
'pap/admin': { defaultExtension: 'js' }
}
});
System.import('/pap/admin/admin.boot.js')
.then(null, console.error.bind(console));
then the whole thing blows up looking for everything I've ever imported, starting with
import {bootstrap} from 'angular2/platform/browser';
It is looking for it at the root (wwwroot or http://localhost:5000/angular2/platform/browser.js) instead of in /node_modules/angular2/. This makes sense to me, although I don't completely understand why it doesn't use the libraries that I've loaded in the script tags.
If I use
System.config({
baseURL: '/node_modules/',
defaultJSExtensions: true,
packages: {
format: 'register',
'pap/admin': { defaultExtension: 'js' }
},
});
System.import('/pap/admin/admin.boot.js')
.then(null, console.error.bind(console));
the app comes to life. It does so even if I remove the libraries from the script tags. Sure, SystemJS now knows that if I import something from, say, 'angular2/core', that it can look in /node_modules/ to find it. The downside here is that performance is noticeably slower in terms of the initial. Checking the output of dotnet core, I can see that it's loading every file in those libraries. Woops.
I thought if I used baseURL: '/' and mapped the Angular bits to where they live that everything would be fine,
map: { angular2: '/node_modules/angular2/' }
but the result is the same; every last piece is loaded.
One more thing … SystemJS says they will be getting rid of defaultJSExtensions soon, but once I added and started wrangling the System.config part, things just wouldn't work without it.
I would appreciate some guidance from anyone who has experience with either SystemJS or building on top of the new dotnet core stuff.
Edit 1
I tried getting started with jspm, but as I commented below, either I am doing something crazy, or it is. Here is my config.js after running only jspm install angular2:
System.config({
defaultJSExtensions: true,
transpiler: "typescript",
typescriptOptions: {
"module": "commonjs",
"emitDecoratorMetadata": true
},
paths: {
"github:*": "jspm_packages/github/*",
"npm:*": "jspm_packages/npm/*"
},
map: {
"angular2": "npm:angular2@2.0.0-beta.9",
"core-js": "npm:core-js@1.2.6",
"typescript": "npm:typescript@1.8.7",
"github:jspm/nodelibs-assert@0.1.0": {
"assert": "npm:assert@1.3.0"
},
"github:jspm/nodelibs-buffer@0.1.0": {
"buffer": "npm:buffer@3.6.0"
},
"github:jspm/nodelibs-constants@0.1.0": {
"constants-browserify": "npm:constants-browserify@0.0.1"
},
"github:jspm/nodelibs-crypto@0.1.0": {
"crypto-browserify": "npm:crypto-browserify@3.11.0"
},
"github:jspm/nodelibs-events@0.1.1": {
"events": "npm:events@1.0.2"
},
"github:jspm/nodelibs-path@0.1.0": {
"path-browserify": "npm:path-browserify@0.0.0"
},
"github:jspm/nodelibs-process@0.1.2": {
"process": "npm:process@0.11.2"
},
"github:jspm/nodelibs-stream@0.1.0": {
"stream-browserify": "npm:stream-browserify@1.0.0"
},
"github:jspm/nodelibs-string_decoder@0.1.0": {
"string_decoder": "npm:string_decoder@0.10.31"
},
"github:jspm/nodelibs-util@0.1.0": {
"util": "npm:util@0.10.3"
},
"github:jspm/nodelibs-vm@0.1.0": {
"vm-browserify": "npm:vm-browserify@0.0.4"
},
"npm:angular2@2.0.0-beta.9": {
"crypto": "github:jspm/nodelibs-crypto@0.1.0",
"es6-promise": "npm:es6-promise@3.1.2",
"es6-shim": "npm:es6-shim@0.33.13",
"process": "github:jspm/nodelibs-process@0.1.2",
"reflect-metadata": "npm:reflect-metadata@0.1.2",
"rxjs": "npm:rxjs@5.0.0-beta.2",
"zone.js": "npm:zone.js@0.5.15"
},
"npm:asn1.js@4.5.2": {
"assert": "github:jspm/nodelibs-assert@0.1.0",
"bn.js": "npm:bn.js@4.11.0",
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"fs": "github:jspm/nodelibs-fs@0.1.2",
"inherits": "npm:inherits@2.0.1",
"minimalistic-assert": "npm:minimalistic-assert@1.0.0",
"vm": "github:jspm/nodelibs-vm@0.1.0"
},
"npm:assert@1.3.0": {
"util": "npm:util@0.10.3"
},
"npm:bn.js@4.11.0": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0"
},
"npm:browserify-aes@1.0.6": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"buffer-xor": "npm:buffer-xor@1.0.3",
"cipher-base": "npm:cipher-base@1.0.2",
"create-hash": "npm:create-hash@1.1.2",
"crypto": "github:jspm/nodelibs-crypto@0.1.0",
"evp_bytestokey": "npm:evp_bytestokey@1.0.0",
"fs": "github:jspm/nodelibs-fs@0.1.2",
"inherits": "npm:inherits@2.0.1",
"systemjs-json": "github:systemjs/plugin-json@0.1.0"
},
"npm:browserify-cipher@1.0.0": {
"browserify-aes": "npm:browserify-aes@1.0.6",
"browserify-des": "npm:browserify-des@1.0.0",
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"crypto": "github:jspm/nodelibs-crypto@0.1.0",
"evp_bytestokey": "npm:evp_bytestokey@1.0.0"
},
"npm:browserify-des@1.0.0": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"cipher-base": "npm:cipher-base@1.0.2",
"crypto": "github:jspm/nodelibs-crypto@0.1.0",
"des.js": "npm:des.js@1.0.0",
"inherits": "npm:inherits@2.0.1"
},
"npm:browserify-rsa@4.0.1": {
"bn.js": "npm:bn.js@4.11.0",
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"constants": "github:jspm/nodelibs-constants@0.1.0",
"crypto": "github:jspm/nodelibs-crypto@0.1.0",
"randombytes": "npm:randombytes@2.0.3"
},
"npm:browserify-sign@4.0.0": {
"bn.js": "npm:bn.js@4.11.0",
"browserify-rsa": "npm:browserify-rsa@4.0.1",
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"create-hash": "npm:create-hash@1.1.2",
"create-hmac": "npm:create-hmac@1.1.4",
"crypto": "github:jspm/nodelibs-crypto@0.1.0",
"elliptic": "npm:elliptic@6.2.3",
"inherits": "npm:inherits@2.0.1",
"parse-asn1": "npm:parse-asn1@5.0.0",
"stream": "github:jspm/nodelibs-stream@0.1.0"
},
"npm:buffer-xor@1.0.3": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"systemjs-json": "github:systemjs/plugin-json@0.1.0"
},
"npm:buffer@3.6.0": {
"base64-js": "npm:base64-js@0.0.8",
"child_process": "github:jspm/nodelibs-child_process@0.1.0",
"fs": "github:jspm/nodelibs-fs@0.1.2",
"ieee754": "npm:ieee754@1.1.6",
"isarray": "npm:isarray@1.0.0",
"process": "github:jspm/nodelibs-process@0.1.2"
},
"npm:cipher-base@1.0.2": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"inherits": "npm:inherits@2.0.1",
"stream": "github:jspm/nodelibs-stream@0.1.0",
"string_decoder": "github:jspm/nodelibs-string_decoder@0.1.0"
},
"npm:constants-browserify@0.0.1": {
"systemjs-json": "github:systemjs/plugin-json@0.1.0"
},
"npm:core-js@1.2.6": {
"fs": "github:jspm/nodelibs-fs@0.1.2",
"path": "github:jspm/nodelibs-path@0.1.0",
"process": "github:jspm/nodelibs-process@0.1.2",
"systemjs-json": "github:systemjs/plugin-json@0.1.0"
},
"npm:core-util-is@1.0.2": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0"
},
"npm:create-ecdh@4.0.0": {
"bn.js": "npm:bn.js@4.11.0",
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"crypto": "github:jspm/nodelibs-crypto@0.1.0",
"elliptic": "npm:elliptic@6.2.3"
},
"npm:create-hash@1.1.2": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"cipher-base": "npm:cipher-base@1.0.2",
"crypto": "github:jspm/nodelibs-crypto@0.1.0",
"fs": "github:jspm/nodelibs-fs@0.1.2",
"inherits": "npm:inherits@2.0.1",
"ripemd160": "npm:ripemd160@1.0.1",
"sha.js": "npm:sha.js@2.4.5"
},
"npm:create-hmac@1.1.4": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"create-hash": "npm:create-hash@1.1.2",
"crypto": "github:jspm/nodelibs-crypto@0.1.0",
"inherits": "npm:inherits@2.0.1",
"stream": "github:jspm/nodelibs-stream@0.1.0"
},
"npm:crypto-browserify@3.11.0": {
"browserify-cipher": "npm:browserify-cipher@1.0.0",
"browserify-sign": "npm:browserify-sign@4.0.0",
"create-ecdh": "npm:create-ecdh@4.0.0",
"create-hash": "npm:create-hash@1.1.2",
"create-hmac": "npm:create-hmac@1.1.4",
"diffie-hellman": "npm:diffie-hellman@5.0.2",
"inherits": "npm:inherits@2.0.1",
"pbkdf2": "npm:pbkdf2@3.0.4",
"public-encrypt": "npm:public-encrypt@4.0.0",
"randombytes": "npm:randombytes@2.0.3"
},
"npm:des.js@1.0.0": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"inherits": "npm:inherits@2.0.1",
"minimalistic-assert": "npm:minimalistic-assert@1.0.0"
},
"npm:diffie-hellman@5.0.2": {
"bn.js": "npm:bn.js@4.11.0",
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"crypto": "github:jspm/nodelibs-crypto@0.1.0",
"miller-rabin": "npm:miller-rabin@4.0.0",
"randombytes": "npm:randombytes@2.0.3",
"systemjs-json": "github:systemjs/plugin-json@0.1.0"
},
"npm:elliptic@6.2.3": {
"bn.js": "npm:bn.js@4.11.0",
"brorand": "npm:brorand@1.0.5",
"hash.js": "npm:hash.js@1.0.3",
"inherits": "npm:inherits@2.0.1",
"systemjs-json": "github:systemjs/plugin-json@0.1.0"
},
"npm:es6-promise@3.1.2": {
"process": "github:jspm/nodelibs-process@0.1.2"
},
"npm:es6-shim@0.33.13": {
"process": "github:jspm/nodelibs-process@0.1.2"
},
"npm:evp_bytestokey@1.0.0": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"create-hash": "npm:create-hash@1.1.2",
"crypto": "github:jspm/nodelibs-crypto@0.1.0"
},
"npm:hash.js@1.0.3": {
"inherits": "npm:inherits@2.0.1"
},
"npm:inherits@2.0.1": {
"util": "github:jspm/nodelibs-util@0.1.0"
},
"npm:miller-rabin@4.0.0": {
"bn.js": "npm:bn.js@4.11.0",
"brorand": "npm:brorand@1.0.5"
},
"npm:parse-asn1@5.0.0": {
"asn1.js": "npm:asn1.js@4.5.2",
"browserify-aes": "npm:browserify-aes@1.0.6",
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"create-hash": "npm:create-hash@1.1.2",
"evp_bytestokey": "npm:evp_bytestokey@1.0.0",
"pbkdf2": "npm:pbkdf2@3.0.4",
"systemjs-json": "github:systemjs/plugin-json@0.1.0"
},
"npm:path-browserify@0.0.0": {
"process": "github:jspm/nodelibs-process@0.1.2"
},
"npm:pbkdf2@3.0.4": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"child_process": "github:jspm/nodelibs-child_process@0.1.0",
"create-hmac": "npm:create-hmac@1.1.4",
"crypto": "github:jspm/nodelibs-crypto@0.1.0",
"path": "github:jspm/nodelibs-path@0.1.0",
"process": "github:jspm/nodelibs-process@0.1.2",
"systemjs-json": "github:systemjs/plugin-json@0.1.0"
},
"npm:process@0.11.2": {
"assert": "github:jspm/nodelibs-assert@0.1.0"
},
"npm:public-encrypt@4.0.0": {
"bn.js": "npm:bn.js@4.11.0",
"browserify-rsa": "npm:browserify-rsa@4.0.1",
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"create-hash": "npm:create-hash@1.1.2",
"crypto": "github:jspm/nodelibs-crypto@0.1.0",
"parse-asn1": "npm:parse-asn1@5.0.0",
"randombytes": "npm:randombytes@2.0.3"
},
"npm:randombytes@2.0.3": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"crypto": "github:jspm/nodelibs-crypto@0.1.0",
"process": "github:jspm/nodelibs-process@0.1.2"
},
"npm:readable-stream@1.1.13": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"core-util-is": "npm:core-util-is@1.0.2",
"events": "github:jspm/nodelibs-events@0.1.1",
"inherits": "npm:inherits@2.0.1",
"isarray": "npm:isarray@0.0.1",
"process": "github:jspm/nodelibs-process@0.1.2",
"stream-browserify": "npm:stream-browserify@1.0.0",
"string_decoder": "npm:string_decoder@0.10.31"
},
"npm:reflect-metadata@0.1.2": {
"assert": "github:jspm/nodelibs-assert@0.1.0",
"process": "github:jspm/nodelibs-process@0.1.2"
},
"npm:ripemd160@1.0.1": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"process": "github:jspm/nodelibs-process@0.1.2"
},
"npm:rxjs@5.0.0-beta.2": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"process": "github:jspm/nodelibs-process@0.1.2"
},
"npm:sha.js@2.4.5": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"fs": "github:jspm/nodelibs-fs@0.1.2",
"inherits": "npm:inherits@2.0.1",
"process": "github:jspm/nodelibs-process@0.1.2"
},
"npm:stream-browserify@1.0.0": {
"events": "github:jspm/nodelibs-events@0.1.1",
"inherits": "npm:inherits@2.0.1",
"readable-stream": "npm:readable-stream@1.1.13"
},
"npm:string_decoder@0.10.31": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0"
},
"npm:util@0.10.3": {
"inherits": "npm:inherits@2.0.1",
"process": "github:jspm/nodelibs-process@0.1.2"
},
"npm:vm-browserify@0.0.4": {
"indexof": "npm:indexof@0.0.1"
},
"npm:zone.js@0.5.15": {
"es6-promise": "npm:es6-promise@3.1.2",
"process": "github:jspm/nodelibs-process@0.1.2"
}
}
});
Edit 2
While scanning through that list of things that jspm has mapped to in my node library, I noticed this:
"npm:angular2@2.0.0-beta.9": {
"crypto": "github:jspm/nodelibs-crypto@0.1.0",
"es6-promise": "npm:es6-promise@3.1.2",
"es6-shim": "npm:es6-shim@0.33.13",
"process": "github:jspm/nodelibs-process@0.1.2",
"reflect-metadata": "npm:reflect-metadata@0.1.2",
"rxjs": "npm:rxjs@5.0.0-beta.2",
"zone.js": "npm:zone.js@0.5.15"
},
Elsewhere I have seen people installing each of these libraries separately, but it looks like installing angular2 pulls in the usual dependencies all on its own now.
You wrote:
The libraries are in node_modules.
Do not put them there. Put them inside wwwroot
. That's where client-side libraries belong. The node_modules
directory is better for server-side libraries.
Are you using jspm? That might help. Perhaps experiment with it in a throwaway project, to learn about the standard project structure.
C:\MyProject> npm install jspm --save-dev
C:\MyProject> jspm init
On jspm init
, accept most of the defaults (by pressing enter.) There is only one non-default for ASP.NET Core.
Enter server baseURL (public folder path) [./]:wwwroot
Once you have done the jspm init
, install client-side resources like this:
C:\MyProject> jsmp install angular
C:\MyProject> jspm install bootstrap
That will put them into the wwwroot > jspm_packages > npm
directory and also map them in the config.js
file.
Here is a resultant project structure that we have been using (with lots omitted for clarity's sake.)
MyProject/
node_modules/ <-- for server-side tooling
wwwroot/
jspm_packages/ <-- for client-side resources
github/
angular
components
twbs
npm/
typescript@1.8.7/
typescript@1.8.7.js/
config.js
package.json
project.json
Startup.cs
And here is our config.js
. We can use baseURL: "/"
because the config.js lives inside our wwwroot
directory.
System.config({
baseURL: "/",
defaultJSExtensions: true,
transpiler: "typescript",
paths: {
"npm:*": "jspm_packages/npm/*",
"github:*": "jspm_packages/github/*"
},
map: {
"angular": "github:angular/bower-angular@1.5.0",
"bootstrap": "github:twbs/bootstrap@3.3.6",
"typescript": "npm:typescript@1.8.7"
}
});
Good luck. :)