I grabbed the ng-book 2 as it seemed like a quality way to figure out Angular2. As a heads up, I've never used any of these module loaders or anything before and I've had very limited use of npm and node so all the terminology and assumed knowledge can be quite confusing.
ng-book 2 uses node but I figured I might as well start off using my usual .NET MVC server as that is what I'll be pairing Angular 2 with at work.
My current issue is apparently in the module loading, as I just keep getting 404 errors when systemjs is trying to load angular packages.
app.ts
/**
* A basic hello-world Angular 2 app
*/
import {
NgModule,
Component
} from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { platformBrowserDynamic } from '#angular/platform-browser-dynamic';
#Component({
selector: 'hello-world',
template: `
<div>
Hello World
</div>
`
})
class HelloWorld {
}
#NgModule({
declarations: [HelloWorld],
imports: [BrowserModule],
bootstrap: [HelloWorld]
})
class HelloWorldAppModule { }
platformBrowserDynamic().bootstrapModule(HelloWorldAppModule);
systemjs.config.js
// See also: https://angular.io/docs/ts/latest/quickstart.html
(function(global) {
// map tells the System loader where to look for things
var map = {
'app': 'app/app',
'rxjs': 'app/node_modules/rxjs',
'#angular': 'app/node_modules/#angular'
};
// packages tells the System loader how to load when no filename and/or no extension
var packages = {
'rxjs': { defaultExtension: 'js' }
};
var angularPackages = [
'core',
'common',
'compiler',
'platform-browser',
'platform-browser-dynamic',
'http',
'router',
'forms',
'upgrade'
];
// add package entries for angular packages in the form '#angular/common': { main: 'index.js', defaultExtension: 'js' }
angularPackages.forEach(function(pkgName) {
packages['#angular/' + pkgName] = {
main: 'bundles/' + pkgName + '.umd.js',
defaultExtension: 'js'
};
});
var config = {
map: map,
packages: packages
}
// filterSystemConfig - index.html's chance to modify config before we register it.
if (global.filterSystemConfig) { global.filterSystemConfig(config); }
System.config(config);
})(this);
index.cshtml
<!DOCTYPE html>
<html>
<head>
<title>Angular 2 - Simple Reddit</title>
<script src="~/app/node_modules/core-js/client/shim.min.js"></script>
<script src="~/app/node_modules/zone.js/dist/zone.js"></script>
<script src="~/app/node_modules/reflect-metadata/Reflect.js"></script>
<script src="~/app/node_modules/systemjs/dist/system.src.js"></script>
<link rel="stylesheet" type="text/css" href="~/app/resources/vendor/semantic.min.css" />
<link rel="stylesheet" type="text/css" href="~/app/styles.css" />
</head>
<body>
<script resource="~/app/resources/systemjs.config.js"></script>
<script>
System.import('/app/app.js')
.then(null, console.error.bind(console));
</script>
<hello-world></hello-world>
</body>
</html>
The layout of the project is like this
And what I end up getting with this are requests like
zone.js:101 GET http://localhost:18481/#angular/core 404 (Not Found)
The first thing I see is that probably your systemjs config is not applied, because you have
<script resource="~/app/resources/systemjs.config.js"></script>
Why do you have resource here? systemjs.config.js contains plain javascript code that should be executed like any other script.
Related
I have created my application using systemjs...everything works fine. Now i would like to create a bundle file, but for some reason my application is requesting my module as a separate http request? I thought it should all be included in my bundle.js file? Not sure if i have set something up incorrectly?
My application is stored in the wwwroot/app folder of my application root (asp.net 5 project).
I use gulp to convert my .ts file in .js and put them into wwwroot/dist/app.
I then gulp to convert all these .js files into my bundle.js which is then stored in wwwroot/dist/bundle.js
Now when i execute the page, my bundle.js file is loaded, the .html files are requested (as expected), but a request is made for public.module? I have a feeling it is something to do with this line in the app.routing.ts file loadChildren: 'app/public.module' where the module is loaded dynamically..
I have checked my bundle.js file and no reference of PublicModule is included? Why?
systemjs.config.js
(function(global) {
// map tells the System loader where to look for things
var map = {
'app': 'app', // 'dist',
'#angular': 'node_modules/#angular',
'rxjs': 'node_modules/rxjs',
'angular2-tree-component': 'node_modules/angular2-tree-component',
'lodash': 'node_modules/lodash',
'ng2-bootstrap': 'node_modules/ng2-bootstrap',
'ng2-ckeditor': 'node_modules/ng2-ckeditor',
'ng2-file-upload': 'node_modules/ng2-file-upload',
'ng2-dnd': 'node_modules/ng2-dnd'
};
// packages tells the System loader how to load when no filename and/or no extension
var packages = {
'app': { main: 'main.js', defaultExtension: 'js' },
'rxjs': { defaultExtension: 'js' },
'angular2-tree-component' : { main: 'dist/angular2-tree-component.js', defaultExtension: 'js' },
'lodash' : { main: 'lodash.js', defaultExtension: 'js' },
'ng2-bootstrap' : { defaultExtension: 'js' },
'ng2-ckeditor' : { main: 'lib/CKEditor.js', defaultExtension: 'js' },
'ng2-file-upload' : { main: 'ng2-file-upload.js', defaultExtension: 'js' },
'ng2-dnd': { main: 'index.js', defaultExtension: 'js'}
};
var ngPackageNames = [
'common',
'compiler',
'core',
'forms',
'http',
'platform-browser',
'platform-browser-dynamic',
'router',
'upgrade'
];
// Individual files (~300 requests):
function packIndex(pkgName) {
packages['#angular/' + pkgName] = { main: 'index.js', defaultExtension: 'js' };
}
// Bundled (~40 requests):
function packUmd(pkgName) {
packages['#angular/' + pkgName] = { main: 'bundles/' + pkgName + '.umd.js', defaultExtension: 'js' };
}
// Most environments should use UMD; some (Karma) need the individual index files
var setPackageConfig = System.packageWithIndex ? packIndex : packUmd;
// Add package entries for angular packages
ngPackageNames.forEach(setPackageConfig);
System.config({
defaultJSExtensions: true,
map: map,
packages: packages
});
})(this);
gulpfile.js
var gulp = require('gulp'),
path = require('path'),
Builder = require('systemjs-builder'),
ts = require('gulp-typescript'),
sourcemaps = require('gulp-sourcemaps'),
sass = require('gulp-sass'),
rename = require('gulp-rename'),
concat = require('gulp-concat'),
cleanCSS = require('gulp-clean-css');
var tsProject = ts.createProject('tsconfig.json');
// copy library files
gulp.task('copy:libs', function() {
gulp.src([
'node_modules/core-js/client/shim.min.js',
'node_modules/zone.js/dist/zone.js',
'node_modules/reflect-metadata/Reflect.js',
'node_modules/systemjs/dist/system.src.js',
'node_modules/ckeditor/ckeditor.js'
]).pipe(gulp.dest('wwwroot/dist/lib'));
return gulp.src('node_modules/font-awesome/**/*', { base: 'node_modules' })
.pipe(gulp.dest('wwwroot/dist/lib'));
});
/** first transpile your ts files */
gulp.task('ts', function() {
return gulp.src('wwwroot/app/**/*.ts')
.pipe(sourcemaps.init({
loadMaps: true
}))
.pipe(ts(tsProject))
.pipe(sourcemaps.write('.'))
.pipe(gulp.dest('wwwroot/dist/app'));
});
/** then bundle */
gulp.task('bundle', ['ts'], function() {
// optional constructor options
// sets the baseURL and loads the configuration file
var builder = new Builder('', 'systemjs.config.js');
/*
the parameters of the below buildStatic() method are:
- your transcompiled application boot file (the one wich would contain the bootstrap(MyApp, [PROVIDERS]) function - in my case 'dist/app/boot.js'
- the output (file into which it would output the bundled code)
- options {}
*/
return builder.buildStatic('wwwroot/dist/app/*.js', 'wwwroot/dist/bundle.js', { minify: false, sourceMaps: true})
.then(function() {
console.log('Build complete');
})
.catch(function(err) {
console.log('Build error');
console.log(err);
});
});
// create css file
gulp.task('css', function () {
return gulp.src('wwwroot/sass/app.scss')
.pipe(sass())
.pipe(concat('app.css'))
.pipe(gulp.dest('wwwroot/dist/css'))
.pipe(cleanCSS())
.pipe(rename('app.min.css'))
.pipe(gulp.dest('wwwroot/dist/css'));
});
/** this runs the above in order. uses gulp4 */
gulp.task('build', ['ts', 'bundle', 'copy:libs']);
index.html
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
<link rel="shortcut icon" type="image/x-icon" href="#Html.Raw(ViewBag.BaseUrl)favicon.ico" />
<link href="https://fonts.googleapis.com/css?family=Open+Sans:400,600,700" rel="stylesheet" type="text/css" />
<link href="~/dist/css/app.min.css" rel="stylesheet" type="text/css" />
<link href="~/dist/lib/font-awesome/css/font-awesome.min.css" rel="stylesheet" type="text/css" />
<!-- 1. Load libraries -->
<script src="~/dist/lib/ckeditor.js"></script>
<!-- Polyfill(s) for older browsers -->
<script src="~/dist/lib/shim.min.js"></script>
<script src="~/dist/lib/zone.js"></script>
<script src="~/dist/lib/reflect.js"></script>
<script src="~/dist/lib/system.src.js"></script>
</head>
<!-- 3. Display the application -->
<body>
<my-app>Loading...</my-app>
<script src="~/dist/bundle.js"></script>
</body>
</html>
main.ts
import { platformBrowserDynamic } from '#angular/platform-browser-dynamic';
import { AppModule } from './app.module';
platformBrowserDynamic().bootstrapModule(AppModule);
app.module.ts
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { FormsModule } from '#angular/forms';
import { HttpModule } from '#angular/http';
import { CollapseModule } from 'ng2-bootstrap/components/collapse';
import { routing } from './app.routing';
import { AppComponent } from './app.component';
import { PublicComponent } from './public.component';
import { ProtectedComponent } from './protected.component';
#NgModule({
imports: [ BrowserModule, FormsModule, HttpModule, routing, CollapseModule ],
declarations: [ AppComponent, PublicComponent, ProtectedComponent ],
bootstrap: [ AppComponent ]
})
export class AppModule { }
app.routing.ts
import { Routes, RouterModule } from '#angular/router';
// public
import { PublicComponent } from './public.component';
import { ProtectedComponent } from './protected.component';
const appRoutes: Routes = [
{
path: '',
component: PublicComponent,
loadChildren: 'app/public.module'
},
{
path: 'admin',
component: ProtectedComponent,
loadChildren: 'app/protected.module'
}
];
export const routing = RouterModule.forRoot(appRoutes);
This looks clearly a bug in systemjs-builder.
https://github.com/systemjs/builder/issues/728
The workaround is adding '.js' in all import statement.
e.g.
import { AppModule } from './app.module';
needs to be
import { AppModule } from './app.module.js';
It worked for me with this solution.
I've started a new project with the Angular CLI tool. After that I follow this official guide to import Underscore and I do exactly as it says.
But still my project crashes in the browser when I try to use Underscore in my app.component with the error message:
ORIGINAL EXCEPTION: ReferenceError: _ is not defined
Underscore is added to the dist/vendor folder so my guess would be that the problem is in the Systemjs configuration.
Here is my angular-cli-build:
var Angular2App = require('angular-cli/lib/broccoli/angular2-app');
module.exports = function(defaults) {
return new Angular2App(defaults, {
sassCompiler: {
includePaths: [
'src/styles'
]
},
vendorNpmFiles: [
'systemjs/dist/system-polyfills.js',
'systemjs/dist/system.src.js',
'zone.js/dist/**/*.+(js|js.map)',
'es6-shim/es6-shim.js',
'reflect-metadata/**/*.+(ts|js|js.map)',
'rxjs/**/*.+(js|js.map)',
'underscore/underscore.js',
'#angular/**/*.+(js|js.map)'
]
});
};
Here is my system-config:
"use strict";
// SystemJS configuration file, see links for more information
// https://github.com/systemjs/systemjs
// https://github.com/systemjs/systemjs/blob/master/docs/config-api.md
/***********************************************************************************************
* User Configuration.
**********************************************************************************************/
/** Map relative paths to URLs. */
const map: any = {
'underscore': 'vendor/underscore/',
};
/** User packages configuration. */
const packages: any = {
'underscore': { main: 'underscore.js', format: 'cjs' },
};
////////////////////////////////////////////////////////////////////////////////////////////////
/***********************************************************************************************
* Everything underneath this line is managed by the CLI.
**********************************************************************************************/
const barrels: string[] = [
// Angular specific barrels.
'#angular/core',
'#angular/common',
'#angular/compiler',
'#angular/forms',
'#angular/http',
'#angular/router',
'#angular/platform-browser',
'#angular/platform-browser-dynamic',
// Thirdparty barrels.
'rxjs',
// App specific barrels.
'app',
'app/shared',
/** #cli-barrel */
];
const cliSystemConfigPackages: any = {};
barrels.forEach((barrelName: string) => {
cliSystemConfigPackages[barrelName] = { main: 'index' };
});
/** Type declaration for ambient System. */
declare var System: any;
// Apply the CLI SystemJS configuration.
System.config({
map: {
'#angular': 'vendor/#angular',
'rxjs': 'vendor/rxjs',
'main': 'main.js'
},
packages: cliSystemConfigPackages
});
// Apply the user's configuration.
System.config({ map, packages });
My app.component:
/// <reference path="../../typings/globals/underscore/index.d.ts" />
import { Component } from '#angular/core';
declare var _;
#Component({
moduleId: module.id,
selector: 'app-root',
template: `<h1>{{title}}</h1>`
})
export class AppComponent {
title = _.version;
}
Where do I go wrong?
And WHY is this so complicated? Will the community accept it being this cumbersome to just add a simple third party library?
Your configuration basically sets up underscore so SystemJS can find it when needed.
When you changed system-config.ts, you told SystemJS: if anyone asks for underscore, it is a file underscore.js that can be found at the vendor/underscore/ folder -- and its module format is CommonJS (cjs).
The changes at angular-cli-build.js are for telling angular-cli what files it should pick and throw into the vendor folder. (So, if you told SystemJS it'd find underscore there, this is what makes it be there.)
But that alone does not import/add underscore into the global scope of your app.
You have to import it at each .ts file so SystemJS adds it to the transpiled .js of that module.
Instead of these two lines:
/// <reference path="../../typings/globals/underscore/index.d.ts" />
declare var _;
Add this to your file:
import * as _ from 'underscore';
If you have problems, try to inspect the generated .js source being executed at the browser. In your case, you'll probably find that there is no require() method importing the underscore.
The doco adding 3rd party lib is misleading.
I have been banging my head for over an hour!
declare var _; // this won't work.
What you need is
/// <reference path="../../../typings/globals/underscore/index.d.ts" />
import * as _ from 'underscore';
I know, this question was asked already, but I can't find the solution for my particular case I can't not understand real reason of the error.
I have an angularjs2 app which is running fine. Now I would like to import marked library.
What I did:
npm install marked
tsd install marked --save
and the tsd.json
{
"version": "v4",
"repo": "borisyankov/DefinitelyTyped",
"ref": "master",
"path": "typings",
"bundle": "typings/tsd.d.ts",
"installed": {
"marked/marked.d.ts": {
"commit": "cc3d223a946f661eff871787edeb0fcb8f0db156"
}
}
}
now trying to import "marked" into my component
import {Component} from 'angular2/core';
import * as marked from 'marked';
#Component({
selector: 'blog-component',
templateUrl: 'app/components/blog/blog.html'
})
export class BlogComponent {
private md: MarkedStatic;
constructor() {
this.md = marked.setOptions({});
}
getMarked() {
return this.md.parse("# HELLO");
}
}
This line: this.md = marked.setOptions({}); produces the error with SyntaxError: Unexpected token.. removing this line does not end with an error.. I also thing that MarkedStatic was imported correclty then. but then ist not possible to parse markdown, because it should be first initialized whith setOptions.
So I assume that importing of marked fails, or the setOptions method fails.. but I can't figure why...
and here the script part of my index.html:
<!-- 1. Load libraries -->
<script src="node_modules/angular2/bundles/angular2-polyfills.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script>
<script src="node_modules/typescript/lib/typescript.js"></script>
<script src="node_modules/rxjs/bundles/Rx.js"></script>
<script src="node_modules/angular2/bundles/angular2.dev.js"></script>
<script src="node_modules/angular2/bundles/router.dev.js"></script>
<script src="node_modules/angular2/bundles/http.dev.js"></script>
<script src="node_modules/marked/marked.min.js"></script>
<script>
System.config({
transpiler: 'typescript',
typescriptOptions: { emitDecoratorMetadata: true },
packages: {'app': {defaultExtension: 'ts'}}
});
System
.import('app/boot')
.then(null, console.error.bind(console));
</script>
You need to add this in your SystemJS configuration instead of including it into a script element:
<script>
System.config({
transpiler: 'typescript',
typescriptOptions: { emitDecoratorMetadata: true },
map: {
marked: 'node_modules/marked/marked.min.js'
},
packages: {'app': {defaultExtension: 'ts'}}
});
</script>
See this plunkr: https://plnkr.co/edit/0oSeaIyMWoq5fAKKlJLA?p=preview.
This question could be useful for you:
How to detect async change to ng-content
I am getting the following errors while running my app:
It seems to be looking for ./app.component, rather than ./app.component.js
Here is my main.ts file:
import { bootstrap } from 'angular2/platform/browser';
import { AppComponent } from './app.component';
bootstrap(AppComponent);
What have I done wrong to configure the dependencies here? NB: If I change the references to import { AppComponent } from './app.component.js';, then the error goes away and I am faced with more of the same errors for other references.
EDIT:
One of the comments has suggested that there might be an issue with my system.config(), which I think sounds very plausible, however, this is and excerpt from my index.html file, which I can't see any issues with?
...
<script>
System.config({
packages: {
app: {
format: 'register',
defaultExtension: 'js'
}
}
});
System.import('client/dev/main.js')
.then(null, console.error.bind(console));
</script>
...
Your mistake is probably that you have :
<script>
System.config({
packages: {
app: {
format: 'register',
defaultExtension: 'js'
}
}
});
System.import('client/dev/main.js')
.then(null, console.error.bind(console));
</script>
instead of
<script>
System.config({
packages: {
"client/dev": { // this line changed, here the directory where your generated `js` files are, has to be specified
format: 'register',
defaultExtension: 'js'
}
}
});
System.import('client/dev/main')
.then(null, console.error.bind(console));
</script>
I had exactly the same problem as you when I started ;)
Also the zone error should disappear if you use the newest angular beta build (12).
I want to use Angular2 along with SystemJS, in such way so I can easily switch between production and development. In development I prefer to use class per file, rather than in production I'd like to use single minimized angular2 bundle.
Currently I have the following index.html and config.js:
indexl.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<link rel="stylesheet" type="text/css" href="/node_modules/bootstrap/dist/css/bootstrap.css"/>
<script type="text/javascript" src="/node_modules/angular2/bundles/angular2-polyfills.js"></script>
<script type="text/javascript" src="/node_modules/systemjs/dist/system.js"></script>
<script type="text/javascript" src="/js/config.js"></script>
<script>
System.import('ts/main.ts').catch(console.error.bind(console));
</script>
</head>
<body>
<my-app>Loading...</my-app>
</body>
</html>
config.js:
System.config({
transpiler: 'typescript',
typescriptOptions: {
emitDecoratorMetadata: true
},
map: {
'angular2': '/node_modules/angular2',
'rxjs': '/node_modules/rxjs'
},
paths: {
'typescript': 'node_modules/typescript/lib/typescript.js',
'http': 'node_modules/angular2/bundles/http.dev.js'
},
packages: {
angular2: {
defaultExtension: 'js'
},
rxjs: { defaultExtension: 'js' },
}
});
Question:
The above code works good for development. Please suggest, how to change System.config in order to use angular2 from a single /node_modules/angular2/bundles/angular2.min.js. Adding angular2.min.js to <script ...></script> is not an option, because in this case I will not be able to switch between dev and min bundles dynamically (assume that index.html is a static page)
In fact, there is nothing to configure in SystemJs if you want to use /node_modules/angular2/bundles/angular2.min.js since modules are explicitly registered into this file using System.register.
So you can remove angular2 from the map block of your SystemJS configuration.
In development, you can use their UMD bundle, here is the systemjs config file from official guide
/**
* System configuration for Angular 2 samples
* Adjust as necessary for your application needs.
*/
(function(global) {
// map tells the System loader where to look for things
var map = {
'app': 'app', // 'dist',
'#angular': 'node_modules/#angular',
'angular2-in-memory-web-api': 'node_modules/angular2-in-memory-web-api',
'rxjs': 'node_modules/rxjs'
};
// packages tells the System loader how to load when no filename and/or no extension
var packages = {
'app': { main: 'main.js', defaultExtension: 'js' },
'rxjs': { defaultExtension: 'js' },
'angular2-in-memory-web-api': { defaultExtension: 'js' },
};
var ngPackageNames = [
'common',
'compiler',
'core',
'http',
'platform-browser',
'platform-browser-dynamic',
'router',
'router-deprecated',
'upgrade',
];
// Add package entries for angular packages
ngPackageNames.forEach(function(pkgName) {
packages['#angular/'+pkgName] = { main: pkgName + '.umd.js', defaultExtension: 'js' };
});
var config = {
map: map,
packages: packages
}
System.config(config);
})(this);
In production, you can use the same setting, but this time you use SystemJS Bundler or Webpack.
Also you must not use *.min.js anymore since it doesn't support tree-shaking optimization like rollup
For setup example, refer here