ASP.NET Core, Angular with Webpack and Visual Studio

This article shows how Webpack could be used together with Visual Studio ASP.NET Core and Angular. 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/AngularWebpackVisualStudio

Blogs in this series:

Authors

Roberto Simonetti

Fabian Gosebrink, Damien Bowden, Roberto Simonetti.

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

2017-08-19: Updated to ASP.NET Core 2.0 and angular 4.3.4,

See here for full history:
https://github.com/damienbod/AngularWebpackVisualStudio/blob/master/CHANGELOG.md

Tools

yarn, nodejs and npm are required to run this solution.

Update to the latest versions:

npm install npm@latest -g

npm install yarn -g

See this link for more details on yarn:

https://github.com/OfferingSolutions/Offering-Solutions-Angular-Course/tree/master/Angular-Course#yarn-not-necessary-but-nice-to-have

or

https://yarnpkg.com/en/docs/install

If you remove the yarn.lock file, you do not require yarn.

Setting up the application

The ASP.NET Core application contains both the server side API services and also hosts the Angular client application. The source code for the Angular application is implemented in the angularApp 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 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.

{
  "name": "angular-webpack-visualstudio",
  "version": "1.0.0",
  "description": "An Angular VS template",
  "main": "wwwroot/index.html",
  "author": "",
  "license": "ISC",
  "repository": {
    "type": "git",
    "url": "https://github.com/damienbod/Angular2WebpackVisualStudio.git"
  },
  "scripts": {
    "start": "concurrently \"webpack-dev-server --hot --inline --port 8080\" \"dotnet run\" ",
    "webpack-dev": "set NODE_ENV=development && webpack",
    "webpack-production": "set NODE_ENV=production && webpack",
    "build-dev": "npm run webpack-dev",
    "build-production": "npm run webpack-production",
    "watch-webpack-dev": "set NODE_ENV=development && webpack --watch --color",
    "watch-webpack-production": "npm run build-production --watch --color",
    "publish-for-iis": "npm run build-production && dotnet publish -c Release",
    "test": "karma start"
  },
  "dependencies": {
    "@angular/animations": "4.3.0",
    "@angular/common": "4.3.0",
    "@angular/compiler": "4.3.0",
    "@angular/compiler-cli": "4.3.0",
    "@angular/core": "4.3.0",
    "@angular/forms": "4.3.0",
    "@angular/http": "4.3.0",
    "@angular/platform-browser": "4.3.0",
    "@angular/platform-browser-dynamic": "4.3.0",
    "@angular/platform-server": "4.3.0",
    "@angular/router": "4.3.0",
    "@angular/upgrade": "4.3.0",
    "angular-in-memory-web-api": "0.3.2",
    "bootstrap": "3.3.7",
    "core-js": "2.4.1",
    "ie-shim": "0.1.0",
    "rxjs": "5.4.2",
    "zone.js": "0.8.12"
  },
  "devDependencies": {
    "@ngtools/webpack": "^1.5.1",
    "@types/node": "^8.0.12",
    "@types/jasmine": "^2.5.53",
    "angular2-template-loader": "^0.6.2",
    "angular-router-loader": "^0.6.0",
    "awesome-typescript-loader": "^3.2.1",
    "clean-webpack-plugin": "^0.1.16",
    "concurrently": "^3.5.0",
    "copy-webpack-plugin": "^4.0.1",
    "css-loader": "^0.28.0",
    "file-loader": "^0.11.2",
    "html-webpack-plugin": "^2.29.0",
    "jquery": "^3.2.1",
    "json-loader": "^0.5.4",
    "node-sass": "^4.5.3",
    "raw-loader": "^0.5.1",
    "rimraf": "^2.6.1",
    "sass-loader": "^6.0.6",
    "source-map-loader": "^0.2.1",
    "style-loader": "^0.18.2",
    "tslint": "^5.5.0",
    "tslint-loader": "^3.5.3",
    "typescript": "^2.4.1",
    "url-loader": "^0.5.9",
    "webpack": "^3.2.0",
    "webpack-dev-server": "^2.5.1",
    "jasmine-core": "^2.6.4",
    "karma": "^1.7.0",
    "karma-chrome-launcher": "^2.2.0",
    "karma-jasmine": "^1.1.0",
    "karma-sourcemap-loader": "^0.3.7",
    "karma-spec-reporter": "^0.0.31",
    "karma-webpack": "^2.0.4"
  },
  "-vs-binding": {
    "ProjectOpened": [
      "watch-webpack-dev"
    ]
  }
}

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": "es2015",
    "moduleResolution": "node",
    "sourceMap": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "removeComments": true,
    "noImplicitAny": true,
    "skipLibCheck": true,
    "lib": [
      "es2015",
      "dom"
    ],
    "typeRoots": [
      "./node_modules/@types/"
    ]
  },
  "exclude": [
    "node_modules",
    "angularApp/main-aot.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

const path = require('path');

const webpack = require('webpack');

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

const helpers = require('./webpack.helpers');

const ROOT = path.resolve(__dirname, '..');

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

module.exports = {

    devtool: 'source-map',
    performance: {
        hints: false
    },
    entry: {
        'polyfills': './angularApp/polyfills.ts',
        'vendor': './angularApp/vendor.ts',
        'app': './angularApp/main.ts'
    },

    output: {
        path: ROOT + '/wwwroot/',
        filename: 'dist/[name].bundle.js',
        chunkFilename: 'dist/[id].chunk.js',
        publicPath: '/'
    },

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

    devServer: {
        historyApiFallback: true,
        contentBase: path.join(ROOT, '/wwwroot/'),
        watchOptions: {
            aggregateTimeout: 300,
            poll: 1000
        }
    },

    module: {
        rules: [
            {
                test: /\.ts$/,
                use: [
                    'awesome-typescript-loader',
                    'angular-router-loader',
                    'angular2-template-loader',
                    'source-map-loader',
                    'tslint-loader'
                ]
            },
            {
                test: /\.(png|jpg|gif|woff|woff2|ttf|svg|eot)$/,
                use: 'file-loader?name=assets/[name]-[hash:6].[ext]'
            },
            {
                test: /favicon.ico$/,
                use: 'file-loader?name=/[name].[ext]'
            },
            {
                test: /\.css$/,
                use: [
                    'style-loader',
                    'css-loader'
                ]
            },
            {
                test: /\.scss$/,
                include: path.join(ROOT, 'angularApp/styles'),
                use: [
                    'style-loader',
                    'css-loader',
                    'sass-loader'
                ]
            },
            {
                test: /\.scss$/,
                exclude: path.join(ROOT, 'angularApp/styles'),
                use: [
                    'raw-loader',
                    'sass-loader'
                ]
            },
            {
                test: /\.html$/,
                use: 'raw-loader'
            }
        ],
        exprContextCritical: false
    },
    plugins: [
        new webpack.optimize.CommonsChunkPlugin({ name: ['vendor', 'polyfills'] }),

        new CleanWebpackPlugin(
            [
                './wwwroot/dist',
                './wwwroot/assets'
            ],
            { root: ROOT }
        ),

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

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

};


webpack.prod.js

const path = require('path');

const webpack = require('webpack');

const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const ngToolsWebpack = require('@ngtools/webpack');

const helpers = require('./webpack.helpers');

const ROOT = path.resolve(__dirname, '..');

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

module.exports = {

    entry: {
        'vendor': './angularApp/vendor.ts',
        'polyfills': './angularApp/polyfills.ts',
        'app': './angularApp/main-aot.ts' // AoT compilation
    },

    output: {
        path: ROOT + '/wwwroot/',
        filename: 'dist/[name].[hash].bundle.js',
        chunkFilename: 'dist/[id].[hash].chunk.js',
        publicPath: '/'
    },

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

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

    module: {
        rules: [
            {
                test: /\.ts$/,
                use: '@ngtools/webpack'
            },
            {
                test: /\.(png|jpg|gif|woff|woff2|ttf|svg|eot)$/,
                use: 'file-loader?name=assets/[name]-[hash:6].[ext]'
            },
            {
                test: /favicon.ico$/,
                use: 'file-loader?name=/[name].[ext]'
            },
            {
                test: /\.css$/,
                use: [
                    'style-loader',
                    'css-loader'
                ]
            },
            {
                test: /\.scss$/,
                include: path.join(ROOT, 'angularApp/styles'),
                use: [
                    'style-loader',
                    'css-loader',
                    'sass-loader'
                ]
            },
            {
                test: /\.scss$/,
                exclude: path.join(ROOT, 'angularApp/styles'),
                use: [
                    'raw-loader',
                    'sass-loader'
                ]
            },
            {
                test: /\.html$/,
                use: 'raw-loader'
            }
        ],
        exprContextCritical: false
    },

    plugins: [
        // AoT plugin.
        new ngToolsWebpack.AotPlugin({
            tsConfigPath: './tsconfig-aot.json'
        }),
        new CleanWebpackPlugin(
            [
                './wwwroot/dist',
                './wwwroot/assets'
            ],
            { root: ROOT }
        ),
        new webpack.NoEmitOnErrorsPlugin(),
        new webpack.optimize.UglifyJsPlugin({
            compress: {
                warnings: false
            },
            output: {
                comments: false
            },
            sourceMap: false
        }),
        new webpack.optimize.CommonsChunkPlugin(
            {
                name: ['vendor', 'polyfills']
            }),

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

        new CopyWebpackPlugin([
            { from: './angularApp/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"
    ]
  },
  "angularCompilerOptions": {
    "genDir": "./aot",
    "entryModule": "./angularApp/app/app.module#AppModule",
    "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.

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',
        chunkFilename: 'dist/[id].chunk.js',
        publicPath: "/"
    },

output for production adds a hash.

output: {
        path: "./wwwroot/",
        filename: 'dist/[name].[hash].bundle.js',
        chunkFilename: 'dist/[id].[hash].chunk.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 index.html

The index.html contains all the references required for the Angular 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 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

npm custom Task Runner

The NPM Task Runner can be used to build the client SPA application from inside Visual Studio. This task runner can be downloaded from:

https://marketplace.visualstudio.com/items?itemName=MadsKristensen.NPMTaskRunner

The task runners need to be configured correctly. Go to Tools –> Options –> Projects and Solutions –> External Web Tools.

Check that are options are checked. See:

https://blogs.msdn.microsoft.com/webdev/2015/03/19/customize-external-web-tools-in-visual-studio-2015/

npm scripts

The npm scripts are used to build, watch the client application as required. The scripts can be run from the command line or the npm task runner.

"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-production": "set NODE_ENV=production&& webpack",
"build-dev": "npm run webpack-dev",
"build-production": "npm run ngc && npm run webpack-production",
"watch-webpack-dev": "set NODE_ENV=development&& webpack --watch --color",
"watch-webpack-production": "npm run build-production --watch --color"

The watch-webpack-dev npm script can be automatically be started in Visual Studio by adding the following to the package.json

"-vs-binding": { "ProjectOpened": [ "watch-webpack-dev" ] }

Note Webpack task runner cannot be used to build the Angular webpack application as it uses the wrong options and cannot be used to do a production build due to the ngc.

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/

tslint

tslint is used in the webpack dev build.

{
	"rules": {
		"class-name": true,
		"comment-format": [
			true
		],
		"curly": true,
		"eofline": false,
		"forin": false,
		"indent": [
			false,
			"spaces"
		],
		"label-position": true,
		"max-line-length": [
			true,
			200
		],
		"member-access": false,
		"member-ordering": [
			true,
			"static-before-instance",
			"variables-before-functions"
		],
		"no-arg": true,
		"no-bitwise": true,
		"no-console": [
			true,
			"debug",
			"info",
			"time",
			"timeEnd",
			"trace"
		],
		"no-construct": true,
		"no-debugger": true,
		"no-duplicate-variable": true,
		"no-empty": false,
		"no-eval": true,
		"no-inferrable-types": [ true ],
		"no-shadowed-variable": false,
		"no-string-literal": false,
		"no-switch-case-fall-through": false,
		"no-trailing-whitespace": true,
		"no-unused-expression": true,
		"no-use-before-declare": true,
		"no-var-keyword": true,
		"object-literal-sort-keys": false,
		"one-line": [
			true,
			"check-open-brace",
			"check-catch",
			"check-else",
			"check-whitespace"
		],
		"quotemark": [
			true,
			"single"
		],
		"radix": false,
		"semicolon": [
			"always"
		],
		"triple-equals": [
			false,
			"allow-null-check"
		],
		"typedef-whitespace": [
			true,
			{
				"index-signature": "nospace",
				"parameter": "nospace",
				"property-declaration": "nospace",
				"variable-declaration": "nospace"
			}
		],
		"variable-name": false,
		"whitespace": [
			true,
			"check-branch",
			"check-decl",
			"check-operator",
			"check-separator",
			"check-type"
		]
	}
}

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 component files

Note: require cannot be used because AoT does not work with this.

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

@Component({
    selector: 'home-component',
    templateUrl: 'home.component.html'
})

export class HomeComponent implements OnInit {

    public message: string;
    public things: Thing[] = [];
    public thing: Thing = new Thing();

    constructor(private _dataService: TestDataService) {
        this.message = "Things from the ASP.NET Core API";
    }

    ngOnInit() {
        this.getAllThings();
    }

    public addThing() {
        this._dataService
            .Add(this.thing)
            .subscribe(() => {
                this.getAllThings();
                this.thing = new Thing();
            }, (error) => {
                console.log(error);
            });
    }

    public deleteThing(thing: Thing) {
        this._dataService
            .Delete(thing.id)
            .subscribe(() => {
                this.getAllThings();
            }, (error) => {
                console.log(error);
            });
    }

    private getAllThings() {
        this._dataService
            .GetAll()
            .subscribe(
            data => this.things = 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.

using System.Linq;
using Angular2WebpackVisualStudio.Models;
using Angular2WebpackVisualStudio.Repositories.Things;
using Microsoft.AspNetCore.JsonPatch;
using Microsoft.AspNetCore.Mvc;

namespace Angular2WebpackVisualStudio.Controller
{
    [Route("api/[controller]")]
    public class ThingsController : Microsoft.AspNetCore.Mvc.Controller
    {
        private readonly IThingsRepository _thingsRepository;

        public ThingsController(IThingsRepository thingsRepository)
        {
            _thingsRepository = thingsRepository;
        }

        [HttpGet]
        public IActionResult Get()
        {
            return Ok(_thingsRepository.GetAll());
        }

        [HttpPost]
        public IActionResult Add([FromBody] Thing thing)
        {
            if (thing == null)
            {
                return BadRequest();
            }

            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            Thing newThing = _thingsRepository.Add(thing);

            return CreatedAtRoute("GetSingleThing", new { id = newThing.Id }, newThing);
        }

        [HttpPatch("{id:int}")]
        public IActionResult PartiallyUpdate(int id, [FromBody] JsonPatchDocument<Thing> patchDoc)
        {
            if (patchDoc == null)
            {
                return BadRequest();
            }

            Thing existingEntity = _thingsRepository.GetSingle(id);

            if (existingEntity == null)
            {
                return NotFound();
            }

            Thing thing = existingEntity;
            patchDoc.ApplyTo(thing, ModelState);

            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            Thing updatedThing = _thingsRepository.Update(id, thing);

            return Ok(updatedThing);
        }

        [HttpGet]
        [Route("{id:int}", Name = "GetSingleThing")]
        public IActionResult Single(int id)
        {
            Thing thing = _thingsRepository.GetSingle(id);

            if (thing == null)
            {
                return NotFound();
            }

            return Ok(thing);
        }

        [HttpDelete]
        [Route("{id:int}")]
        public IActionResult Remove(int id)
        {
            Thing thing = _thingsRepository.GetSingle(id);

            if (thing == null)
            {
                return NotFound();
            }

            _thingsRepository.Delete(id);
            return NoContent();
        }

        [HttpPut]
        [Route("{id:int}")]
        public IActionResult Update(int id, [FromBody]Thing thing)
        {
            var thingToCheck = _thingsRepository.GetSingle(id);

            if (thingToCheck == null)
            {
                return NotFound();
            }

            if (id != thing.Id)
            {
                return BadRequest("Ids do not match");
            }

            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            Thing updatedThing = _thingsRepository.Update(id, thing);

            return Ok(updatedThing);
        }
    }
}

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 { Thing } from './../models/thing';
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 TestDataService {

    private actionUrl: string;
    private headers: Headers;

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

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

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

    public GetAll = (): Observable<Thing[]> => {
        return this._http.get(this.actionUrl).map((response: Response) => <Thing[]>response.json());
    }

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

    public Add = (thingToAdd: Thing): Observable<Thing> => {
        var toAdd = JSON.stringify({ name: thingToAdd.name });

        return this._http.post(this.actionUrl, toAdd, { headers: this.headers }).map(res => <Thing>res.json());
    }

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

    public Delete = (id: number): Observable<any> => {
        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 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

https://blogs.msdn.microsoft.com/webdev/2015/03/19/customize-external-web-tools-in-visual-studio-2015/

https://marketplace.visualstudio.com/items?itemName=MadsKristensen.NPMTaskRunner

http://sass-lang.com/

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

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

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

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

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

Advertisements

72 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?

  27. Ajay Kamat · · Reply

    Great article! Thanks! I am trying to incorporate primeng thirdparty component into the project and i am unable to get it to work. I added css ref. into vendor.ts and imported modules in app.module, but I get errors on compile: Unhandled Promise rejection: Template parse errors:
    Can’t bind to ‘selected’ since it isn’t a known property of ‘p-accordionTab’ etc. etc..

    Anything I am missing?? Please help!

    1. Hi Ajay thanks
      have you imported it in the component where you are using it?

      Greetings Damien

    2. For me PrimeNg works perfectly but schedule.

  28. You have just saved me months of research and spin-up time! I was getting very aggravated with learning all the nuances when implementing a solution in core + Angular 2 + Webpack. This is my first trip down front-end development using anything but MVC. This is spectacular.

  29. Hey how about some css references, like I have downloaded npm module and have imported it in my app.module.ts thats fine, now I need to implement styles. I can see in the folder there are css files but I’m not sure how I can add those style files to webpack so it can bundle it too my vendor.css file.
    thanks.

    1. Hi Sohaib
      You can add the third party css to the component and it will added to this componeent/module so that the other modules do not increase in size.

      If you require a global style you can add it to the main module or if you want to keep it separate import it in the vendor.ts or just add it to the index.html

      You should do it so that the end bundles are as small as possible and that the user gets the best experience.

      Greetings Damien

  30. Leonardo Lima da Silva · · Reply

    Hi Damien. Great article, it’s a real time saver. I’m new to webpack and hot module replacement. I’m running the “start” task with the npm task runner in VS2017, and it’s very slow (~12 seconds), furthermore, I’m getting a full page refresh, which invalidates the benefits of HMR. Only the SCSS updates without full refresh, but is slow as well. This slowness is usual, or I am missing something? I use gulp in a similar fashion and the live reload takes less than 2 seconds.

    Thanks in advance.

    1. Hi Leonardo
      That’s really slow. I run from the cmd line and it runs/updates ever second. Try it from the cmdline as see if this works better
      Greetings Damien

  31. Hi. I’m getting an error regarding the Loader. What should I do to fix it?

    ERROR in ./angularApp/polyfills.ts
    Module build failed: Error: Final loader didn’t return a Buffer or String
    at C:\Users\Me\Documents\MyProject\src\MyProject.Web\node_modules\webpack\lib\NormalModule.js:149:64
    at C:\Users\Me\Documents\MyProject\src\MyProject.Web\node_modules\loader-runner\lib\LoaderRunner.js:370:3
    at iterateNormalLoaders (C:\Users\Me\Documents\MyProject\src\MyProject.Web\node_modules\loader-runner\lib\LoaderRunner.js:211:10)
    at iterateNormalLoaders (C:\Users\Me\Documents\MyProject\src\MyProject.Web\node_modules\loader-runner\lib\LoaderRunner.js:218:10)
    at C:\Users\Me\Documents\MyProject\src\MyProject.Web\node_modules\loader-runner\lib\LoaderRunner.js:233:3
    at context.callback (C:\Users\Me\Documents\MyProject\src\MyProject.Web\node_modules\loader-runner\lib\LoaderRunner.js:111:13)
    at runMicrotasksCallback (internal/process/next_tick.js:58:5)
    at _combinedTickCallback (internal/process/next_tick.js:67:7)
    at process._tickCallback (internal/process/next_tick.js:98:9)

    1. seems like the npm packages have a problem. Try found the command line

      Delete the contents of the node_modules
      Then from the same folder as the package.json file
      $ npm install
      $ npm run build-production
      $ dotnet restore
      $ dotnet run

      Greetings Damien
      $

  32. Srini · · Reply

    Hi Damien,

    I am using visual studio enterprise 2017 RC.

    I downloaded your “VS2017 angular 4”. It compiled well but during running the app..

    In the console I see these error.

    Failed to load resource: the server responded with a status of 404 (Not Found) app.3d6e78a2100c846d62d4.bundle.js
    Failed to load resource: the server responded with a status of 404 (Not Found)
    polyfills.3d6e78a2100c846d62d4.bundle.js Failed to load resource: the server responded with a status of 404 (Not Found)
    vendor.3d6e78a2100c846d62d4.bundle.js Failed to load resource: the server responded with a status of 404 (Not Found)
    app.3d6e78a2100c846d62d4.bundle.js Failed to load resource: the server responded with a status of 404 (Not Found)

  33. srinivasakosuri · · Reply

    I am using visual studio Enterprise 2017 rc. I downloaded your “VS2017 angular 4 ”

    It compiles well but while running, and the page stops at “loading…” and I get these below errors in chrome.

    Failed to load resource: the server responded with a status of 404 (Not Found) app.3d6e78a2100c846d62d4.bundle.js Failed to load resource: the server
    vendor.3d6e78a2100c846d62d4.bundle.js Failed to load resource: the server responded with a status of 404 (Not Found)
    polyfills.3d6e78a2100c846d62d4.bundle.js Failed to load resource: the server responded with a status of 404 (Not Found)
    vendor.3d6e78a2100c846d62d4.bundle.js Failed to load resource: the server responded with a status of 404 (Not Found)
    app.3d6e78a2100c846d62d4.bundle.js Failed to load resource: the server responded with a status of 404 (Not Found)

    Is there something that I should do or should I have the latest packages of npm etc..

    node v6.10.0
    npm v3.10.10

    1. This means the SPA did not build correctly. You can test if it builds from the command line first, if this works, then you can configure VS to use the correct npm, node.

      In the cmd:
      Change directory to where the package.json file is
      $ npm install
      $ npm run build-production
      $ dotnet restore
      $ dotnet run

      Now it should work

      Greetings Damien

      1. srinivasakosuri · ·

        This worked for me.. Thank you!!!

  34. Dushko Stanoeski · · Reply

    Hi Damien,

    I have an AngularJS + .NET Framework 4.6 app at the moment that I want to migrate to Angular + .NET Core Web App that targets .NET Framework.

    At the moment I’m using MVC and .NET for registering and logging in and after you log in, depending on the roles that you are in you can access 6 different views, each containing a different SPA. With AngularJS and the bundling that .NET 4.6 provided this was quite easy, but now with Webpack and npm and all the other stuff, I am a bit lost.

    Is it possible to keep my current structure and configure webpack so it delivers the bundles in a view, or should I use a different approach?

    1. Hi Dushko (Hope that’s correct)

      This will work, you need to change the outputs and the entry points in the webpack config. I will try to create a demo of this, but it will be a week before I’ll publish anything on gitHub.

      In short, output is the MVC views, src one per app, and the tsconfig files need to be changed.

      Greetings Damien

      1. Dushko Stanoeski · ·

        You got the name right 🙂

        I’m a bit lost in the gulp/grunt/bower/npm/webpack and a couple of hundred other tools you need to make Angular 2 work, hopefully I’ll get the hang of it. Don’t know if it would be simpler to completely separate Angular 2 and .NET Core (I was reading your blog posts on the topic) or not.

  35. frosa · · Reply

    Hi there.

    Thanks for sharing.

    I’m having problems importing UIkit library to webpack configuration.
    UIkit imported successfully and working but the icons doesn’t appear.

    Can you provide me the configuration and initialization of UIkit+Uikit Icons in this template or point me in the right direction?

    Thanks.

    Greetings.

  36. Magesh · · Reply

    Can we have MVC Index.cshtml as home page and inject the scripts using web pack? Will HMR work in this case? I want to authenticate with windows authentication. So I need default MVC framework. Please provide ur suggestions

  37. […] Source: ASP.NET Core, Angular with Webpack and Visual Studio | Software Engineering […]

  38. Myola Pais · · Reply

    Hi,

    Thank you for the template. We are trying to build and deploy the template using VSTS.

    We are trying to use the production build. Does the command need to be publish-for-iis or build-production.

    when we do the publish-for-iis we get the error:

    ngc -p ./tsconfig-aot.json
    2017-04-24T00:59:47.2366218Z
    2017-04-24T00:59:47.3836277Z module.js:471
    2017-04-24T00:59:47.3836277Z throw err;
    2017-04-24T00:59:47.3836277Z ^
    2017-04-24T00:59:47.3836277Z
    2017-04-24T00:59:47.3836277Z Error: Cannot find module ‘typescript’
    2017-04-24T00:59:47.3836277Z at Function.Module._resolveFilename (module.js:469:15)
    2017-04-24T00:59:47.3836277Z at Function.Module._load (module.js:417:25)
    2017-04-24T00:59:47.3836277Z at Module.require (module.js:497:17)
    2017-04-24T00:59:47.3836277Z at require (internal/module.js:20:19)
    2017-04-24T00:59:47.3836277Z at Object. (C:\a\1\s\StartUMA-DEV\UMA.StartUMA.StudentPortal\node_modules\tsickle\build\src\tsickle.js:14:10)
    2017-04-24T00:59:47.3836277Z at Module._compile (module.js:570:32)
    2017-04-24T00:59:47.3836277Z at Object.Module._extensions..js (module.js:579:10)
    2017-04-24T00:59:47.3836277Z at Module.load (module.js:487:32)
    2017-04-24T00:59:47.3836277Z at tryModuleLoad (module.js:446:12)
    2017-04-24T00:59:47.3836277Z at Function.Module._load (module.js:438:3)
    2017-04-24T00:59:47.3986287Z npm ERR! code ELIFECYCLE
    2017-04-24T00:59:47.3986287Z npm ERR! errno 1
    2017-04-24T00:59:47.3986287Z npm ERR! angular-webpack-visualstudio@1.0.0 ngc: `ngc -p ./tsconfig-aot.json`
    2017-04-24T00:59:47.3986287Z npm ERR! Exit status 1

    1. To publish the app:

      > npm install
      > dotnet restore
      > dotnet build
      > npm run publish-for-iis

      The publish-for-iis script uses the build-production script. Maybe you you to restore the npm packages. Try from the commandline with the commands shown above.

      Greetings Damien

  39. Hi Damien,

    I have separated out my projects to app(netcore) and UI(angular2). Things are working great. Now during deployment in app.constants.ts, how can I configure these for various environments. Since I separated UI and app to different projects and deployed to various servers. I would like to put the environment variables in launchsettings.json so that I can easily configure environment variables in appveyor. Is there an easy way that you know to do it?

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: