UPDATE: Since the Angular team updated ng2 from beta to RC, there were changes which break the step-by-step tutorial described in this post. I’ll update it as soon as possible.
As a single developer, creating and developing a big application such as Slidebean on your own is no easy task. In comes Angular to save the day. As the main framework for Slidebean, Angular — not without its kinks here and there — has exceptionally performed and exceeded my expectations as an application framework.
For those who don’t know, Slidebean let’s you create incredible presentations in an easier, faster, better way than with Powerpoint. Check it out at slidebean.com
That being said, Angular 2 is coming. And as much as Angular 1 was a groundbreaking framework, ng2 — as the cool kids call it — comes with big improvements (and big changes!) across the board. Alas, it’s time to move on.
The following is a guide I created after spending a lot of time finding out how to properly set up a project aimed for production which included:
- Angular2, set up with the official Yeoman generator
- SASS and Bootstrap
- Electron, for native desktop application deployment
Note: I’ll use ES6 js instead of TypeScript in this guide. Adding TypeScript should be easy enough though! If you’re into TypeScript, ES6 should feel very similar too.
Prerequisites
1) npm
Before you start, make sure you have installed node
and npm
on your system: https://docs.npmjs.com/getting-started/installing-node
2) Yeoman & Bower
Now that you have npm, install yeoman and bower using your command line or Terminal like so:
npm install -g yo npm install -g bower
We’ll need a Yeoman Angular2 generator. There are several Angular2 generators out there, though personally I prefer to use the official generator. To install it, simply enter:
npm install -g generator-angular2
3) SASS
Additionally, if you’d like to use SASS (highly recommended), install it following these instructions: http://sass-lang.com/install
Initializing the Angular2 project with Yeoman
First off, we’ll use Yeoman to create the basic file structure for us. Create a folder where you want to store the project, move into that folder and then enter:
yo
You’ll see a menu with several options:
Go ahead and choose Run a generator > Angular2
.
Yeoman will begin doing its thing, setting up the files and directories needed to run your project. After it’s done, you should have a sample but fully functional app with the following file structure:
src/
→ where all our project source files are locatedbuild/
→ where final, built files will be placednode_modules/
→ stores packages installed via npmpackage.json
→ our main npm scriptgulpfile.js
→ our Gulp script
Wanna give it a spin? Simply enter:
npm start
You should see your app come to live in your default browser via the localhost:8000 address.
“Yes! Our work here is done.” Uh, no, not quite.
A brief explanation on npm scripts and gulp tasks
You may skip this section if you’re already familiar with npm
and gulp
.
To understand what occurs when you enter npm start
, open up the package.json
file in your favorite editor, and check out the following entry:
"scripts": { "build": "gulp", "start": "gulp dev" },
Basically, npm is mapping the npm start
command with the start
entry in this setting, which in turn is calling gulp dev
underneath. What gulp dev
is doing is running the dev
task described inside the gulpfile.js
file. Open up gulpfile.js
in your editor and look for the following entry:
// run development task gulp.task('dev', ['watch', 'serve']);
So, this means the dev
task runs both the watch
and serve
tasks simultaneously. Feel free to check out what these individual tasks do in detail but, in short: serve
builds and loads the app in a web browser (serving it using a library called gulp-webserver
in the default address localhost:8000) and watch
detects any changes you make to your source files and refreshes the app (very handy during development).
We’ll need to understand how gulp works, so we can modify and create new tasks to fit our needs. With that out of the way, let’s make some changes.
Restructuring the src/ directory
Yeoman created a src/
directory with some sample files to get us started. That’s great and all but, as our application grows, having everything in one single directory is a big no no. We’ll now go ahead and create a well organized file structure.
Let’s start by creating the following directories inside src/:
- app/ → where our Angular2 files will be placed
- styles/ → contains our css/SASS files
- fonts/ → contains our font files (if any)
- images/ → contains our images
- electron/ → contains our electron stuff
We’ll focus on the app/
directory first. Delete all the sample files Yeoman created except index.html
, and then create two files under app/
named main.js
and app.js:
app/main.js
will take care of bootstraping our applicationapp/app.js
will be our first Angular2 component, which will be loaded inside main.js
Set the contents of app.js
to:
import {Component} from 'angular2/core'; @Component({ selector: 'sb-app', template: '<h1>Our app running properly now :)</h1>' }) export class Application { }
As you can see, Application
is just an empty Angular2 component which displays a simple template. We use the selector "sb-app"
, though feel free to use anything you’d like; just make sure you use this selector in your src/index.html file where you wish to load the app.
Now set the contents of main.js
to:
import {bootstrap} from 'angular2/platform/browser'; import {Application} from 'app/app'; bootstrap(Application);
This simple script kickstarts our Angular2 app by loading and bootstraping our Application component. Nothing too fancy.
Why two separate files just to do this?
Good question. Right now, it may seem like overkill to have two files just to bootstrap our app. However, as your application grows, your bootstrapping code will surely grow. By keeping main.js and app.js separated from each other, we separate concerns: main.js will strictly handle bootstrapping code and global dependency injection; app.js will handle business logic initialization stuff, such as routes and generally any other “non-plumbing” logic. For the most part, main.js will largely remain intact.
Now, let’s adjust src/index.html
to load our new app correctly:
<!doctype html> <html lang=""> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>castleblack</title> </head> <body> <sb-app></sb-app> <script src="lib/es6-shim.min.js"></script> <script src="lib/angular2-polyfills.js"></script> <script src="lib/traceur-runtime.js"></script> <script src="lib/system-csp-production.src.js"></script> <script src="lib/Reflect.js"></script> <script> System.config({defaultJSExtensions: true}); </script> <script src="lib/angular2.js"></script> <script src="lib/Rx.js"></script> <script> System.import('app/main').catch(console.log.bind(console)); </script> </body> </html>
All right! Now let’s test everything. Run these commands:
npm run build npm start
If you followed all the steps, you should see a new tab in your browser with something like this:
Customizing the Gulp script
Yeoman created our gulpfile.js
script and added several tasks to be able to run the sample project. However, there are a few things missing from the script, such as cleaning up the build directory. Plus, it’s a good idea to group similar tasks by prefixing their name, keeping things tidy. We’ll be working on the gulpfile.js script in this section.
config vars
Not a fan of having hardcoded strings all over the place, so let’s add a variable called config
, which will store the main paths we’ll use throughout our gulpfile.js
script:
var gulp = require('gulp'), rename = require('gulp-rename'), traceur = require('gulp-traceur'), webserver = require('gulp-webserver'); var config = { sourceDir: 'src', buildDir: 'build', npmDir: 'node_modules' };
clean task
We’ll add a task to delete everything on the build/
folder before our project is built. This way we avoid issues where the build/
folder has outdated or extra files which are no longer needed. We’ll need to install a new npm package called del
:
npm install --save-dev del
Let’s include del
and a new task in gulpfile.js
to empty the folder:
var gulp = require('gulp'), del = require('del'), rename = require('gulp-rename'), traceur = require('gulp-traceur'), webserver = require('gulp-webserver'); var config = { sourceDir: 'src', buildDir: 'build', npmDir: 'node_modules' }; gulp.task('clean', function() { return del(config.buildDir + '/**/*', { force: true }); });
We’ll use this new clean
task in the next section.
frontend tasks
Yeoman generated a few tasks for us, such as "dependencies"
, "js"
, "html"
, "css"
. These are all tasks related to building our Angular2 app. At some point, we’ll also have tasks related solely to building our Electron app; before we do this, let’s group all the Angular2 tasks with the prefix "frontend"
. Plus, we’ll go ahead an use the config
var we created earlier. Finally, we’ll group the development tasks as well.
var gulp = require('gulp'), del = require('del'), rename = require('gulp-rename'), traceur = require('gulp-traceur'), webserver = require('gulp-webserver'); var config = { sourceDir: 'src', buildDir: 'build', npmDir: 'node_modules' }; gulp.task('clean', function() { return del(config.buildDir + '/**/*', { force: true }); }); gulp.task('dev', [ 'dev:watch', 'dev:serve' ]); gulp.task('dev:serve', function () { gulp.src(config.buildDir) .pipe(webserver({ open: true })); }); gulp.task('dev:watch', function() { gulp.watch(config.sourceDir + '/**/*.js', ['frontend:js']); gulp.watch(config.sourceDir + '/**/*.html', ['frontend:html']); gulp.watch(config.sourceDir + '/**/*.css', ['frontend:css']); }); gulp.task('frontend', [ 'frontend:dependencies', 'frontend:js', 'frontend:html', 'frontend:css' ]); gulp.task('frontend:dependencies', function() { return gulp.src([ config.npmDir + '/traceur/bin/traceur-runtime.js', config.npmDir + '/systemjs/dist/system-csp-production.src.js', config.npmDir + '/systemjs/dist/system.js', config.npmDir + '/reflect-metadata/Reflect.js', config.npmDir + '/angular2/bundles/angular2.js', config.npmDir + '/angular2/bundles/angular2-polyfills.js', config.npmDir + '/rxjs/bundles/Rx.js', config.npmDir + '/es6-shim/es6-shim.min.js', config.npmDir + '/es6-shim/es6-shim.map' ]) .pipe(gulp.dest(config.buildDir + '/lib')); }); gulp.task('frontend:js', function() { return gulp.src(config.sourceDir + '/**/*.js') .pipe(rename({ extname: '' })) .pipe(traceur({ modules: 'instantiate', moduleName: true, annotations: true, types: true, memberVariables: true })) .pipe(rename({ extname: '.js' })) .pipe(gulp.dest(config.buildDir)); }); gulp.task('frontend:html', function () { return gulp.src(config.sourceDir + '/**/*.html') .pipe(gulp.dest(config.buildDir)) }); gulp.task('frontend:css', function () { return gulp.src(config.sourceDir + '/**/*.css') .pipe(gulp.dest(config.buildDir)) });
A lot of changes here. Do notice:
- We replaced all the
"src"
,"build"
and"node_modules"
hardcoded strings with theconfig
variable properties. - We renamed the
dependencies
,js
,html
andcss
tasks, prefixing thcode with"frontend:"
. - We added a new task simply called
"frontend"
, which calls all the other tasks.
Ok so now let’s adjust the scripts section of package.json to use our new gulp tasks:
{ "name": "sampleapp", "version": "0.0.0", "scripts": { "start": "gulp clean && gulp frontend && gulp dev", "build": "gulp clean && gulp frontend" }, "dependencies": {
Now we have two npm commands we can use:
npm start
cleans the build folder, builds the Angular app, and serves it.npm run build
cleans the build folder and builds the Angular app.
Preparing the Electron app
We’ll use Electron to package our Angular2 app as a native desktop application. Remember the src/electron
directory we created earlier? We’ll create a file in there called main.js
, which will be the main file electron will use to start the native app:
'use strict'; const electron = require('electron'); // Keep a global reference of the window object, if you don't, the window will // be closed automatically when the JavaScript object is garbage collected. var mainWindow; electron.app.on('window-all-closed', function() { if (process.platform != 'darwin') { app.quit(); } }); electron.app.on('ready', function() { mainWindow = new electron.BrowserWindow({ width: 1200, height: 750 }); mainWindow.loadURL('file://' + __dirname + '/index.html'); mainWindow.webContents.openDevTools(); mainWindow.on('closed', function() { mainWindow = null; }); });
If you’re not familiar with electron, this is the base script for running the native app. It simply:
- creates a new window
- loads
index.html
(from our Angular app, more on that below) - opens the dev tools (make sure you disable this at some point)
- quits the application when needed
We’ll also need a basic package.json
file specifically for our electron app, so let’s create one in the same directory. Most importantly, it must specify which is the main electron script (the one we just created):
{ "main": "main.js", "version": "0.0.0", "name": "sampleapp" }
All right, now with both of these files under src/electron
, we’ll adjust gulpfile.js
to add a task that copies the electron files to the build folder:
gulp.task('electron', function() { return gulp.src([ config.sourceDir + '/electron/main.js', config.sourceDir + '/electron/package.json' ]) .pipe(gulp.dest(config.buildDir)); });
So far we just have the new files and a gulp task to copy them to the build folder. Nothing fancy yet.
To actually build and run the electron app, we’ll need a few npm packages. Go ahead and install these:
npm install --save-dev gulp-atom-electron npm install --save-dev gulp-symdest
After that’s done, we’ll modify gulpfile.js
to:
- include the new npm packages
- specify a packages directory where the electron packages will be placed
- add tasks to build the electron packages
var gulp = require('gulp'), del = require('del'), rename = require('gulp-rename'), traceur = require('gulp-traceur'), webserver = require('gulp-webserver'), electron = require('gulp-atom-electron'), symdest = require('gulp-symdest'); var config = { sourceDir: 'src', buildDir: 'build', packagesDir: 'packages', npmDir: 'node_modules' }; gulp.task('clean', [ 'clean:build', 'clean:package' ]); gulp.task('clean:build', function() { return del(config.buildDir + '/**/*', { force: true }); }); gulp.task('clean:package', function() { return del(config.packagesDir + '/**/*', { force: true }); });
gulp.task('package', [ 'package:osx', 'package:linux', 'package:windows' ]); gulp.task('package:osx', function() { return gulp.src(config.buildDir + '/**/*') .pipe(electron({ version: '0.36.7', platform: 'darwin' })) .pipe(symdest(config.packagesDir + '/osx')); }); gulp.task('package:linux', function() { return gulp.src(config.buildDir + '/**/*') .pipe(electron({ version: '0.36.7', platform: 'linux' })) .pipe(symdest(config.packagesDir + '/linux')); }); gulp.task('package:windows', function() { return gulp.src(config.buildDir + '/**/*') .pipe(electron({ version: '0.36.7', platform: 'win32' })) .pipe(symdest(config.packagesDir + '/windows')); });
Finally, we’ll add new scripts in the main package.json file to make use of these new gulp tasks:
{ "name": "castleblack", "version": "0.0.0", "scripts": { "start": "gulp clean:build && gulp frontend && gulp dev", "build": "gulp clean:build && gulp frontend && gulp electron", "package": "gulp clean && gulp frontend && gulp electron && gulp package" },
I know I know, that was a lot to digest. But now, simply run npm run package
, and look for your built electron app inside the packages
directory!
- The
frontend
gulp task leaves all the Angular2 files in thebuild/
directory. - The
electron
task copiessrc/electron/main.js
andsrc/electron/package.json
to the root path ofbuild/
. This is why inmain.js
theindex.html
page is loaded from the root directory as well. - The
package
tasks grab everything that is in thebuild/
folder, and packages it.
Angular2 + Electron: Quirks and Pitfalls
So our app is not quite ready to work as an electron native app. As soon as you start importing files and using routes, you’ll run into a few issues.
<base href="/">
In order to make Angular2’s pushState routing work, we must add a <base href="/">
tag in the <head>
section of our index.html
. However, this breaks includes in Electron, and you’ll start seeing issues where files are trying to be loaded via file://
from the wrong directory. To address this, remove the <base href="/">
tag and add this setting as part of your Angular2 app’s bootstrap call.
We’ll add this to our src/app/main.js
file:
import {bootstrap} from 'angular2/platform/browser'; import {provide} from 'angular2/core' import {APP_BASE_HREF} from 'angular2/router'; import {Application} from 'app/app'; bootstrap(Application, [ provide(APP_BASE_HREF, { useValue: '/' }) ]);
This effectively sets the base href setting for the Angular app, but does not interfere with Electron’s file loading paths.
HashLocationStragegy
If you’re using Angular2’s router providers, you’ll run into an issue where routes cannot be loaded in HTML5 mode.
Say you have a main route called /dashboard
. This works flawlessly when you’re serving your Angular2 app in the web, but since Electron serves files from the file system, it looks for /dashboard as an actual directory and fails.
To fix this, simply change your Angular2 app’s location strategy to use HashLocationStrategy
. In the previous example, your /dashboard
route would become /#/dashboard
instead. But since you’re serving your app as a native desktop app and urls are not visible, this is probably not a big deal.
Again, we modify src/app/main.js
to use HashLocationStrategy
:
import {bootstrap} from 'angular2/platform/browser'; import {provide} from 'angular2/core' import {ROUTER_PROVIDERS, APP_BASE_HREF, LocationStrategy, HashLocationStrategy} from 'angular2/router'; import {Application} from 'app/app'; bootstrap(Application, [ ROUTER_PROVIDERS, provide(APP_BASE_HREF, { useValue: '/' }), provide(LocationStrategy, { useClass: HashLocationStrategy }) ]);
Sass, Bower and Bootstrap (Optional)
Bower is not entirely necessary; you can do away with just npm. However, if you wish to use it, run this command and follow the instructions:
bower init
After that’s done, you’ll have a new file in your project called bower.json
. To install dependencies, use the bower install --save <package name>
command.
We’ll go ahead and install the official SASS version of Bootstrap:
bower install --save bootstrap-sass-official
Now we have all the Bootstrap files we need under the bower_components/
folder. Just as node_modules/
contains all packages installed via npm
, bower_components/
contains everything we install via bower
.
Let’s modify gulpfile.js
to copy the Bootstrap js scripts to our build folder as well.
var config = { sourceDir: 'src', buildDir: 'build', packagesDir: 'packages', npmDir: 'node_modules', bowerDir: 'bower_components' };
gulp.task('frontend:dependencies', function() { return gulp.src([ config.npmDir + '/traceur/bin/traceur-runtime.js', config.npmDir + '/systemjs/dist/system-csp-production.src.js', config.npmDir + '/systemjs/dist/system.js', config.npmDir + '/reflect-metadata/Reflect.js', config.npmDir + '/angular2/bundles/angular2.js', config.npmDir + '/angular2/bundles/angular2-polyfills.js', config.npmDir + '/rxjs/bundles/Rx.js', config.npmDir + '/es6-shim/es6-shim.min.js', config.npmDir + '/es6-shim/es6-shim.map', config.bowerDir + '/jquery/dist/jquery.min.js', config.bowerDir + '/bootstrap-sass/assets/javascripts/bootstrap.min.js' ]) .pipe(gulp.dest(config.buildDir + '/lib')); });
And now we modify our index.html
page to include the new scripts:
<script> System.config({defaultJSExtensions: true}); </script> <script src="lib/jquery.min.js"></script> <script src="lib/bootstrap.min.js"></script> <script src="lib/angular2.js"></script> <script src="lib/Rx.js"></script>
Besides the scripts, we also need to include Bootstrap’s css files. If we were not using SASS, it would be a matter of copying the appropriate css files to the build folder, and including them in index.html
. But since we’ll be using SASS, let’s do so properly!
Let’s create our first stylesheet. Name it global.scss
and place it in the src/styles
directory:
@import "_variables"; @import "bootstrap";
What? Just two lines? Well, for now, yes. We’re first importing a file named _variables.scss
, which will contain our global SASS variables and overrides Bootstrap’s default values; and then we’re importing Bootstrap itself. Let’s go ahead and create the file _variables.scss
and place it in the same directory:
$body-bg: #CCC; $text-color: #333; $brand-primary: #9b59b6;
It’s important to keep our global variables in a separate file, since we’ll most probably be needing them in other places as our app grows.
Finally, let’s load global.scss
in index.html
. One assumption we can make is that global.scss
will become global.css
when built, so, in general, we can refer to all .scss
files as .css
.
<head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>sampleapp</title> <link rel="stylesheet" href="styles/global.css"> </head>
Aren’t we forgetting something? We haven’t set up SASS. We’ll need an npm package named gulp-sass
, so let’s install it:
npm install --save-dev gulp-sass
We’ll replace the frontend:css
task with one called frontend:sass
, which will compile our .scss
files into .css
:
var gulp = require('gulp'), del = require('del'), rename = require('gulp-rename'), traceur = require('gulp-traceur'), sass = require('gulp-sass'), webserver = require('gulp-webserver'), electron = require('gulp-atom-electron'), symdest = require('gulp-symdest');
gulp.task('frontend', [ 'frontend:dependencies', 'frontend:js', 'frontend:html', 'frontend:sass' ]);
gulp.task('frontend:sass', function () { return gulp.src(config.sourceDir + '/**/*.scss') .pipe(sass({ style: 'compressed', includePaths: [ config.sourceDir + '/styles', config.bowerDir + '/bootstrap-sass/assets/stylesheets' ] })) .pipe(gulp.dest(config.buildDir)); });
Notice we also need to pass a few directories as the includePaths
parameter for SASS. This is what makes the @import "bootstrap"
directive in global.scss
work! We also pass the src/styles
directory itself to allow imports from the same directory.
Summary
Did you follow the whole guide? Well, kudos to you, this was a lot of code! I hope by now you:
- are familiar with Yeoman, npm, bower, and gulp;
- have a basic understanding of how gulp scripts work;
- know how to set up a new Angular2 project using the official Yeoman generator;
- are able to use SASS and Bootstrap in an Angular2 project;
- are able to deploy a simple Angular2 native app with Electron!
Let me know in the comments if you have any questions or comments, or if you spotted or ran into any issues.
Happy coding ^____^
Great tut! too bad Electron doesn’t seem to support packaging for mobile targets, too.
Really great article. I have one query though if you may answer. I have routing implemented now in your sample app and it’s giving me “RangeError: Maximum call stack size exceeded” from Angular2.js. Any idea?
Hey Bhavin. I’m not sure. I’m guessing: perhaps you’re doing some forced redirection somewhere, and that is causing a redirection loop?
Hey Jose, Thank you for your reply and i would like to say i fixed that error but kinda way which i don’t like. I had to use angular2.Beta12 for that instead of latest beta 17. If i used Beta 17 and all it’s dependencies, I am getting same error again but if i use beta 12, then routing and all works fine.
As of now, I kept Beta 12 but definitely very soon, i will try to work on 17 again.
Thank you and again, wonderful article you have here!!
Really nice and complete guide. Thank you very much!! However, now that Angular 2 RC1 is live, are you gonna update it?
Thanks Ismael! I might, though I first have to check whether there are breaking changes. Let me know if you spot any 🙂
Nice guide. I think you forget to mention about adding the “dev:serve” part into gulp but thats not a big deal. Sadly, everythings was working great as I add the APP_BASE_HREF fix. From now I got this messages;
file:///E:/Documents/offx-assistant/packages/windows/resources/app/angular2/router.js Failed to load resource: net::ERR_FILE_NOT_FOUND
angular2-polyfills.js:138 Error: Unable to load script file:///E:/Documents/offx-assistant/packages/windows/resources/app/angular2/router.js(…)
Any idea how to fix that ?
You may have already figured this out or given up, but for those that come across the same issue…
You will need to add router.js to your dependencies in gulpfile.js:
config.npmDir + ‘/angular2/bundles/router.js’,
and to your index.html:
http://lib/router.js
I messed up on the html bit, but just copy one of the other script lines and replace src=”lib/whatever.js” with src=”lib/router.js”
What exactly do you have to add to the gulpfile? I am having the same problem.
Nevermind!
Just guessing, but maybe you forgot to copy the router.js dependency from the node_modules folder to your build folder, via gulp?
Good starting tutorial for me, Thanks!
As of August 23, 2016 this tutorial doesn’t seem to work, I followed the tutorial until I get to the frontend tasks step. When I add the following lines in the package.json: “start”: “gulp clean && gulp frontend && gulp dev”, “build”: “gulp clean && gulp frontend” Then type npm start. It gives me the following error: i.is.cc/yyTJiGE.jpg Please let me know what I can do to fix this error
Hey Juan. Yeah, since ng2 changed from beta to RC, there were a lot of breaking changes. I’ll update this post as soon as possible.
Thanks for the speedy answer, Jose, I solved the above issue, but I ran into another problem with your tutorial when I got to the Angular2 + Electron: Quirks and Pitfalls section. After completing all the steps in this section I got the following error from npm start:
error: Unable to load script http://localhost:8000/angular2/platform/browser.js Error loading http://localhost:8000/angular2/platform/browser.js as “angular2/platform/browser” from http://localhost:8000/app/main.js
var newErr = new Error(err.message, err.fileName, err.lineNumber);
Let me know if this is something you can solve, and can you add how to install Sass-Bootstrap4 and ng2-Bootstrap on your next revision? Thanks again!
Hey Jose, I think I almost got it to work, but now when I run npm start I get the following error on: router.js (line 2, col 1)
ReferenceError: System is not defined
System.register(“angular2/src/router/router_link_transform”,
[“angular2/compiler”, “angular2/src/core/change_detection/parser/ast”,
“angular2/src/facade/exceptions”, “angular2/core”,
“angular2/src/core/change_detection/parser/parser”], true,
function(require, exports, module) {
How do I correctly setup route.js? Note: I followed Lawg Sy advice on adding src=”lib/router.js” and config.npmDir + ‘/angular2/bundles/router.js’,but I keep getting the above error.
This is my stackoverflow thread: https://stackoverflow.com/questions/39125242/router-js-causes-a-referenceerror-system-is-not-defined Let me know if there’s any additional steps I can take to fix this issue.
I see interesting posts here. Your blog can go viral easily,
you need some initial traffic only. How to get it?
Search for: ricusso’s methods massive traffic
I have learned much here, thank you!!
Hi Jose, thanks for great how-to, but could you please mark line 7: “ROUTER_PROVIDERS” as a newly added line, please?
With the help of these comments, this guide has become very useful! I managed to get things working well BUT I still have a problem. The deployed windows app presents a popup error message when the application is closed. It starts with “ReferenceError: app is not defined at EventEmitter.” and is followed by the stack trace pointing to /packages/windows/resources/app/main.js.
Once this happens, the process doesn’t end and I have to manually terminate it in the task manager.
I’ll try to find out a solution myself but I’d appreciate some help! I’ve done some research but have had no success.
Thanks for a great guide!