ASP.NET Core, Angular2 with Webpack and Visual Studio

This article shows how Webpack could be used together with Visual Studio ASP.NET Core and Angular2. Both the client and the server side of the application is implemented inside one ASP.NET Core project which makes it easier to deploy.

vs_webpack_angular2

Code: https://github.com/damienbod/Angular2WebpackVisualStudio

Authors

Roberto Simonetti

Fabian Gosebrink, Damien Bowden, Roberto Simonetti.

This post is hosted on both http://damienbod.com and http://offering.solutions/ .

2016.11.17: Updated to Angular 2.2.0 and webpack 2 build.
2016.10.24: Using AoT, treeshaking, updated to webpack 2, Switched to @types: removed tsd & typings
2016.10.16: Updated to Angular 2.1.0, typings, Webpack SASS build
2016.10.01: Updated to Angular 2.0.1, typings
2016.09.15 Updated to Angular 2 release and ASP.NET Core 1.0.1
2016.09.03 Updated to Angular 2 rc.6
2016.08.12: Updated to Angular 2 rc.5 and split webpack file.
2016.07.02: Updated to Angular 2 rc.4
2016.06.29: Updated to ASP.NET Core RTM
2016.06.26: Updated to Angular 2 rc.3 and new routing
2016.06.17: Updated to Angular 2 rc.2

Setting up the application

The ASP.NET Core application contains both the server side API services and also hosts the Angular 2 client application. The source code for the Angular 2 application is implemented in the angular2App folder. Webpack is then used to deploy the application, using the development build or a production build, which deploys the application to the wwwroot folder. This makes it easy to deploy the application using the standard tools from Visual Studio with the standard configurations.

npm configuration

The npm package.json configuration loads all the required packages for Angular 2 and Webpack. The Webpack packages are all added to the devDependencies. A “npm build” script and also a “npm buildProduction” are also configured, so that the client application can be built using Webpack from the cmd line using “npm build” or “npm buildProduction”. These two scripts just call the same cmd as the Webpack task runner.

{
  "version": "1.0.0",
  "description": "",
  "main": "wwwroot/index.html",
  "author": "",
  "license": "ISC",
  "scripts": {
    "ngc": "ngc -p ./tsconfig-aot.json",
    "start": "concurrently \"webpack-dev-server --inline --progress --port 8080\" \"dotnet run\" ",
    "webpack-dev": "set NODE_ENV=development&& webpack",
    "webpack-prod": "set NODE_ENV=production&& webpack",
    "build": "npm run webpack-dev",
    "buildProduction": "npm run ngc && npm run webpack-prod"
  },
  "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",
    "zone.js": "^0.6.25",

    "@angular/compiler-cli": "2.2.0",
    "@angular/platform-server": "~2.1.0",
    "bootstrap": "^3.3.7",
    "ie-shim": "^0.1.0"
  },
  "devDependencies": {
    "@types/node": "^6.0.45",
    "angular2-template-loader": "^0.5.0",
    "awesome-typescript-loader": "^2.2.4",
    "clean-webpack-plugin": "^0.1.9",
    "concurrently": "^3.1.0",
    "copy-webpack-plugin": "^2.1.3",
    "css-loader": "^0.23.0",
    "file-loader": "^0.8.4",
    "html-webpack-plugin": "^2.8.1",
    "jquery": "^2.2.0",
    "json-loader": "^0.5.3",
    "node-sass": "^3.10.1",
    "raw-loader": "^0.5.1",
    "rimraf": "^2.5.2",
    "sass-loader": "^4.0.2",
    "source-map-loader": "^0.1.5",
    "style-loader": "^0.13.0",
    "ts-helpers": "^1.1.1",
    "typescript": "2.0.3",
    "url-loader": "^0.5.6",
    "webpack": "2.1.0-beta.27",
    "webpack-dev-server": "^1.16.2"
  }
}

tsconfig configuration

The tsconfig is configured to use commonjs as the module. The types are configured in this file, so typings are no longer required.

{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "moduleResolution": "node",
    "sourceMap": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "removeComments": true,
    "noImplicitAny": true,
    "skipLibCheck": true,
    "lib": [
      "es2015",
      "dom"
    ],
    "types": [
      "node"
    ]
  },
  "files": [
    "angular2App/app/app.module.ts",
    "angular2App/main.ts"
  ],
  "awesomeTypescriptLoaderOptions": {
    "useWebpackText": true
  },
  "compileOnSave": false,
  "buildOnSave": false
}

Webpack build

The Webpack development build >webpack -d just uses the source files and creates outputs for development. The production build copies everything required for the client application to the wwwroot folder, and uglifies the js files. The webpack -d –watch can be used to automatically build the dist files if a source file is changed.

The Webpack config file was created using the excellent gihub repository https://github.com/preboot/angular2-webpack. Thanks for this. Small changes were made to this, such as the process.env.NODE_ENV and Webpack uses different source and output folders to match the ASP.NET Core project. If you decide to use two different projects, one for server, and one for client, preboot or angular-cli, or both together would be a good choice for the client application.

webpack.config.js

/// <binding ProjectOpened='Run - Development' />

var isProd = (process.env.NODE_ENV === 'production');

if (!isProd) {
    module.exports = require('./webpack.dev.js');
} else
{
    module.exports = require('./webpack.prod.js');
}

webpack.dev.js

var path = require('path');

var webpack = require('webpack');

var HtmlWebpackPlugin = require('html-webpack-plugin');
var CopyWebpackPlugin = require('copy-webpack-plugin');
var CleanWebpackPlugin = require('clean-webpack-plugin');

console.log("@@@@@@@@@ USING DEVELOPMENT @@@@@@@@@@@@@@@");

module.exports = {

    devtool: 'source-map',

    entry: {
        'app': './angular2App/main.ts' // JiT compilation
    },

    output: {
        path: "./wwwroot/",
        filename: 'dist/[name].bundle.js',
        publicPath: "/"
    },

    resolve: {
        extensions: ['.ts', '.js', '.json', '.css', '.scss', '.html']
    },

    devServer: {
        historyApiFallback: true,
        stats: 'minimal',
        outputPath: path.join(__dirname, 'wwwroot/')
    },

    module: {
        rules: [
            {
                test: /\.ts$/,
                loaders: [
                    'awesome-typescript-loader',
                    'angular2-template-loader',
                    'source-map-loader'
                ]
            },
            {
                test: /\.(png|jpg|gif|ico|woff|woff2|ttf|svg|eot)$/,
                exclude: /node_modules/,
                loader: "file-loader?name=assets/[name]-[hash:6].[ext]",
            },
            {
                test: /\.css$/,
                exclude: /node_modules/,
                loader: "style-loader!css-loader"
            },
            {
                test: /\.scss$/,
                exclude: /node_modules/,
                loaders: ["style-loader", "css-loader", "sass-loader"]
            },
            {
                test: /\.html$/,
                loader: 'raw-loader'
            }
        ],
        exprContextCritical: false
    },

    plugins: [
        new CleanWebpackPlugin(
            [
                './wwwroot/dist',
                './wwwroot/fonts',
                './wwwroot/assets'
            ]
        ),

        new HtmlWebpackPlugin({
            filename: 'index.html',
            inject: 'body',
            template: 'angular2App/index.html'
        }),

        new CopyWebpackPlugin([
            { from: './angular2App/images/*.*', to: "assets/", flatten: true }
        ])
    ]

};


webpack.prod.js

var path = require('path');

var webpack = require('webpack');

var HtmlWebpackPlugin = require('html-webpack-plugin');
var CopyWebpackPlugin = require('copy-webpack-plugin');
var CleanWebpackPlugin = require('clean-webpack-plugin');

console.log("@@@@@@@@@ USING PRODUCTION @@@@@@@@@@@@@@@");

module.exports = {

    entry: {
        'app': './angular2App/main-aot.ts' // AoT compilation
    },

    output: {
        path: "./wwwroot/",
        filename: 'dist/[name].[hash].bundle.js',
        publicPath: "/"
    },

    resolve: {
        extensions: ['.ts', '.js', '.json', '.css', '.scss', '.html']
    },

    devServer: {
        historyApiFallback: true,
        stats: 'minimal',
        outputPath: path.join(__dirname, 'wwwroot/')
    },

    module: {
        rules: [
            {
                test: /\.ts$/,
                loaders: [
                    'awesome-typescript-loader'
                ]
            },
            {
                test: /\.(png|jpg|gif|ico|woff|woff2|ttf|svg|eot)$/,
                exclude: /node_modules/,
                loader: "file-loader?name=assets/[name]-[hash:6].[ext]",
            },
            {
                test: /\.css$/,
                exclude: /node_modules/,
                loader: "style-loader!css-loader"
            },
            {
                test: /\.scss$/,
                exclude: /node_modules/,
                loaders: ["style-loader", "css-loader", "sass-loader"]
            },
            {
                test: /\.html$/,
                loader: 'raw-loader'
            }
        ],
        exprContextCritical: false
    },

    plugins: [
        new CleanWebpackPlugin(
            [
                './wwwroot/dist',
                './wwwroot/fonts',
                './wwwroot/assets'
            ]
        ),
        new webpack.NoErrorsPlugin(),
        new webpack.optimize.UglifyJsPlugin({
            compress: {
                warnings: false
            },
            output: {
                comments: false
            },
            sourceMap: false
        }),

        new HtmlWebpackPlugin({
            filename: 'index.html',
            inject: 'body',
            template: 'angular2App/index.html'
        }),

        new CopyWebpackPlugin([
            { from: './angular2App/images/*.*', to: "assets/", flatten: true }
        ])
    ]
};


Webpack Production build

The production build has to be run from the command line. At present ngc, the angular compiler can only be used from the command line.

https://github.com/angular/angular/tree/master/modules/%40angular/compiler-cli

See also (Using ngc) http://blog.mgechev.com/2016/06/26/tree-shaking-angular2-production-build-rollup-javascript/

It can be run using npm run buildProduction which is configured in the package.json.

"buildProduction": "npm run ngc && npm run webpack-prod"

The production build uses tsconfig-aot.json and main-aot.ts as an entry point.

{
  "compilerOptions": {
    "target": "es5",
    "module": "es2015",
    "moduleResolution": "node",
    "sourceMap": false,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "removeComments": true,
    "noImplicitAny": true,
    "suppressImplicitAnyIndexErrors": true,
    "skipLibCheck": true,
    "lib": [
      "es2015",
      "dom"
    ]
  },
  "files": [
    "angular2App/app/app.module.ts",
    "angular2App/main-aot.ts"
  ],
  "angularCompilerOptions": {
    "genDir": "aot",
    "skipMetadataEmit": true
  },
  "compileOnSave": false,
  "buildOnSave": false
}

Lets dive into this a bit:

Firstly, all plugins are loaded which are required to process all the js, ts, … files which are included, or used in the project.

var path = require('path');

var webpack = require('webpack');

var HtmlWebpackPlugin = require('html-webpack-plugin');
var CopyWebpackPlugin = require('copy-webpack-plugin');
var CleanWebpackPlugin = require('clean-webpack-plugin');

The npm environment variable NODE_ENV is used to define the type of build, either a development build or a production build. The entries are configured depending on this parameter.

    entry: {
        'app': './angular2App/main.ts' // JiT compilation
    },

for webpack.prod.js

entry: {
        'app': './angular2App/main-aot.ts' // AoT compilation
    },

The entries provide Webpack with the required information, where to start from, or where to hook in to. Three entry points are defined in this configuration. These strings point to the files required in the solution. The starting point for the app itself is provided in one of these files, boot.ts as a starting-point and also all vendor scripts minified in one file, the vendor.ts.

import 'jquery/src/jquery';
import 'bootstrap/dist/js/bootstrap';

import './css/bootstrap.css';
import './css/bootstrap-theme.css';

Webpack knows which paths to run and includes the corresponding files and packages.

The “loaders” section and the “modules” section in the configuration provides Webpack with the following information: which files it needs to get and how to read the files. The modules tells Webpack what to do with the files exactly. Like minifying or whatever.

In this project configuration, if a production node parameter is set, different plugins are pushed into the sections because the files should be treated differently.

The output

output: {
        path: "./wwwroot/",
        filename: 'dist/[name].bundle.js',
        publicPath: "/"
    },

output for production adds a hash.

output: {
        path: "./wwwroot/",
        filename: 'dist/[name].[hash].bundle.js',
        publicPath: "/"
    },

tells webpack where to put the files in the end. You can use like wildcards to use the “name” or an “hash” or something like that.

Angular 2 index.html

The index.html contains all the references required for the Angular 2 client. The scripts are added as part of the build and not manually. The developer only needs to use the imports.

Source index.html file in the angular2App/public folder:

<!doctype html>
<html>
<head>
    <base href="./">

    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Angular 2 Webpack Demo</title>

    <meta http-equiv="content-type" content="text/html; charset=utf-8" />

    <meta name="viewport" content="width=device-width, initial-scale=1.0" />

</head>
<body>
    <my-app>Loading...</my-app>
</body>
</html>


And the produced build file in the wwwroot folder. The scripts for the app, vendor and boot have been added using Webpack. Hashes are used in a production build for cache busting.

<!doctype html>
<html>
<head>
    <base href="./">

    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Angular 2 Webpack Demo</title>

    <meta http-equiv="content-type" content="text/html; charset=utf-8" />

    <meta name="viewport" content="width=device-width, initial-scale=1.0" />

    <link rel="stylesheet" href="css/bootstrap.css">
</head>
<body>
    <my-app>Loading...</my-app>
<script type="text/javascript" src="/dist/app.bundle.js"></script></body>

</html>

Visual Studio tools

Webpack task runner from Mads Kristensen can be downloaded and used to send Webpack commands using the webpack.config.js file. The node NODE_ENV parameter is used to define the build type. The parameter can be set to “development”, or “production”.

vs_webpack_angular2_02

The Webpack task runner can also be used by double clicking the task. The execution results are then displayed in the task runner console.

vs_webpack_angular2_03

This runner provides a number of useful commands which can be activated automatically. These tasks can be attached to Visual Studio events by right clicking the task and selecting a binding. This adds a binding tag to the webpack.config.js file.

/// <binding ProjectOpened='Run - Development' />

Webpack SASS

SASS is used to style the SPA application. The SASS files can be built using the SASS loader. Webpack can build all the styles inline or as an external file, depending on your Webpack config.

{
  test: /\.scss$/,
  exclude: /node_modules/,
  loaders: ["style", "css", "sass"]
},

See: https://damienbod.com/2016/10/14/using-sass-with-webpack-angular2-and-visual-studio/

Webpack Clean

clean-webpack-plugin is used to clean up the deployment folder inside the wwwroot. This ensures that the application uses the latest files.

The clean task can be configured as follows:

var CleanWebpackPlugin = require('clean-webpack-plugin');

And used in Webpack.

  new CleanWebpackPlugin(['./wwwroot/dist']),

The module loaders

module: {
        loaders: [
           //...loaders here
        ]
    },

tell webpack how to react when a certain file extension comes into play. It will then use loaders to handle that file.

The plugins you are providing in the end are necessary to configure how the files should be processed.


    plugins: [
        //...loaders here
    ]

Angular 2 component files

The Angular 2 components are slightly different to the standard example components. The templates and the styles use require, which adds the html or the css, scss to the file directly using Webpack, or as an external link depending on the Webpack config.

import { Component, OnInit } from '@angular/core';
import { TestDataService } from '../services/testDataService';


@Component({
    selector: 'homecomponent',
    templateUrl: 'home.component.html',
    providers: [TestDataService]
})

export class HomeComponent implements OnInit {

    public message: string;
    public values: any[];

    constructor(private _dataService: TestDataService) {
        this.message = "Hello from HomeComponent constructor";
    }

    ngOnInit() {
        this._dataService
            .GetAll()
            .subscribe(
            data => this.values = data,
            error => console.log(error),
            () => console.log('Get all complete')
            );
    }
}

The ASP.NET Core API

The ASP.NET Core API is quite small and tiny. It just provides a demo CRUD service.

 [Route("api/[controller]")]
    public class ValuesController : Microsoft.AspNetCore.Mvc.Controller
    {
        // GET: api/values
        [HttpGet]
        public IActionResult Get()
        {
            return new JsonResult(new string[] { "value1", "value2" });
        }

        // GET api/values/5
        [HttpGet("{id}")]
        public IActionResult Get(int id)
        {
            return new JsonResult("value");
        }

        // POST api/values
        [HttpPost]
        public IActionResult Post([FromBody]string value)
        {
            return new CreatedAtRouteResult("anyroute", null);
        }

        // PUT api/values/5
        [HttpPut("{id}")]
        public IActionResult Put(int id, [FromBody]string value)
        {
            return new OkResult();
        }

        // DELETE api/values/5
        [HttpDelete("{id}")]
        public IActionResult Delete(int id)
        {
            return new NoContentResult();
        }
    }

The Angular2 Http-Service

Note that in a normal environment, you should always return the typed classes and never the plain HTTP response like here. This application only has strings to return, and this is enough for the demo.

import { Injectable } from '@angular/core';
import { Http, Response, Headers } from '@angular/http';
import 'rxjs/add/operator/map'
import { Observable } from 'rxjs/Observable';
import { Configuration } from '../app.constants';

@Injectable()
export class DataService {

    private actionUrl: string;
    private headers: Headers;

    constructor(private _http: Http, private _configuration: Configuration) {

        this.actionUrl = _configuration.Server + 'api/values/';

        this.headers = new Headers();
        this.headers.append('Content-Type', 'application/json');
        this.headers.append('Accept', 'application/json');
    }

    public GetAll = (): Observable =&gt; {
        return this._http.get(this.actionUrl).map((response: Response) =&gt; response.json());
    }

    public GetSingle = (id: number): Observable =&gt; {
        return this._http.get(this.actionUrl + id).map(res =&gt; res.json());
    }

    public Add = (itemName: string): Observable =&gt; {
        var toAdd = JSON.stringify({ ItemName: itemName });

        return this._http.post(this.actionUrl, toAdd, { headers: this.headers }).map(res =&gt; res.json());
    }

    public Update = (id: number, itemToUpdate: any): Observable =&gt; {
        return this._http
            .put(this.actionUrl + id, JSON.stringify(itemToUpdate), { headers: this.headers })
            .map(res =&gt; res.json());
    }

    public Delete = (id: number): Observable =&gt; {
        return this._http.delete(this.actionUrl + id);
    }
}

Notes:

The Webpack configuration could also build all of the scss and css files to a separate app.css or app.”hash”.css which could be loaded as a single file in the distribution. Some of the vendor js and css could also be loaded directly in the html header using the index.html file and not included in the Webpack build.

If you are building both the client application and the server application in separate projects, you could also consider angular-cli of angular2-webpack for the client application.

Debugging the Angular 2 in Visual Studio with breakpoints is not possible with this setup. The SPA app can be debugged in chrome.

Links:

https://github.com/preboot/angular2-webpack

https://webpack.github.io/docs/

https://github.com/jtangelder/sass-loader

https://github.com/petehunt/webpack-howto/blob/master/README.md

http://www.sochix.ru/how-to-integrate-webpack-into-visual-studio-2015/

http://sass-lang.com/

WebPack Task Runner from Mads Kristensen

http://blog.thoughtram.io/angular/2016/06/08/component-relative-paths-in-angular-2.html

https://angular.io/docs/ts/latest/guide/webpack.html

https://angular.io/docs/ts/latest/tutorial/toh-pt5.html

http://angularjs.blogspot.ch/2016/06/improvements-coming-for-routing-in.html?platform=hootsuite

http://blog.mgechev.com/2016/06/26/tree-shaking-angular2-production-build-rollup-javascript/

47 comments

  1. Hello. thanks. very useful article. if i want to make split app folder to several bundle with webpack, what should i do?

    1. You could create different entry points, and use different src folders

      Greetings Damien

  2. It might be a good idea to separate the front-end code from the back-end, here is a working example with ASP.NET Core, Webpack and React:

    https://github.com/kriasoft/aspnet-starter-kit

  3. […] ASP.NET Core, Angular2 with Webpack and Visual Studio – Damien Bowden joins forces with Fabian Gosebrink to take a look combining ASP.NET Core with ANgualr 2 and WebPack […]

  4. Hi, great article. I was struggling with the new Angular2 routing.. Your example really helped me out. I had one question, when running the sample, automatic redirect to the home page is not happening. The app.routes.ts has an entry that it should route to it. Why is that ?

    Thanks for this great article !

    1. Hi Vik

      thanks. There is no redirect, I have just defined the default route. I’m also having problems with the new router and webpack.

      Greetings Damien

      1. The new router is now working, was an issue with the vendor order.

  5. Paul Evans · · Reply

    Thanks. Working on a new site and decided to try Angular 2. Started working with the ng2-admin-master template. But wanted to get it into a structure like yours, using Web API for data access. ng2-admin uses Webpack, which I was unfamiliar with, so it’s been a steep learning curve. This should be very helpful.

    … also, with respect to your last comment, ng2-admin is using 3.0.0-beta.2 of angular router and it’s working with Webpack

  6. This looks like a very interesting approach.
    I downloaded the source to take a look at it ( in vs2015 Update 3).
    Something seems to be going wrong with npm restoring packages.
    I get a yellow triangle and the npm node in solution explorer says npm – not installed.
    When I right click each of the packages they all have “Uninstall package” as an option.
    I don’t follow what’s going on.
    Any ideas?

    In another solution’s package.json I have
    “dependencies”:
    {
    “angular2”: “2.0.0-beta.17”,
    Which finds angular packages OK.
    In neither solution, if I try adding a dependency starting “@ then it finds nothing. That could well be just intellisense I suppose.

    1. Hi Andy

      This is just a VS 2015 bug, VS shows npm warnings as faults. One npm package has a warning. Hopewfully VS Tooling will fix this.

      Greetings Damien

  7. In the mean time, how do you compile and run?

    When I hit f5 it doesn’t build. I get an error
    cannot find ‘@angular/common’

  8. When I right click and restore packages, I find this output:
    PATH=.\node_modules\.bin;C:\Program Files (x86)\Microsoft Visual Studio 14.0\Web\External;%PATH%;C:\Program Files (x86)\Microsoft Visual Studio 14.0\Web\External\git
    “C:\Program Files (x86)\Microsoft Visual Studio 14.0\Web\External\npm.CMD” install
    (node:9456) fs: re-evaluating native module sources is not supported. If you are using the graceful-fs module, please update it to a more recent version.
    npm WARN install Couldn’t install optional dependency: Unsupported
    npm WARN prefer global node-gyp@3.4.0 should be installed with -g
    > @1.0.0 postinstall C:\Code\Angular2WebpackVisualStudio-master\Angular2WebpackVisualStudio\src\Angular2WebpackVisualStudio
    > typings install
    typings WARN deprecated 8/2/2016, 4:50:38 PM: “registry:dt/node#6.0.0+20160621231320” has been deprecated
    ├── core-js (global)
    └── node (global)
    npm WARN EPEERINVALID @angular/forms@0.2.0 requires a peer of @angular/common@^2.0.0-rc.4 but none was installed.
    npm WARN EPEERINVALID @angular/platform-browser@2.0.0-rc.4 requires a peer of @angular/common@^2.0.0-rc.4 but none was installed.
    npm WARN EPEERINVALID @angular/platform-browser-dynamic@2.0.0-rc.4 requires a peer of @angular/common@^2.0.0-rc.4 but none was installed.
    npm WARN EPEERINVALID @angular/router@3.0.0-beta.1 requires a peer of @angular/common@^2.0.0-rc.4 but none was installed.
    npm WARN EPACKAGEJSON @1.0.0 No description
    npm WARN EPACKAGEJSON @1.0.0 No repository field.

    1. Hi Andy

      check that npm works first
      >npm install -g npm

      Then when this is ok, you can double click the webpack build in the task runner in VS to build the client code

      greetings Damien

  9. I will check if I have any of your warnings, I will do that next week, last time I built, I didn’t.

    Greetings Damien

  10. Hi Damien,

    I appreciate your help.

    npm seems to be working.

    When I double click the run-development it outputs a bunch of errors.
    eg
    ERROR in C:\Code\Angular2WebpackVisualStudio-master\Angular2WebpackVisualStudio\src\Angular2WebpackVisualStudio\node_modules\@angular\platform-browser\src\web_workers\worker\platform_location.d.ts
    (8,53): error TS2307: Cannot find module ‘@angular/common’.

    Unsurprisingly, it then fails to build on f5

    It’s obviously not getting all those @angular…. dependencies, but I have no idea why.

    1. This could be a typings issue Try deleting the contents of the typings folder and run from the command line in the src folder:

      >npm install typings
      >
      >npm install
      >
      >typings install
      >
      >SET NODE_ENV=development && webpack -d –color

      It can only work, once the webpack build is successful. I don’t understand what’s going wrong, but I suspect some node tool is missing on your computer.

      Also, are you using the latest version of node and npm 1.8.10?

      Make sure Typescript 1.0 does not existing in the Microsoft sdk folder, (Typescript update bug)

      >npm -v => should be latest version.

      Greetings Damien

  11. Hi Damien,

    Thanks for your help.

    I think the issues are due to the fact I don’t understand what I’m doing with node and npm… Plus as you say, something has gone wrong with the install on this machine..
    Is there an introductory guide somewhere that you would recommend?

    I tried a number of things yesterday.
    Today I’ve uninstalled Node, removed the appdata folders for npm and re-installed node 64bit.
    Tried your advice on typings but the npm install typings seemed to fail so I reverted.

    I can now compile.
    So that’s progress :^)

    I now have a problem with node-sass:

    ERROR in Missing binding C:\Code\Angular2WebpackVisualStudio-master\Angular2WebpackVisualStudio\src\Angular2WebpackVisualStudio\node_modules\node-sass\vendor\win32-x64-46\binding.node
    Node Sass could not find a binding for your current environment: Windows 64-bit with Node.js 4.x
    Found bindings for the following environments:
    – Windows 32-bit with Node.js 5.x
    This usually happens because your environment has changed since running `npm install`.
    Run `npm rebuild node-sass` to build the binding for your current environment.
    @ ./angular2App/app/app.component.ts 21:54-82

    I notice that’s saying 32 bit node.js 5.x
    I installed 64 bit node and it’s a different version.

    npm version is 3.10.5
    node version is 4.4.7

    Running that npm rebuild command ( from the src folder ) seems to make no difference.

  12. I found a question on stack overflow which is about something similar.
    As suggested by one of the posters there, I deleted my node_modules folder and allowed visual studio to re-create it.
    Oh yeah.. node_modules. Obviously.
    Cranking up visual studio for the project took a while – there’s a LOT of stuff ends up in that folder.
    Then of course the task runner kicks in.

    I get a rather alarming set of red errors in the task runner like:
    error TS2384: Overload signatures must all be ambient or non-ambient.
    ERROR in ./~/reflect-metadata/Reflect.ts

    After a while wailing and banging my head on the desk I hit f5 on the off chance.
    It worked.

    Conclusions:

    Read up on node and npm first.
    Don’t trust the vs tooling.
    Remember this is bleeding edge – it’s you bleeding.

    I really hope someone comes up with a way for visual studio (or something, anything) to make all this easier.

    1. Wow, sounded like a right battle, glad you got it working.

      Greetings Damien

  13. Alex Golovan · · Reply

    Hi Damien,

    Thanks for your help all articles!

    I expanded this example but having very interesting question related to Angular routing.

    Those are routes that defined in my app.routes.ts

    export const routes: RouterConfig = [
    { path: ”, component: HomeComponent, terminal: true },

    { path: ‘home’, component: HomeComponent, terminal: true },
    { path: ‘*’, component: HomeComponent },
    …UserClaimsRoutes
    ];

    This is my app.component.html

    Home
    New Request

    Initially, I am landing at Home page, using the following code in app.component.ts to navigate to Home component.

    ngOnInit() {
    this.router.navigate([‘/home’]);

    Home.component.html has the following links:

    User Claims
    Search By Tracking ID

    When I click UserClaims, it goes to UserClaims page. Very good!

    When I click Home button, I want to activate HomeComponent again and see all links and to select another link, however, nothing is happening, i still see UserClaims page

    If I select New Request, which is on app.component,html, I am going to this page. From there, I can select Home, and it goes to Home page.

    How can I always activate Home and see all my links and be able to activate another link? What I am missing here?

    Thanks!

  14. Alex Golovan · · Reply

    I figured out issue in my last question! I have another one – it is related to using webpack and putting the current version on dev.
    I am using TaskRunner at my local and it does all changes needed to put into wwwroot folder.
    However, when we put our sources into Git, we did not put app,js file, we just put all sources that we have outside of wwwroot and plus all configuration files. How we can invoke webpack on dev to build those files?

    1. cmd> webpack -d or with other options

      npm tools need to build installed on your build server, npm, node webpack, typings etc

      You can see the exact command I use for webpack dev or prod builds in the console of the webpack task runner

      Greetings Damien

  15. Alex Golovan · · Reply

    Thank you very much!

  16. Alex Golovan · · Reply

    Do you know by any chance if anything special should be done to work IE11 with webpack?

    I added the following lines of code to index.html

    http://node_modules/es6-shim/es6-shim.min.js
    http://node_modules/systemjs/dist/system-polyfills.js
    http://node_modules/angular2/es6/dev/src/testing/shims_for_IE.js

    It crashes now at vendor.js – Oject doesn’t support property or method ‘keys’.

    var _clearValues = (function () {
    if ((new exports.Map()).keys().next) { //crashes here
    return function _clearValues(m) {
    var keyIterator = m.keys();

    I found many references to this error but I think that something should be done related to webpack build. I still continue searching, but may be you have same answers. Thanks again!

  17. Alex Golovan · · Reply

    Your recent sample from 08/12, work at IE. Previous one – from 07/02, does not work. What change at newest sample made it possible to work on IE? Thanks!

    1. Alex Golovan · · Reply

      Yup – it did it! Thanks again for your help!

  18. Hi Damien, nice article.

    I was wondering if you can show how to use MVC view instead of static html page.
    I don’t see the need for .net core if you are just serving static html, maybe i am missing something🙂

    The project i am working on has only one page with MVC it’s the start and i can’t transfer it to static html cause of security reasons.
    So how to serve the project?
    How do you publish?

    Any ideas?

  19. Are you talking about a MVC view with a SPA? If so, here’s a really good example:

    https://github.com/aspnet/JavaScriptServices/tree/dev/samples/angular/MusicStore

    If it’s just a plan MVC application, the ASP.NET Core docs are good.

    https://docs.asp.net/en/latest/mvc/index.html

    The server usually needs to solve the security requirements and also implement some services or persistence. If it only needs to server static files, then yes, you’re right ASP.NET Core is not required, or over the top.

    Publish: depends on the client, number of deployments. I always try to automatic as much a possible (Return of investment). If the projects reaches a certain size, or needs to be maintained, updated regularly, then full automation using a CI is always the cheapest way.

    Hope this helps greetings Damien

    1. Thanks for the quick reply, sadly the Music Store is out of date and not using Webpack.
      The thing is i’m currently running gulp before starting the web app using Kestrel web server to compile and minify/bundle the code and i am using SystemJS.

      I wanted to use Webpack cause of HMR, but it can’t serve the inital MVC page🙂 if it were a static html as shown in your example then i wouldn need Kestrel to serve the MVC page and use Webpack dev server.

      Thanks anyway, if i find a solution i will post it here

      1. Sorry I sent you the wrong link, this is the correct one
        https://github.com/aspnet/JavaScriptServices/tree/dev/templates/Angular2Spa
        with webpack

    2. Thanks a lot Damien for pointing me in the right direction.
      I had that repo starred and bookmarked, just never got around to look at it🙂

      So Steve is starting the project with .NET Core and in the same time an instance of webpack serving the compiled, bundled and minified files.
      Basically JS services for .NET Core is a bridge to nodejs.

      I found this helpfull, it’s a video where Steve talks about the exact thing i was looking for and explains a bit more.

      The related blog post
      http://blog.stevensanderson.com/2016/05/02/angular2-react-knockout-apps-on-aspnet-core/

  20. If you have Angular 1.5 web site, is it a way to start development part of this side in Angular 2.0? I mean that both Angular 1.5 and Angular 2.0? Thanks!

  21. nigelpage · · Reply

    Outstanding article and working sample – thank you! One suggestion… please change “launchUrl” to “http://localhost:5000/” in “Angular2WebpackVisualStudio” in your launchSettings.json file, then self-hosted solutions will open to the Angular app, not the api\Values – thanks.

    1. Hi nigelpage, thanks, I’ll make the change this weekend. thanks for the tip

      Greetings Damien

    2. @nigelpage, fixed.
      Thanks for the feedback

      Greetings Damien

  22. How can i implement Lazy Loading??

    1. I will add this this week, have a gitHub issue opened, Greetings Damien

      1. Thanks a lot… finally I got it with angular2-router-loader

  23. Hello,
    I tried to run this project. In Microsoft Edge when I look into developer console, it gives many missing .map file errors. Any idea what can be wrong?

    1. Hi Nafr1

      No, this seems to be a problem with the development build in Edge and IE, in firefox and chrome it’s fine. The productionBuild works in all 4 browsers, haven’t tested in Safari.

      The map files are part of the bundle in dev mode when you do a webpack -d build.

      Greetings Damien

  24. what is the use of AoT? I noticed that AoT files are generated at production build only?

  25. Hello Damien,
    Any plans to fix this dev issue in Edge and IE?

    Thanks.

    1. In the near future no, have no time due to other commitments. Because it’s only the dev build in IE and Edge, it’s not on my high priority list, as soon as I get time, I will try to solve it.

      Here’s then issue to track, or add comments:
      https://github.com/damienbod/Angular2WebpackVisualStudio/issues/29

  26. Hello Damien,
    Sounds fair. Any plans to add Unit testing and e2e testing with this entire framework?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: