I'm trying to produce an Angular app based on my first app, which gives me some trouble.
Here's what I've got:
index.html
<!DOCTYPE html>
<html>
<head>
<base href="/"/>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>FiveRX 2.0 Management</title>
<meta charset="utf-8"/>
<!-- Dependencies -->
<script src="/node_modules/core-js/client/shim.min.js"></script>
<script src="/node_modules/systemjs/dist/system.js"></script>
<script src="/node_modules/zone.js/dist/zone.js"></script>
<!-- Init Application -->
<script src="/app/config/system.config.js"></script>
<script src="/app/config/system.init.js"></script>
</head>
<body>
<div class="header">
<div class="title">Troubleshooting</div>
</div>
<layout></layout>
</body>
</html>
system.config.js
(function (global) {
System.config({
paths: {
"npm:": "node_modules/"
},
map: {
"app": "app",
"@angular/core": "npm:@angular/core/bundles/core.umd.js",
"@angular/common": "npm:@angular/common/bundles/common.umd.js",
"@angular/compiler": "npm:@angular/compiler/bundles/compiler.umd.js",
"@angular/platform-browser": "npm:@angular/platform-browser/bundles/platform-browser.umd.js",
"@angular/platform-browser-dynamic": "npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js",
"@angular/http": "npm:@angular/http/bundles/http.umd.js",
"@angular/router": "npm:@angular/router/bundles/router.umd.js",
"@angular/forms": "npm:@angular/forms/bundles/forms.umd.js",
"@angular/animations": "npm:@angular/animations/bundles/animations.umd.js",
"@angular/animations/browser": "npm:@angular/animations/bundles/animations-browser.umd.js",
"@angular/platform-browser/animations": "npm:@angular/platform-browser/bundles/platform-browser-animations.umd.js",
"rxjs": "npm:rxjs",
},
packages: {
app: {
main: "bootstrap.js"
},
rxjs: {
defaultExtension: "js"
},
scripts: {
format: "register",
defaultExtension: "js",
scriptLoad: true
}
},
meta: {
"*": {
authorization: true
}
}
});
})(this);
system.init.js
System.import('app')
.catch(function(err) {
console.error(err);
});
bootstrap.ts
import { platformBrowserDynamic } from "@angular/platform-browser-dynamic";
tsconfig.json
{
"compilerOptions": {
"target": "es5",
"moduleResolution": "node",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"removeComments": false,
"noImplicitAny": false,
"lib": [ "es5", "es6", "es2015", "dom" ]
}
}
As you see, the bootstrap file doesn't contain anything but an import of platform-browser-dynamic. I get the following error when I try to run this:
Error: exports is not defined
Evaluating http://localhost:55549/app/bootstrap.js
Loading app
at eval (:55549/app/bootstrap.js:2)
at eval (<anonymous>)
at _e (evaluate.js:106)
at instantiate.js:414
at R (register-loader.js:684)
at E (register-loader.js:631)
at O (register-loader.js:540)
at register-loader.js:128
at ZoneDelegate.invoke (zone.js:365)
at Zone.run (zone.js:125)
at zone.js:760
at ZoneDelegate.invokeTask (zone.js:398)
at Zone.runTask (zone.js:165)
at drainMicroTaskQueue (zone.js:593)
at <anonymous>
Now, I can get this to work by targetting ES6 instead of ES5, but that's neither an explanation nor an option. Any ideas what's up here?
You've run into a rather peculiar situation.
With your configuration, tsc
will compile modules to the CommonJS format, which is the default if your target is not es6
. So your bootstrap.ts
code compiles to this JavaScript:
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=bootstrap.js.map
SystemJS is normally able to recognize that a module is a CommonJS module and will automatically provide an execution environment suitable for this case. Unfortunately, the generated code above is not enough to get SystemJS to recognize that your module is in the CommonJS format and so it default to its native module format and fails on Object.defineProperty
because exports
does not exist.
In the code above, you'll notice that there is no require
call that corresponds to your import
statement. That's because tsc
detects that there is no need for a require
call at runtime, and thus does not emit it. If you just change your TypeScript code to this, then tsc
will emit a require
call (otherwise the platformBrowserDynamic()
call would fail) and SystemJS can detect the module format:
import { platformBrowserDynamic } from "@angular/platform-browser-dynamic";
platformBrowserDynamic();
In cases where SystemJS is still unable to detect the format, remember that you can use the format
option in your SystemJS configuration to tell SystemJS to use a specific format.
When you change the target to es6
, the default module format changes to es6
too, which explains why you don't get that error anymore.