SystemJS import fails silently on bundled Angular2 app - javascript

I am having trouble with SystemJS.
I have a typical Angular2 application written in Typescript.
I am trying to bundle all my application .js into a single file to optimize load time.
The bundle is created by gulp using systemjs-builder like this :
gulpfile.js
paths.compiledTs = "./wwwroot/app";
gulp.task('bundle:app', function (done) {
var builder = new Builder("/", './systemjs.config.js');
var builderConfig = {
normalize: true,
minify: true,
mangle: true,
runtime: false
};
builder.bundle(paths.compiledTs + '/main.js', paths.compiledTs + '/middleware-app.js', builderConfig)
.then(function () {
done();
})
.catch(function (err) {
console.log(err);
done();
});
});
The bundle is loaded though script tag. It works correcly as a call to System.defined in the browser console shows my modules :
System.defined
System.defined(picture)
Here is my systemjs.config.js. If I understand things correctly, an import to "app" should resolve to wwwroot/app/main.ts, then to the bundle file through the "bundles" parameter.
systemjs.config.js
/**
* System configuration
*/
(function (global) {
// map tells the System loader where to look for things
var map = {
'app': 'wwwroot/app',
'#angular': 'wwwroot/lib/#angular'
};
// 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' },
'lodash': { defaultExtension: 'js' },
'moment': { defaultExtension: 'js' },
'pikaday': { defaultExtension: 'js' },
'ng2-translate': { defaultExtension: 'js' },
};
var ngPackageNames = [
'common',
'compiler',
'core',
'forms',
'http',
'platform-browser',
'platform-browser-dynamic',
'router'
];
// Individual files (~300 requests):
function packNgIndex(pkgName) {
packages['#angular/' + pkgName] = { main: 'index.js', defaultExtension: 'js' };
}
// Bundled (~40 requests):
function packNgUmd(pkgName) {
packages['#angular/' + pkgName] = { main: 'bundles/' + pkgName + '.umd.min.js', defaultExtension: 'js' };
}
// Most environments should use UMD; some (Karma) need the individual index files
var setNgPackageConfig = System.packageWithIndex ? packNgIndex : packNgUmd;
// Add package entries for angular packages
ngPackageNames.forEach(setNgPackageConfig);
var config = {
defaultJSExtensions: true,
baseURL: global.baseUrl,
paths: {
"lodash": "wwwroot/lib/lodash.min.js",
"moment": "wwwroot/lib/moment.min.js",
"pikaday": "wwwroot/lib/pikaday.js"
},
map: map,
packages: packages,
meta: {
pikaday: {
deps: ['moment']
},
'angular2/*': {
build: false
},
'rxjs/*': {
build: false
},
'ng2-translate/*': {
build: false
}
},
bundles: {
"wwwroot/lib/bundles/rxjs.min.js": [
"rxjs/*",
"rxjs/operator/*",
"rxjs/observable/*",
"rxjs/add/operator/*",
"rxjs/add/observable/*",
"rxjs/util/*"
],
"wwwroot/lib/bundles/ng2-translate.min.js": [
"ng2-translate/*"
],
"wwwroot/app/middleware-app.js": [
"app/*",
"app/common/busy-indicator/*",
"app/common/config/*",
"app/common/date-picker/*",
"app/common/dialog/*",
"app/common/guards/*",
"app/common/interface/*",
"app/common/login/*",
"app/common/models/*",
"app/common/pagination/*",
"app/common/services/*",
"app/common/storage/*",
"app/i18n/*",
"app/layout/*",
"app/pages/authentication/*",
"app/pages/logs/*",
"app/pages/monitoring/*",
"app/pages/not-found/*",
"app/pages/referentials/*",
"app/pages/reports/*"
]
}
};
System.config(config);
})(this);
However once I attempt to import my entry point from index.html, nothing happens (meaning I don't enter my then callback or my catch block). Here is an extract of my index :
<script src="#Href("~/wwwroot/app/middleware-app.js")"></script>
<script type="text/javascript">
System.import('app')
.then(app => {
console.log("never entered");
var endpoint = '#endpointUrl';
var version = '#Html.Version()';
var production = #Html.IsProductionEnabled();
app.run(endpoint, version, production);
})
.catch(function (err) {
console.log("never entered as well");
console.error(err);
});
</script>
I have tried various things like using bundleStatic instead, importing app/main.js, changing the bundling options.
Thank you for any help you can provide.

I assume that you are quite advanced and you have good angular2 understanding.
I had similar issue with #angular/upgrade component. After serious headache, I have found out that some of the error messages are lost inside angular2 (even in currently stable package).
The possible source of error can be inside #angular/compiler. The RuntimeCompiler.compileComponents() is losing messages from CompileMetadataResolver.getNgModuleMetadata(). Simple, yet not ideal solution is to wrap call to getNgModuleMetadata in try-catch block.
Solution when you are using bundled compiler and angular 2.0.0:
compiler.umd.js:line 16799
Change this:
RuntimeCompiler.prototype._compileComponents = function (mainModule, isSync) {
var _this = this;
var templates = new Set();
var loadingPromises = [];
var ngModule = this._metadataResolver.getNgModuleMetadata(mainModule);
ngModule.transitiveModule.modules.forEach(function (localModuleMeta) {
...
to:
RuntimeCompiler.prototype._compileComponents = function (mainModule, isSync) {
var _this = this;
var templates = new Set();
var loadingPromises = [];
try {
var ngModule = this._metadataResolver.getNgModuleMetadata(mainModule);
} catch(e) {
console.log(e);
throw e;
}
ngModule.transitiveModule.modules.forEach(function (localModuleMeta) {
...
Obviously, this is not ideal solution, but I was able to find out that one of my modules had circular dependency (which was causing undefined instead of valid service inside NgModule.import).

Related

How do I include libphonenumber-js in my angular2 app using systemJS?

After installing https://github.com/halt-hammerzeit/libphonenumber-js using npm and updating my systemjs.config.ts to include
map:{
...
'libphonenumber-js': 'node_modules/libphonenumber-js'
},
packages: {
...
'libphonenumber-js': {
main: './custom.es6.js',
defaultExtension: 'js'
}
},
and attempting to use
import { parse, format, asYouType } from 'libphonenumber-js';
in my #Directive, I'm stuck with
Cannot find module 'libphonenumber-js'
How on earth am I supposed to wire this library into my app?
EDIT:
Directory layout:
websiteName
websiteName/index.html
websiteName/node_modules
websiteName/node_modules/libphonenumber-js
websiteName/app
websiteName/app/systemjs.config.ts
Index.html contains:
<script src="/app/systemjs.config.js"></script>
<script>
System.import('app').catch(function (err) { console.error(err); });
</script>
systemjs.config.ts contains:
declare var System: any;
/**
* System configuration for Angular samples
* Adjust as necessary for your application needs.
*/
(function (global) {
System.config({
paths: {
// paths serve as alias
'npm:': 'node_modules/'
},
// map tells the System loader where to look for things
map: {
// our app is within the app folder
app: 'app',
// other references
'libphonenumber-js': 'npm:libphonenumber-js'
},
// packages tells the System loader how to load when no filename and/or no extension
packages: {
app: {
main: './main.js',
defaultExtension: 'js'
},
// other references
'libphonenumber-js': {
main: './bundle/libphonenumber-js.min.js',
defaultExtension: 'js'
}
}
});
})(this);
Your package configuration is incorrect. It needs to point at the source file for libphonenumber-js. Need to update the references to match your project structure.
Try this:
(function (global) {
System.config({
paths: {
// paths serve as alias
'npm:': './node_modules'
},
// map tells the System loader where to look for things
map: {
// our app is within the app folder
app: 'app',
// other references
'libphonenumber-js': 'npm:libphonenumber-js'
},
// packages tells the System loader how to load when no filename and/or no extension
packages: {
app: {
main: './main.js',
defaultExtension: 'js'
},
// other references
'libphonenumber-js': {
main: 'libphonenumber-js.min',
defaultExtension: 'js'
}
}
});
})(this);

Running Jasmine Unit Testing with Angular 2 from CDN running SystemJS

I am looking to run Angular 2 from CDN links with SystemJS and also want to setup unit testing with Jasmine.
I have managed to get it loading the application and setup Jasmine in my code which is shown below:
/**
* based on systemjs.config.js in angular.io
* System configuration for Angular 2 samples
* Adjust as necessary for your application needs.
*/
(function(global) {
var addRouting = false;
//map tells the System loader where to look for things
var map = {
'app': 'bundles/core/src', // 'dist',
'rxjs': 'https://npmcdn.com/rxjs#' + rxJsVersion,
'angular2-in-memory-web-api': 'https://npmcdn.com/angular2-in-memory-web-api', // get latest
'ts': 'https://npmcdn.com/plugin-typescript#' + typescriptPluginVersion + '/lib/plugin.js',
'typescript': 'https://npmcdn.com/typescript#' + typescriptVersion + '/lib/typescript.js'
};
//packages tells the System loader how to load when no filename and/or no extension
var packages = {
'app': { main: 'main.ts', defaultExtension: 'ts' },
'rxjs': { defaultExtension: 'js' },
'angular2-in-memory-web-api': { defaultExtension: 'js' },
};
var packageNames = [
'#angular/common',
'#angular/compiler',
'#angular/core',
'#angular/http',
'#angular/platform-browser',
'#angular/platform-browser-dynamic',
'#angular/testing',
'#angular/upgrade',
'#angular/forms',
]
// add map entries for angular packages in the form '#angular/common': 'https://npmcdn.com/#angular/common#0.0.0-3'
packageNames.forEach(function(pkgName) {
map[pkgName] = 'https://npmcdn.com/' + pkgName + '#' + angularVersion;
});
// add package entries for angular packages in the form '#angular/common': { main: 'index.js', defaultExtension: 'js' }
packageNames.forEach(function(pkgName) {
packages[pkgName] = { main: 'index.js', defaultExtension: 'js' };
});
if ( addRouting ){
// Router API
map['#angular/router'] = 'https://npmcdn.com/#angular/router#' + angularRouterVersion;
packages['#angular/router'] = { main: 'index.js', defaultExtension: 'js' };
}
var config = {
transpiler: 'ts',
typescriptOptions: {
emitDecoratorMetadata: true,
module: "commonjs",
experimentalDecorators: true
},
meta: {
'typescript': {
"exports": "ts"
}
},
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);
This loads the Angular 2 library sucessfully and I am able to see Angular render in the page using the following markup:
<script src="{{ asset('bundles/core/js/config.js') }}"></script>
<script>
function loadTestingScripts(){
return Promise.all([
System.import('bundles/core/src/app/app.spec.ts')
]);
}
Promise.all([
System.import('app')
])
.then( loadTestingScripts() )
.then( window.onload )
.catch( console.error.bind(console) );
</script>
However when I try and run the following test code:
import { ComponentFixture, TestBed } from '#angular/core/testing/index';
import { By } from '#angular/platform-browser/index';
import { DebugElement } from '#angular/core/index';
import { AppComponent } from './app.component';
let comp: AppComponent;
let fixture: ComponentFixture<AppComponent>;
let el: DebugElement;
describe('1st tests', () => {
it('true is true', () => expect(true).toBe(true));
});
describe('AppComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [ AppComponent ], // declare the test component
});
fixture = TestBed.createComponent(AppComponent);
});
});
I receive an error 'TypeError: callback.apply is not a function' (zone.js#0.6.21:192).
However I have seen this achieved here with a beta version of the library:
http://embed.plnkr.co/vUjNLCVG8SVRYK6ZnKG0/
Is there any reason why the latest version cannot run unit testing with Angular 2 via a CDN url?
I am running Angular 2 final (2.0.0).
Below shows what I am trying to achieve:
https://embed.plnkr.co/7CCtow/
There seems to be two parts to this question, so I'll call them out and answer them individually.
Can we run jasmine unit testing with angular2 from CDN running systemjs?
Yes. I've created a plunker that seems to do what you wanted to do.
At the time of this answer, the systemjs.config.js in this plunk has been pretty hacked to help illustrate the changes, but I've copied the important parts below in case I clean it up in the future. The main changes that I needed to make to go from an older RC to the "latest" angular2 release version (2.4 at the time of writing) was to resolve the testing dependencies from the CDN for:
#angular/core/testing
#angular/platform-browser-dynamic/testing
#angular/platform-browser/testing
#angular/compiler/testing
And here's the appropriate fragment
var map = {
...
"#angular/core/testing": "https://npmcdn.com/#angular/core#2.4.0/bundles/core-testing.umd.js",
"#angular/platform-browser-dynamic/testing": "https://npmcdn.com/#angular/platform-browser-dynamic#2.4.0/bundles/platform-browser-dynamic-testing.umd.js",
"#angular/platform-browser/testing": "https://npmcdn.com/#angular/platform-browser#2.4.0/bundles/platform-browser-testing.umd.js",
"#angular/compiler/testing": "https://npmcdn.com/#angular/compiler#2.4.0/bundles/compiler-testing.umd.js",
...
};
Note: I am mapping the /testing dependencies to the umd format packages in the /bundles location. It looks like you're trying to map to the index.js inside #angular/core/testing/index which from what I can tell isn't the dependency that you're looking for, we want umd in this case.
Is there any reason why the latest version cannot run unit testing with Angular 2 via a CDN url?
Regarding the second part of your question, It seems you may be referencing the latest zone.js dependency as opposed to angular2.
No, there isn't a reason I can see. With the right configuration it works perfectly well with the version I tested:
0.6.21
0.6.23
0.6.25 which was the latest 0.6.x (at the time of writing)
I did find that there were a lot of changes and a few issues were raised in the zone.js project around this time, though many seem to be resolved by the versions we're talking about. the right configuration and order were important in my test running page where I have the fragment.
<script src="https://npmcdn.com/zone.js#0.6.25?main=browser"></script>
<script src="https://npmcdn.com/zone.js#0.6.25/dist/long-stack-trace-zone.js?main=browser"></script>
<script src="https://npmcdn.com/zone.js#0.6.25/dist/async-test.js?main=browser"></script>
<script src="https://npmcdn.com/zone.js#0.6.25/dist/fake-async-test.js?main=browser"></script>
<script src="https://npmcdn.com/zone.js#0.6.25/dist/sync-test.js?main=browser"></script>
<script src="https://npmcdn.com/zone.js#0.6.25/dist/proxy.js?main=browser"></script>
<script src="https://npmcdn.com/zone.js#0.6.25/dist/jasmine-patch.js?main=browser"></script>

Angular 2 SFX production build

I have an Angular 2 Beta 8 (cannot update now) app that I need to bundle and minify for production deployment. With the following configs I can generate a SFX bundle but a minified version of the bundle does not work. It keeps on executing something and overflows the tab. I have component in it that has a console.log in in its constructor. That keeps running like more than 1000 times before the tab crashes. But the unminified version of the bundle runs as expected which is totally weird to me.
system.config.js
System.config({
defaultJSExtensions: true,
map: {
app: 'wwwroot/app/core',
angular2: 'node_modules/angular2',
rxjs: 'node_modules/rxjs',
dragula: 'wwwroot/lib/dragula/dragula.min',
'ng2-dragula/ng2-dragula': 'wwwroot/lib/dragula/ng2-dragula',
'ng2-cookies/ng2-cookies': 'wwwroot/lib/ng2-cookies/ng2-cookies'
},
packages: {
app: {
defaultExtension: 'js',
main: 'main.js'
},
angular2: {
defaultExtension: 'js'
},
rxjs: {
defaultExtension: 'js'
}
}
});
gulpfile.js
function getBuilder(configPath) {
var builder = new SystemBuilder();
return builder.loadConfig(configPath)
.then(function () {
return builder;
});
}
gulp.task('bundle', function () {
return getBuilder('./system.config.js')
.then(function (builder) {
return builder.buildStatic('app', './bundledapp.js', { minify: true });
});
});
Any help is really appreciated.
Due to some bug in Angular 2 Beta versions a prod build was not possible

Error angular2-cookies/core.js not found in my app angular2 aspnet core

I search around 2hours where is my error.
That is the reason, I try to ask my question here.
I have this error :
"angular2-cookies/core.js not found"
I have installed angular2-cookie correctly with npm.
Here is my ServiceCookies :
import { Injectable } from '#angular/core';
import {CookieService, CookieOptionsArgs} from 'angular2-cookie/core';
#Injectable()
export class CookiesService {
private option: CookieOptionsArgs;
constructor(private cookieService: CookieService) {
}
getCookie(key: string) {
return this.cookieService.get('cookieName');
}
setCookie(key: string, value: string) {
var expiresDate = new Date(new Date().getTime() + 3600 * 1000);
this.option.expires = expiresDate.toDateString();
// 10 ans pour le moment
this.cookieService.put(key, value, this.option.expires);
}
deleteCookie(key: string) {
this.cookieService.remove(key);
}
}
Here is my system.config.js where i declare paths files for the running of my app.
/**
* System configuration for Angular 2 samples
* Adjust as necessary for your application needs.
* Override at the last minute with global.filterSystemConfig (as plunkers do)
*/
(function (global) {
// map tells the System loader where to look for things
var map = {
'app': 'app', // 'dist',
'rxjs': 'js/rxjs',
'#angular': 'js/#angular',
'angular2-in-memory-web-api': 'node_modules/angular2-in-memory-web-api',
'angular2-cookie': 'node_modules/angular2-cookies'
};
// packages tells the System loader how to load when no filename and/or no extension
var packages = {
'app': { main: 'boot.js', defaultExtension: 'js' },
'rxjs': { defaultExtension: 'js' },
'angular2-in-memory-web-api': { defaultExtension: 'js' },
'angular2-cookie': { main: 'core.js', defaultExtension: 'js' }
};
var packageNames = [
'#angular/common',
'#angular/compiler',
'#angular/core',
'#angular/http',
'#angular/platform-browser',
'#angular/platform-browser-dynamic',
'#angular/router-deprecated',
'#angular/router',
'#angular/testing',
'#angular/upgrade'
];
var paths = {
'node_modules': 'node_modules',
'app': 'app/',
'app/*': 'app/*'
};
// add package entries for angular packages in the form '#angular/common': { main: 'index.js', defaultExtension: 'js' }
packageNames.forEach(function (pkgName) {
packages[pkgName] = { main: 'index.js', defaultExtension: 'js' };
});
var config = {
map: map,
packages: packages,
paths: paths
}
if (global.filterSystemConfig) { global.filterSystemConfig(config); }
System.config(config);
})(this);
One typo I've found in your system.config.js is that is should be
'angular2-cookie': 'node_modules/angular2-cookie'
and not
'angular2-cookie': 'node_modules/angular2-cookies'
in your map{}, not sure if that will fix it completely.

Package and run Angular2 RC.0 like the previous beta aggregated module

Since I upgraded to Angular2 RC.0, all the modules are now loaded individually (600 HTTP requests on the application loading) which is very long and almost unusable. The beta17 loads all the modules at once (or at least one file for each core, http, rxjs...).
I have followed the official quickstart guide for beta and RC.
Could you tell me how to use the same mechanism as the beta or what the new mechanism is to use aggregate modules with the RC.0 ?
I have the same issue, and resolved by 'systemjs-builder'. but havn't test detailly. for you as a reference. https://github.com/A-hsien/Angular2-systemjs-builder
thx for comment from #Gaurav.
following code will package '#angular' by each folder under '#angular'.
just save them to a whateverthename.js file.
var Builder = require('systemjs-builder');
var packages = {};
var packageNames = [
'#angular/common',
'#angular/compiler',
'#angular/core',
'#angular/http',
'#angular/platform-browser',
'#angular/platform-browser-dynamic',
'#angular/router-deprecated',
'#angular/upgrade',
];
packageNames.forEach(function(pkgName) {
packages[pkgName] = { main: 'index.js' };
});
var builder = new Builder({
baseURL: '/node_modules',
defaultJSExtensions: true,
packages: packages
});
packageNames.forEach(function(pkgName) {
builder.bundle(pkgName, 'assets/'+ pkgName+'.js')
.then(function() {
console.log(pkgName+'Build complete');
})
.catch(function(err) {
console.log(pkgName+'Build error');
console.log(err);
});
});
then execute the command node whateverthename.js.
modeues will be build to assets folder.
By using the answer from #A-Hsiao and adding rxjs dependency, I have sucessfully combine all js files into one minified file. The following node script must be executed.
var Builder = require('systemjs-builder');
var packages = {
'rxjs': {main: 'Rx.js'}
};
var packageNames = [
'#angular/common',
'#angular/compiler',
'#angular/core',
'#angular/http',
'#angular/platform-browser',
'#angular/platform-browser-dynamic',
'#angular/router-deprecated',
];
packageNames.forEach(function (pkgName) {
packages[pkgName] = {main: 'index.js'};
});
packageNames.push('rxjs');
var builder = new Builder({
baseURL: '/node_modules',
defaultJSExtensions: true,
packages: packages
});
packageNames.forEach(function (pkgName) {
builder.bundle(pkgName, 'build/assets/' + pkgName + '.js')
.then(function () {
console.log(pkgName + ' Build complete');
})
.catch(function (err) {
console.log(pkgName + ' Build error');
console.log(err);
});
});
All the generated file can be combined and minified. Then the following systemjs.config.js must be imported after the bundled file.
(function (global) {
var map = {
'app': 'app'
};
var packages = {
'app': {main: 'main.js'},
'rxjs': {main: 'Rx.js'}
};
var packageNames = [
'#angular/common',
'#angular/compiler',
'#angular/core',
'#angular/http',
'#angular/platform-browser',
'#angular/platform-browser-dynamic',
'#angular/router-deprecated'
];
packageNames.forEach(function (pkgName) {
packages[pkgName] = {main: 'index.js'};
});
var config = {
map: map,
packages: packages,
defaultJSExtensions: true
};
if (global.filterSystemConfig) {
global.filterSystemConfig(config);
}
System.config(config);
})(this);

Categories