In Focus

Upgrading From AngularJS 2 Beta To RC 6

In this article, you will learn, how to upgrade from AngularJS 2 Beta to RC 6.

Introduction

In the past months, I’ve demonstrated, how to get started with Angular 2 within ASP.NET Core. The demo project was using Angular 2 Beta version because that’s the current release at that time of writing. Recently, Angular 2 Release Candidate 6 (RC 6) version was released. To align with the latest version, I think, it’s a good idea to upgrade to keep up with the most stable release and utilize Angular 2 features to their full extent.

You can find the current release change log at CHANGELOG.md

Important: The current release of Angular 2 requires at least node v4.x.x and npm 3.x.x. Verify that you are running the versions mentioned, by running node -v and npm -v in a terminal/console Window. Older versions produce errors.

Let’s Start Modifying!

Before making any file changes, make sure, you have the supported versions of Node and NPM. If you have the older versions, uninstall node, download and install the required version- Node.js

NPM is already integrated in the Node installer, so you don’t have to worry about manually upgrading it.
After the installation, make sure to restart your machine to ensure the updates will take effect. In my case, I have the versions, given below, installed-

  • Node v6.3.1 (the current release as of this writing).
  • NPM 3.10.3 (latest version as of this writing).

Keep in mind that this upgrade is also applicable, if you are using Angular 2 RC 4 versions and the versions prior to it.

Adding the typings.json File

The typings.json file might not be required for the release of RC 5 and few other versions. If there are cases, we need to support the backward compatibility and support previous RC versions and we need to create a new file to create typings containing node, jasmine and core-js typings. To do that, just right-click on your project root and then add a new .JSON file. In my case, I have selected the “NPM Config File” and just rename it as “typings.json”. Replace the default generated content with the code, given below-

  1. {  
  2.   "globalDependencies": {  
  3.     "core-js""registry:dt/core-js#0.0.0+20160602141332",  
  4.     "jasmine""registry:dt/jasmine#2.2.0+20160621224255",  
  5.     "node""registry:dt/node#6.0.0+20160621231320"  
  6.   }  
  7. }  
Note: The core-js line in the typings.json file is the only required one. Yet, we’ve also taken the chance to add the jasmine and node typings: you could need them in the near future, should you want to use the Jasmine test framework and/or use the code, which references the objects in nodejs environment. Keep them there for now, they won’t hurt your project.

Updating the package.json File

If your system is not supporting previous versions of Angular, I would really recommend you to delete the existing node_modules folder before updating the package.json file. This will ensure, we won’t be having a local copy of the previous Angular 2 bundles and modules.

Open the package.json file and replace everything in it with the code, given below-
  1. {  
  2.   "version""1.0.0",  
  3.   "name""Your Application Name",  
  4.   "author""Optional Field",  
  5.   "description""Optional Field",  
  6.   "dependencies": {  
  7.     "@angular/common""2.0.0-rc.6",  
  8.     "@angular/compiler""2.0.0-rc.6",  
  9.     "@angular/core""2.0.0-rc.6",  
  10.     "@angular/http""2.0.0-rc.6",  
  11.     "@angular/platform-browser""2.0.0-rc.6",  
  12.     "@angular/platform-browser-dynamic""2.0.0-rc.6",  
  13.     "@angular/upgrade""2.0.0-rc.6",  
  14.     "@angular/forms""2.0.0-rc.6",  
  15.     "@angular/router""3.0.0-rc.2",  
  16.   
  17.     "core-js""^2.4.1",  
  18.     "reflect-metadata""^0.1.3",  
  19.     "rxjs""5.0.0-beta.6",  
  20.     "systemjs""^0.19.37",  
  21.     "typings""^1.3.2",  
  22.     "zone.js""^0.6.12",  
  23.     "moment""^2.14.1"  
  24.   },  
  25.   
  26.   "devDependencies": {  
  27.     "gulp""^3.9.1",  
  28.     "gulp-clean""^0.3.2",  
  29.     "gulp-concat""^2.6.0",  
  30.     "gulp-less""^3.1.0",  
  31.     "gulp-sourcemaps""^1.6.0",  
  32.     "gulp-typescript""^2.13.6",  
  33.     "gulp-uglify""^2.0.0",  
  34.     "typescript""^1.8.10"  
  35.   },  
  36.   "scripts": {  
  37.     "postinstall""typings install dt~core-js --global"  
  38.   }  
  39. }  
The packages with the @ symbol is a part of the new Angular 2 bundle: the other ones are loading libraries, helper tools and polyfills for the older Browser support. The current version of Angular 2 as of this writing is 2.0.0-rc.6. You can check for the updates. You may also have noticed, we’ve replaced the dependencies to Grunt with Gulp. I’ll explain it later in this article. You may remove the existing gruntfile.js file, similar to, what I did. Prefer using Grunt. No one is going to fire you for using Grunt.

If you have noticed, we’ve added the scripts section to install the typings. Typings manages and installs the TypeScript definitions.

Now, save the file to restore the required packages for our Application. Once installed, you should be able to see something like-

packages

Tip: If Typings didn’t install successfully on Save, try to use the “Restore Package” option by right-clicking on the Dependencies node. Another way is to use the command line to run typings explicitly. To do that, just navigate to the root folder of your app and do a CTRL+SHIFT and select “Open command window here”. In the command line, type the command, given below-

npm run typings install

If successful, you should be able to see something like-

cmd

As a recap, all Angular 2 dependencies will be installed in the location, given below, in your local drive-

../src/<YourProjectName>/node_modules

Updating the tsconfig.json File

Now, open your tsconfig.json file. If you do not have it, you need to create one. Here’s the updated TypeScript JSON Configuration file, given below-
  1. {  
  2.   "compileOnSave"false,  
  3.   "compilerOptions": {  
  4.     "emitDecoratorMetadata"true,  
  5.     "experimentalDecorators"true,  
  6.     "module""system",  
  7.     "moduleResolution""node",  
  8.     "noImplicitAny"false,  
  9.     "noEmitOnError"false,  
  10.     "removeComments"false,  
  11.     "target""es5"  
  12.   },  
  13.   "exclude": [  
  14.     "node_modules",  
  15.     "wwwroot"  
  16.   ]  
  17.   
  18. }  
The compileOnSave signals the IDE to generate all the files for a given tsconfig.json. On saving. compilerOptions, the configuration will influence, how the Intellisense and our external TypeScript compiler will work. By excluding the folders in the config, we tell the built-in TypeScript compiler is provided by Visual Studio 2015 to disable compiling the external TypeScript files within that location.

Updating the AppComponent File

Since we are upgrading to RC version, we also need to update the component, which has references to the previous beta version of Angular.

The coding for app.component.ts is given below-
  1. import {Component} from "@angular/core";  
  2.   
  3. @Component({  
  4.     selector: 'angularjs2demo',  
  5.     template: `<h1>AngularJS 2 Demo</h1><div>Hello ASP.NET Core! Greetings from AngularJS 2.</div>`  
  6. })  
  7.   
  8. export class AppComponent { }   
There’s not much to say about the update, given above. We just changed the import reference to the new name, which is @angular/core.

The Angular 2 Module File

Angular Modules, also known as NgModules, have been introduced, since Angular2 RC5. This provides a powerful way to organize and bootstrap any Angular2 Application as it helps the developers to consolidate their own set of components, directives and pipes into the reusable blocks.

Every Angular2 Application, since RC5 must have at least one module, which is conventionally called root module and is given the AppModule class name.

Now, create a new TypeScript file and name the file as “app.module.ts”. If you followed my previous article, you may create the file under Scripts/app folder. Here’s, how the app.module.ts file should look like-
  1. ///<reference path="../../typings/index.d.ts"/>  
  2. import {NgModule} from "@angular/core";  
  3. import {BrowserModule} from "@angular/platform-browser";  
  4. import {HttpModule} from "@angular/http";  
  5. import "rxjs/Rx";  
  6.   
  7. import {AppComponent} from "./app.component";  
  8.   
  9. @NgModule({  
  10.     // directives, components, and pipes  
  11.     declarations: [  
  12.         AppComponent  
  13.     ],  
  14.     // modules  
  15.     imports: [  
  16.         BrowserModule,  
  17.         HttpModule  
  18.     ],  
  19.     // providers  
  20.     providers: [  
  21.     ],  
  22.     bootstrap: [  
  23.         AppComponent  
  24.     ]  
  25. })  
  26. export class AppModule { }  
The first line from the config, given above, adds a reference to the type definitions to ensure our TypeScript compiler will find it. Note, in case, we’re using a CDN or a pre-compiled version of Angular2, we can (and should) definitely remove this line. We then import the basic Angular2 modules, which we will need for our app. You can add more Angular 2 module reference in this file, when required. We also have imported the rxjs library definition file(s), which will be useful to compile some Angular2 libraries. We then imported our component "AppComponent". Finally, we have declared our root NgModule, as we can see it consists in an array of named arrays, each one containing a set of Angular2 objects, which serves a common purpose- directives, components, pipes, modules and providers. The last one of them contains the component(s), we want to bootstrap, which in our case is the AppComponent one.

For more information about App Module, see here,

Updating the Boot File

Open boot.ts file and replace the existing code with the code, given below-
  1. import {platformBrowserDynamic} from "@angular/platform-browser-dynamic";  
  2. import {AppModule} from "./app.module";  
  3.   
  4. platformBrowserDynamic().bootstrapModule(AppModule);  
Just like in the app.component.ts file, we changed the reference to the new Angular bundle. Notice, we have referenced the new AppModule, which we have created previously. Now, we’re just missing an entry point to load with the Browser. Thus, let’s add it right now.

Adding the SystemJS File

Now, let’s add the systemjs configuration file. Right-click on wwwroot folder and select Add > New Item. Under Client-side templates, select “JavaScript File”, as given below-

Adding the SystemJS File

Name the file as “systemjs.config.js” and then copy the code, given below-
  1. (function (global) {  
  2.     System.config({  
  3.         paths: {  
  4.             // paths serve as alias  
  5.             'npm:''js/'  
  6.         },  
  7.         // map tells the System loader where to look for things  
  8.         map: {  
  9.             // our app is within the app folder  
  10.             app: 'app',  
  11.   
  12.             // angular bundles  
  13.             '@angular/core''npm:@angular/core/bundles/core.umd.js',  
  14.             '@angular/common''npm:@angular/common/bundles/common.umd.js',  
  15.             '@angular/compiler''npm:@angular/compiler/bundles/compiler.umd.js',  
  16.             '@angular/platform-browser''npm:@angular/platform-browser/bundles/platform-browser.umd.js',  
  17.             '@angular/platform-browser-dynamic''npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',  
  18.             '@angular/http''npm:@angular/http/bundles/http.umd.js',  
  19.             '@angular/router''npm:@angular/router/bundles/router.umd.js',  
  20.             '@angular/forms''npm:@angular/forms/bundles/forms.umd.js',  
  21.   
  22.             // angular testing umd bundles  
  23.             '@angular/core/testing''npm:@angular/core/bundles/core-testing.umd.js',  
  24.             '@angular/common/testing''npm:@angular/common/bundles/common-testing.umd.js',  
  25.             '@angular/compiler/testing''npm:@angular/compiler/bundles/compiler-testing.umd.js',  
  26.             '@angular/platform-browser/testing''npm:@angular/platform-browser/bundles/platform-browser-testing.umd.js',  
  27.             '@angular/platform-browser-dynamic/testing''npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic-testing.umd.js',  
  28.             '@angular/http/testing''npm:@angular/http/bundles/http-testing.umd.js',  
  29.             '@angular/router/testing''npm:@angular/router/bundles/router-testing.umd.js',  
  30.             '@angular/forms/testing''npm:@angular/forms/bundles/forms-testing.umd.js',  
  31.   
  32.             // other libraries  
  33.             'rxjs''npm:rxjs',  
  34.             'angular2-in-memory-web-api''npm:angular2-in-memory-web-api',  
  35.         },  
  36.         // packages tells the System loader how to load when no filename and/or no extension  
  37.         packages: {  
  38.             app: {  
  39.                 main: './boot.js',  
  40.                 defaultExtension: 'js'  
  41.             },  
  42.             rxjs: {  
  43.                 defaultExtension: 'js'  
  44.             },  
  45.             'angular2-in-memory-web-api': {  
  46.                 defaultExtension: 'js'  
  47.             }  
  48.         }  
  49.     });  
  50. })(this);  
The SystemJS.config file will load the Application and library modules. We are going to need this loader to build our Angular 2 app. For more details about SystemJS config, read on: SystemJS.

If you want to use WebPack as your module bundler, see Introduction to WebPack

Updating the index.html

Now, we need the SystemJS config to load our app modules and components. We also need to update our index.html to include the new configuration. Replace your index.html file, so it will look something like-
  1. <html>  
  2. <head>  
  3.     <base href="/">  
  4.     <title>ASP.NET Core with Angular 2 RC Demo</title>  
  5.     <meta name="viewport" content="width=device-width, initial-scale=1">  
  6.   
  7.     <!-- Step 1. Load libraries -->  
  8.     <!-- Polyfill(s) for older browsers -->  
  9.     <script src="js/shim.min.js"></script>  
  10.     <script src="js/zone.js"></script>  
  11.     <script src="js/Reflect.js"></script>  
  12.     <script src="js/system.src.js"></script>  
  13.   
  14.     <!-- Angular2 Native Directives -->  
  15.     <script src="/js/moment.js"></script>  
  16.   
  17.     <!-- Step 2. Configure SystemJS -->  
  18.     <script src="systemjs.config.js"></script>  
  19.     <script>  
  20.       System.import('app').catch(function(err){ console.error(err); });  
  21.     </script>  
  22. </head>  
  23. <!-- Step 3. Display the application -->  
  24. <body>  
  25.     <!-- Application PlaceHolder -->  
  26.     <angularjs2demo>Please wait...</angularjs2demo>  
  27. </body>  
  28. </html>  
Switching to Gulp

This time, we will be using Gulp as the JavaScript Task Runner to automate our client-side scripts. I’d like to note that switching to Gulp does not mean Grunt is a bad tool. Of course, Grunt is still a great tool and used by many. If you prefer, you can always use it to automate the tasks for you. I just preferred to use Gulp because of its conciseness and easy task writing. It also uses node.js’ streams and executes faster, since it does not open/close files or creates intermediary copies all the time. Again, every developer has a preference, so it’s all up to you, which JS task runners, you would use.

Now, let’s add a new file for our Gulp configuration. Go ahead, right click on the project solution and then select Add > New Item. Under Client-side template, select “Gulp Configuration File”, as shown in the figure, given below-

Gulp

Click Add to generate the file, replace the default generated configuration with the code, given below-
  1. var gulp = require('gulp'),  
  2.     gp_clean = require('gulp-clean'),  
  3.     gp_concat = require('gulp-concat'),  
  4.     gp_less = require('gulp-less'),  
  5.     gp_sourcemaps = require('gulp-sourcemaps'),  
  6.     gp_typescript = require('gulp-typescript'),  
  7.     gp_uglify = require('gulp-uglify');  
  8.   
  9. /// Define paths  
  10. var srcPaths = {  
  11.     app: ['Scripts/app/main.ts''Scripts/app/**/*.ts'],  
  12.     js: [  
  13.         'Scripts/js/**/*.js',  
  14.         'node_modules/core-js/client/shim.min.js',  
  15.         'node_modules/zone.js/dist/zone.js',  
  16.         'node_modules/reflect-metadata/Reflect.js',  
  17.         'node_modules/systemjs/dist/system.src.js',  
  18.         'node_modules/typescript/lib/typescript.js',  
  19.         'node_modules/ng2-bootstrap/bundles/ng2-bootstrap.min.js',  
  20.         'node_modules/moment/moment.js'  
  21.     ],  
  22.     js_angular: [  
  23.         'node_modules/@angular/**'  
  24.     ],  
  25.     js_rxjs: [  
  26.         'node_modules/rxjs/**'  
  27.     ]  
  28. };  
  29.   
  30. var destPaths = {  
  31.     app: 'wwwroot/app/',  
  32.     js: 'wwwroot/js/',  
  33.     js_angular: 'wwwroot/js/@angular/',  
  34.     js_rxjs: 'wwwroot/js/rxjs/'  
  35. };  
  36.   
  37. // Compile, minify and create sourcemaps all TypeScript files   
  38. // and place them to wwwroot/app, together with their js.map files.  
  39. gulp.task('app', ['app_clean'], function () {  
  40.     return gulp.src(srcPaths.app)  
  41.         .pipe(gp_sourcemaps.init())  
  42.         .pipe(gp_typescript(require('./tsconfig.json').compilerOptions))  
  43.         .pipe(gp_uglify({ mangle: false }))  
  44.         .pipe(gp_sourcemaps.write('/'))  
  45.         .pipe(gulp.dest(destPaths.app));  
  46. });  
  47.   
  48. // Delete wwwroot/app contents  
  49. gulp.task('app_clean'function () {  
  50.     return gulp.src(destPaths.app + "*", { read: false })  
  51.     .pipe(gp_clean({ force: true }));  
  52. });  
  53.   
  54. // Copy all JS files from external libraries to wwwroot/js  
  55. gulp.task('js'function () {  
  56.     gulp.src(srcPaths.js_angular)  
  57.         .pipe(gulp.dest(destPaths.js_angular));  
  58.     gulp.src(srcPaths.js_rxjs)  
  59.         .pipe(gulp.dest(destPaths.js_rxjs));  
  60.     return gulp.src(srcPaths.js)  
  61.         .pipe(gulp.dest(destPaths.js));  
  62. });  
The code, given above, contains three (3) main variables, which are-
  • gulp - It initializes each Gulp plugins, which we are going to require to run the tasks.
  • srcPaths - It holds an array of sources, which we want to copy and transpile.
  • destPaths - It holds an array of specific location within wwwroot. This is basically where we dump the scripts we defined from the srcPaths. It also contains five (5) main tasks.

    • app_clean - This task deletes the existing files from the destination folders, we defined.
    • app - This task compiles, uglify and create sourcemaps for all TypeScript files and place them to wwwroot/app folder, together with their js.map files.
    • js - This task will copy all JavaScript files from external libraries, which are located within the node_modules folder and place them to wwwroot/js folder.
    • watch - This task watches files defined in an app and js tasks, which are changed.
    • default - It defines the default task so it will launch all other tasks

Testing the App

Clean and Build your solution. Make sure, it has no errors. If it builds successfully, right click on the gulpfile.js and select “Task Runner Explorer”.

Make sure to click "Refresh" button to load the task, as shown in the figure, given below-

Refresh

Now, right-click to the default task and hit Run. You should be able to see something like this, when successful-

commnad

After successfully running the Task Runner, you should also see that the “app” and “js” folders are generated within your “wwwroot” folder, as shown in the figure, given below-

folder

Running the Application should result to something like-

application

That’s it! I hope, you find this post useful.