How to setup an Angular 2 and TypeScript project with Visual Studio 2017

You can see the source code of this tutorial on my GitHub repository, here : Angular2 web app source code on GitHub.

Versions :

Create new ASP.NET Core web application

How to setup an Angular 2 and TypeScript project with Visual Studio 2017

How to setup an Angular 2 and TypeScript project with Visual Studio 2017
How to setup an Angular 2 and TypeScript project with Visual Studio 2017

Create the MVC folders structure

What is MVC ?

MVC, for Model-View-Controller is an architectural pattern who separates an application into three main components :

The purpose of this architectural pattern is to build applications that are easily maintenable and testable, separating differents components. A best practice is to pair this architectural pattern with an N-Tier layers architecture.

How to setup an Angular 2 and TypeScript project with Visual Studio 2017

Create a folder where put the TypeScript files

How to setup an Angular 2 and TypeScript project with Visual Studio 2017

Set TypeScript configuration

If TypeScript is the primary language for Angular application development, it can't be executed by the browsers directly; TypeScript must be "transpiled" into JavaScript using the tsc compiler, which requires some configuration.

To configure the TypeScript compiler and set your environment, you have two files to add :

tsconfig.json

The TypeScript configuration file is required to guide the TypeScript compiler as it generates JavaScript files which are used by the browser.

How to setup an Angular 2 and TypeScript project with Visual Studio 2017

This is the default content when you add the tsconfig.json file to your project :


{
  "compilerOptions": {
    "noImplicitAny": false,
    "noEmitOnError": true,
    "removeComments": false,
    "sourceMap": true,
    "target": "es5"
  },
  "exclude": [
    "node_modules",
    "wwwroot"
  ]
}

So, what do we have in this file ?

The compilerOptions section is optional, if its null default values will be use. You can find the details of this section here : http://www.typescriptlang.org/docs/handbook/compiler-options.html

If you want more information about this file, you can read the documentation : http://www.typescriptlang.org/docs/handbook/tsconfig-json.html

For our project, we have to specify where the tsc can find our TypeScript files and where we want it generates the JavaScript files, and some other settings. This is the content we need :


{
  "compilerOptions": {
    "target": "es6",
    "module": "commonjs",
    "moduleResolution": "node",
    "sourceMap": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "removeComments": true,
    "suppressImplicitAnyIndexErrors": true,
    "rootDir": "App",
    "outDir": "wwwroot/app"
  },
  "compileOnSave": true,
  "angularCompilerOptions": {
    "genDir": ".",
    "debug": true
  },
  "exclude": [
    "node_modules",
    "wwwroot"
  ]
}

TypeScript type definition files

Many JavaScript libraries, such as jQuery, extend the JavaScript environment with syntax and features that the TypeScript compiler doesn't recognize natively. This file tell the compiler about the libraries you load.


{
  "globalDependencies": {
    "jquery": "registry:dt/jquery",
    "jasmine": "registry:dt/jasmine"
  }
}

Add a NPM configuration file

What is NPM ?

NPM, for Node Package Manager, is a utility that aids JavaScript open source package installation, version and dependency management. NPM is distributed with Node.js, which is an asynchronous event driven JavaScript runtime, designed to build scalable network applications.

Angular 2 and its dependencies are delivered through NPM, so you need to add the NPM configuration file in your project, package.json.

How to setup an Angular 2 and TypeScript project with Visual Studio 2017

You will have an empty NPM configuration file :


{
  "version": "1.0.0",
  "name": "asp.net",
  "private": true,
  "devDependencies": {
  }
}

To add Angular 2 and its dependencies to your projects, you have to add some dependencies in your NPM configuration file :


{
  "version": "1.0.0",
  "description": "NO404 administration panel",
  "name": "no404 backoffice",
  "readme": "no404 backoffice",
  "license": "MIT",
  "dependencies": {
    "@angular/common": "~2.2.0",
    "@angular/compiler": "~2.2.0",
    "@angular/core": "~2.2.0",
    "@angular/forms": "~2.2.0",
    "@angular/http": "~2.2.0",
    "@angular/platform-browser": "~2.2.0",
    "@angular/platform-browser-dynamic": "~2.2.0",
    "@angular/router": "~3.2.0",
    "@angular/upgrade": "~2.2.0",

    "angular-in-memory-web-api": "~0.1.15",
    "core-js": "^2.4.1",
    "reflect-metadata": "^0.1.8",
    "rxjs": "5.0.0-beta.12",
    "systemjs": "0.19.39",
    "zone.js": "^0.6.25",

    "bower": "1.7.9",
    "jquery": "^3.1.0"
  },
  "devDependencies": {
    "@types/core-js": "^0.9.34",
    "@types/node": "^6.0.45",
    "concurrently": "^2.2.0",
    "gulp": ">=3.9.1",
    "gulp-concat": ">=2.5.2",
    "gulp-copy": ">=0.0.2",
    "gulp-cssmin": ">=0.1.7",
    "gulp-load-plugins": "^1.3.0",
    "gulp-rename": ">=1.2.2",
    "gulp-rimraf": ">=0.2.0",
    "gulp-tsc": ">=1.2.0",
    "gulp-uglify": ">=1.2.0",
    "gulp-watch": ">=4.3.9",
    "gulp-clean-css": "^3.0.4",
    "gulp-clean": "^0.3.2",
    "jasmine-core": "2.4.1",
    "tslint": "^3.15.1",
    "typescript": "^2.0.0",
    "typings": "^1.3.2"
  },
  "scripts": {
    "start": "concurrently \"npm run gulp\" \"npm run watch\" \"npm run tsc:w\"",
    "postinstall": "typings install",
    "tsc": "tsc",
    "tsc:w": "tsc -w",
    "typings": "typings",
    "gulp": "gulp",
    "watch": "gulp watch",
    "ngc": "ngc"
  }
}

If you open your web application in the folder explorer, you can now see a node_modules folder with some external dependencies in there :

How to setup an Angular 2 and TypeScript project with Visual Studio 2017

Add Gulp

Add gulp.config.js


module.exports = function () {

    var base = {
        webroot: "./wwwroot/",
        node_modules: "./node_modules/"
    };

    var config = {
        /**
         * Files paths
         */
        angular: base.node_modules + "@angular/**/*.js",
        app: "App/**/*.*",
        appDest: base.webroot + "app",
        js: base.webroot + "js/*.js",
        jsDest: base.webroot + 'js',
        css: base.webroot + "css/*.css",
        cssDest: base.webroot + 'css',
        lib: base.webroot + "lib/",
        node_modules: base.node_modules,
        angularWebApi: base.node_modules + "angular2-in-memory-web-api/*.js",
        corejs: base.node_modules + "core-js/client/shim*.js",
        zonejs: base.node_modules + "zone.js/dist/zone*.js",
        reflectjs: base.node_modules + "reflect-metadata/Reflect*.js",
        systemjs: base.node_modules + "systemjs/dist/*.js",
        rxjs: base.node_modules + "rxjs/**/*.js",
        jasminejs: base.node_modules + "jasmine-core/lib/jasmine-core/*.*"
    };

    return config;
};

Add the gulp configuration file

How to setup an Angular 2 and TypeScript project with Visual Studio 2017

/*
This file is the main entry point for defining Gulp tasks and using Gulp plugins.
Click here to learn more. https://go.microsoft.com/fwlink/?LinkId=518007
*/

var gulp = require('gulp');

gulp.task('default', function () {
    // place code for your default task here
});

/// 
"use strict";

var gulp = require('gulp');
var config = require('./gulp.config')();
var cleanCSS = require('gulp-clean-css');
var clean = require('gulp-clean');
var rename = require('gulp-rename');
var $ = require('gulp-load-plugins')({ lazy: true });

gulp.task("clean:js", function (cb) {
    //return $.rimraf('wwwroot/js/*.min.js', cb);
    return gulp.src('wwwroot/js/*.min.js', { read: false }).pipe(clean());
});

gulp.task("clean:css", function (cb) {
    //return $.rimraf('wwwroot/css/*.min.css', cb);
    return gulp.src('wwwroot/css/*.min.css', { read: false }).pipe(clean());
});

gulp.task('minify:css', function () {
    return gulp.src(config.css)
        .pipe(cleanCSS())
        .pipe(rename({
            suffix: '.min'
        }))
        .pipe(gulp.dest(config.cssDest));
});

gulp.task("clean", ["clean:js", "clean:css"]);
gulp.task('minify', ['minify:css']);

gulp.task("copy:angular", function () {

    return gulp.src(config.angular,
        { base: config.node_modules + "@angular/" })
        .pipe(gulp.dest(config.lib + "@angular/"));
});

gulp.task("copy:angularWebApi", function () {
    return gulp.src(config.angularWebApi,
        { base: config.node_modules })
        .pipe(gulp.dest(config.lib));
});

gulp.task("copy:corejs", function () {
    return gulp.src(config.corejs,
        { base: config.node_modules })
        .pipe(gulp.dest(config.lib));
});

gulp.task("copy:zonejs", function () {
    return gulp.src(config.zonejs,
        { base: config.node_modules })
        .pipe(gulp.dest(config.lib));
});

gulp.task("copy:reflectjs", function () {
    return gulp.src(config.reflectjs,
        { base: config.node_modules })
        .pipe(gulp.dest(config.lib));
});

gulp.task("copy:systemjs", function () {
    return gulp.src(config.systemjs,
        { base: config.node_modules })
        .pipe(gulp.dest(config.lib));
});

gulp.task("copy:rxjs", function () {
    return gulp.src(config.rxjs,
        { base: config.node_modules })
        .pipe(gulp.dest(config.lib));
});

gulp.task("copy:app", function () {
    return gulp.src(config.app)
        .pipe(gulp.dest(config.appDest));
});

gulp.task("copy:jasmine", function () {
    return gulp.src(config.jasminejs,
        { base: config.node_modules + "jasmine-core/lib" })
        .pipe(gulp.dest(config.lib));
});

gulp.task("dependencies", [
    "copy:angular",
    "copy:angularWebApi",
    "copy:corejs",
    "copy:zonejs",
    "copy:reflectjs",
    "copy:systemjs",
    "copy:rxjs",
    "copy:jasmine",
    "copy:app"
]);

gulp.task("watch", function () {
    return $.watch(config.app)
        .pipe(gulp.dest(config.appDest));
});

gulp.task("default", ["clean", 'minify', "dependencies"]);

You can see now a task "default" in the task explorator

How to setup an Angular 2 and TypeScript project with Visual Studio 2017
How to setup an Angular 2 and TypeScript project with Visual Studio 2017

You can see that the dependencies has been added in the lib folder.

How to setup an Angular 2 and TypeScript project with Visual Studio 2017

Add Bower

Add bower to add jquery and boostrap dependencies

How to setup an Angular 2 and TypeScript project with Visual Studio 2017

Create TypeScript app files

Create the main file to bootstrap your application


import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';

const platform = platformBrowserDynamic();

platform.bootstrapModule(AppModule);

Add app.module.ts


import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpModule } from '@angular/http';

import { AppComponent } from './app.component';
import { HomeComponent } from './home/home.component';
import { AppRoutingModule } from './app-routing.module';

@NgModule({
    imports: [
        BrowserModule,
        HttpModule,
        AppRoutingModule
    ],
    declarations: [
        AppComponent,
        HomeComponent
    ],
    bootstrap: [AppComponent],
    providers: [
    ]
})
export class AppModule { }

Add app.component.ts


import { Component, OnInit } from '@angular/core';

@Component({
    selector: 'no404-bo-app',
    template: `
        <div class="container">
            <nav>
                <a routerLink="home" routerLinkActive="active">Home</a>
            </nav>
            <router-outlet></router-outlet>
        </div>
    `,
    providers: []
})
export class AppComponent implements OnInit {

    constructor() {
        console.log('AppComponent -> constructor');
    }

    ngOnInit() {
        console.log('AppComponent -> ngOnInit');
    }
}

Create the routing module (app-routing.module.ts)


import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { HomeComponent } from './home/home.component';

export const routes: Routes = [
    { path: '', redirectTo: 'home', pathMatch: 'full' },
    { path: 'home', component: HomeComponent }
];

@NgModule({
    imports: [RouterModule.forRoot(routes)],
    exports: [RouterModule]
})
export class AppRoutingModule { }

And add the home component


import { Component, OnInit } from '@angular/core';

@Component({
    selector: 'home',
    template: `
        <h1>Home</h1>
        <p>Hello you !</p>
    `
})
export class HomeComponent implements OnInit {
    
    constructor() {
        console.log('HomeComponent -> constructor');

    }

    ngOnInit() {
        console.log('HomeComponent -> ngOnInit');
        
    }
}
How to setup an Angular 2 and TypeScript project with Visual Studio 2017

If you build your solution, you can see that your outpout app folder has been populated with some javascript files generated by your TypeScript files.

How to setup an Angular 2 and TypeScript project with Visual Studio 2017

If you launch your website, you will have something like this :

How to setup an Angular 2 and TypeScript project with Visual Studio 2017

No trace in the console and not the content in our typescript templates. Why ? Cause we have to tell our website startup that we want to load our typescript application.

Configure your web app to dispay your angular application

Check if your application is targeting the .NETCoreApp framework, version 1.1, if not update it.

How to setup an Angular 2 and TypeScript project with Visual Studio 2017

Check if the Nuget dependencies are targeting the last version, if not update them all.

How to setup an Angular 2 and TypeScript project with Visual Studio 2017

Add the Nuget dependencies you need :

Microsoft.AspNetCore.StaticFiles is a middleware for handling requests for file system resources including files and directories that enable your application to serve HTML and javascript files, indispensable elements of an Angular application.

For more information about Microsoft.AspNetCore.StaticFiles, you can see :

How to setup an Angular 2 and TypeScript project with Visual Studio 2017

Once you have added the Microsoft.AspNetCore.StaticFiles package, you have to enable your app to serve static files. It occurs in the Configure method in the startup class, using app.UseStaticFiles():.


public void ConfigureServices(IServiceCollection services)
{
    services
               .AddMvc()
               .AddJsonOptions(options => options.SerializerSettings.ContractResolver =
                   new DefaultContractResolver());
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    loggerFactory.AddConsole(Configuration.GetSection("Logging"));
    loggerFactory.AddDebug();

    app.UseCors(
        builder => builder.AllowAnyOrigin()
            .AllowAnyHeader()
            .AllowAnyMethod()
            .AllowCredentials())
        .UseStaticFiles();

    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");
    });
}

Add the Home controller with the view

Add HomeController and Index.cshtml in the home folder of the Views.

Add systemjs.config.js javascript file in your js folder of the wwwroot folder.


(function (global) {
    System.config({
        paths: {
            'npm:': 'lib/'
        },
        map: {
            app: 'app',
            '@angular/core': 'npm:@angular/core/bundles/core.umd.js',
            '@angular/common': 'npm:@angular/common/bundles/common.umd.js',
            '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',
            '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js',
            '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
            '@angular/http': 'npm:@angular/http/bundles/http.umd.js',
            '@angular/router': 'npm:@angular/router/bundles/router.umd.js',
            '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',
            'rxjs': 'npm:rxjs',
            'angular-in-memory-web-api': 'npm:angular-in-memory-web-api/bundles/in-memory-web-api.umd.js'
        },
        packages: {
            app: {
                main: './main.js',
                defaultExtension: 'js'
            },
            rxjs: {
                defaultExtension: 'js'
            },
            'angular2-in-memory-web-api': {
                main: './index.js',
                defaultExtension: 'js'
            }
        }
    });
})(this);

Set up the content of your Index.cshtml view to load the ui dependencies your need, and load your Angular application.


<!DOCTYPE html>
<html>
<head>
    <base href="/">
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />

    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
    <link rel="stylesheet" href="~/css/site.css" />

    <script src="~/lib/jquery/dist/jquery.js"></script>
    <script src="~/lib/bootstrap/dist/js/bootstrap.js"></script>

    <script src="~/lib/core-js/client/shim.js"></script>
    <script src="~/lib/zone.js/dist/zone.js"></script>
    <script src="~/lib/reflect-metadata/Reflect.js"></script>
    <script src="~/lib/systemjs/dist/system.src.js"></script>

    <script src="~/js/systemjs.config.js"></script>
    <script>
      System.import('app').catch(function(err){ console.error(err); });
    </script>
</head>
<body>
    <div class="container">
        <no404-bo-app>Loading...</no404-bo-app>
    </div>
</body>
</html>

And it's work !

If you launch your application now, you can see that all is working and your Angular 2 application is correctly loaded.

How to setup an Angular 2 and TypeScript project with Visual Studio 2017

You can now implement your Angular 2 application to do what you have to do. Enjoy :)




PS: If you see a strange C folder appearing in your solution, follow this tutorial : Update ASP.NET Core web application to .NETCoreApp1.1 causes a project loading failure

How to setup an Angular 2 and TypeScript project with Visual Studio 2017
February 11, 2017
  • ASP.NET Core
  • Angular
  • Angular2
  • TypeScript
  • NPM
  • Node.js
  • MVC