Quantcast

comments edit

As usual, the source is available on Github here.

This part will add continuous integration using AppVeyor. They’re free for projects hosted on github public repositories, so, let’s go!

For a standard .NET project, there is almost no setup required, just add your repository as a new project, and it will build the .sln file at the root, and run your tests !

Here is the output after adding my Samples.SerializerFun repository, without any specific configuration.

Build success !

but for Node.js…

… things are going to be a little different, we’re going to have to use an appveyor.yml file to setup everything.

Here is the first version of the file, which is quite simple, full reference available here.

# environment variables
environment:
  nodejs_version: "5"

# scripts that run after cloning repository
install:
  # install node 
  - ps: Install-Product node $Env:nodejs_version
  - npm install -g npm
  - npm install -g webpack  
  
# scripts to run before build
before_build:
  # install node modules
  - cd %APPVEYOR_BUILD_FOLDER%
  - cd Samples.Front
  - npm install
  # run webpack with production flag
  - webpack -p
  
artifacts:
  - path: Samples.Front\wwwroot

However, this will lead to a nasty error :

Build FAILED.
 
"C:\projects\samples-angular2\Samples.Angular2.sln" (default target) (1) ->
"C:\projects\samples-angular2\Samples.Front\Samples.Front.xproj" (default target) (2) ->
(GetRuntimeToolingPathTarget target) -> 
  C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v14.0\DNX\Microsoft.DNX.targets(126,5): error : The Dnx Runtime package needs to be installed. See output window for more details. [C:\projects\samples-angular2\Samples.Front\Samples.Front.xproj]

After a bit of fiddling and searching, adding the following lines :

# scripts that run after cloning repository
install:
  # install DNX
  - set PATH=C:\Program Files (x86)\MSBuild\14.0\Bin;%PATH%
  - dnvm upgrade
  - dnu restore  

Downloaded and installed latest DNX, which allowed the project to build, after adding

  # back to original folder
  - cd %APPVEYOR_BUILD_FOLDER%  

at the end of before_build scripts, otherwise, the build system would try to build Samples.Angular2.sln, while still in the Samples.Front project…

finally

The build succeeds :

Build success !

And a nice artifact is generated for download.

comments edit

This series sample will convert the Tour of heroes sample application from angular.io.

As usual, the source is available on Github here.

This part will add webpack support to our samples, to replace grunt.

Prerequisites

The following two visual studio extensions will make our lifes easier :

Improved task runner explorer

Webpack installation

A nice introduction for this new fancy Webpack thing was made by Burke Holland from Telerik. Have a look at it, I’ll be waiting for you here!

Now, we can start writing some config and code !

First of all, we’ll need to update the package.json file :

  "dependencies": {
    "angular2": "2.0.0-beta.15",
    "es6-shim": "^0.35.0",
    "reflect-metadata": "0.1.2",
    "rxjs": "5.0.0-beta.2",
    "zone.js": "0.6.11"
  },
  "devDependencies": {
    "webpack": "^1.12.13",

    "copy-webpack-plugin": "^1.1.1",
    "css-loader": "^0.23.0",
    "file-loader": "^0.8.4",
    "html-loader": "^0.4.0",
    "raw-loader": "0.5.1",
    "style-loader": "^0.13.0",
    "ts-loader": "^0.8.1",

    "typescript": "^1.8.0",
    "typings": "^0.7.12"
  },

Webpack configuration

All configuration is done through a javascript file named … webpack.conf.js. The base concept is that webpack will discover your code, from one or more entry points:

    config.entry = {
        'polyfills': ['core-js/client/core', 'angular2/bundles/angular2-polyfills'],
        'vendor': './src/vendor.ts',
        'app': './src/main.ts' // our angular app
    };

From there, loaders will transform your code:

    loaders: [
        // Reference: https://github.com/TypeStrong/ts-loader
        // -> ts compilation
        {
          test: /\.ts$/,
          loader: 'ts'
        },

        // Reference: https://github.com/webpack/css-loader
        // -> will resolve imports and requires in css
        // Reference: https://github.com/webpack/style-loader
        // -> will load the css into the page
        {
          test: /\.css$/,
          // all files in css folder
          include: path.join(sourcesRoot, 'src/css'),
          loader: 'style!css'
        },

        // Reference: https://github.com/webpack/raw-loader
        {
          test: /\.css$/,
          // all files in app folder will get inlined
          include: path.join(sourcesRoot, 'src/app'),
          loader: 'raw'
        },

        // https://github.com/webpack/raw-loader
        {
          test: /\.html$/,
          loader: 'raw'
        }
    ]

And produce an output :

    config.output = {
        path: path.join(sourcesRoot, 'wwwroot'),
        filename: 'js/[name].js'
    };

Typings

This one is mandatory for referencing libraries from your code, and having compilation working smoothly. Setup is straightforward : create a typings.json file, and run

typings install

Using package.json, this can go into a script, and we can put webpack there as well :

  "scripts": {
    "typings": "typings install",
    "webpack-dev": "webpack -d --color"
  },

Updating the code

A few updates are required, add a vendor.ts file to reference external libraries entry points :

// Angular 2
import 'angular2/platform/browser';
import 'angular2/platform/common_dom';
import 'angular2/core';
import 'angular2/router';
import 'angular2/http';

// RxJS
import 'rxjs';

Replace templateUrls and styleUrls, as for the moment, we’re going to let webpack inline the templates and the styles:

    // from:
    templateUrl: 'hero-detail.component.html',
    styleUrls: ['hero-detail.component.css'],

    // to:
    template: require('./hero-detail.component.html'),
    styles: [require('./hero-detail.component.css')],

Weird issue : templates loaded as urls ?!

In the following exception, it looks like the template used for one component acts as an URL : GET http://localhost:53792/%3Ch1%3E%7B%7Btitle%7D%7D%3C/h1%3E%0D%0A%0D%0A%0D%0A 400 (Bad Request) EXCEPTION: Failed to load %3Ch1%3E%7B%7Btitle%7D%7D%3C/h1%3E%0D%0A%0D%0A%0D%0A EXCEPTION: Failed to load %3Ch1%3E%7B%7Btitle%7D%7D%3C/h1%3E%0D%0A%0D%0A%0D%0A EXCEPTION: Error: Uncaught (in promise): Failed to load %3Ch1%3E%7B%7Btitle%7D%7D%3C/h1%3E%0D%0A%0D%0A%0D%0A EXCEPTION: Error: Uncaught (in promise): Failed to load %3Ch1%3E%7B%7Btitle%7D%7D%3C/h1%3E%0D%0A%0D%0A%0D%0A STACKTRACE: Error: Uncaught (in promise): Failed to load %3Ch1%3E%7B%7Btitle%7D%7D%3C/h1%3E%0D%0A%0D%0A%0D%0A at resolvePromise (angular2-polyfills.js:602) at angular2-polyfills.js:638 at ZoneDelegate.invokeTask (angular2-polyfills.js:423) at Object.NgZoneImpl.inner.inner.fork.onInvokeTask (ng_zone_impl.js:36) at ZoneDelegate.invokeTask (angular2-polyfills.js:422) at Zone.runTask (angular2-polyfills.js:320) at drainMicroTaskQueue (angular2-polyfills.js:541) at XMLHttpRequest.ZoneTask.invoke (angular2-polyfills.js:493) Unhandled Promise rejection: Failed to load %3Ch1%3E%7B%7Btitle%7D%7D%3C/h1%3E%0D%0A%0D%0A%0D%0A ; Zone: angular ; Task: Promise.then ; Value: Failed to load %3Ch1%3E%7B%7Btitle%7D%7D%3C/h1%3E%0D%0A%0D%0A%0D%0A Error: Uncaught (in promise): Failed to load %3Ch1%3E%7B%7Btitle%7D%7D%3C/h1%3E%0D%0A%0D%0A%0D%0A(…) Unhandled Promise rejection: Failed to load %3Ch1%3E%7B%7Btitle%7D%7D%3C/h1%3E%0D%0A%0D%0A%0D%0A ; Zone: <root> ; Task: Promise.then ; Value: Failed to load %3Ch1%3E%7B%7Btitle%7D%7D%3C/h1%3E%0D%0A%0D%0A%0D%0A Error: Uncaught (in promise): Failed to load %3Ch1%3E%7B%7Btitle%7D%7D%3C/h1%3E%0D%0A%0D%0A%0D%0A(…)

After a LOT of head scratching and banging, the issue was simply that :

@Component({
    selector: 'dashboard',
    templateUrl: require('./dashboard.component.html'),
    styleUrls: [require('./dashboard.component.css')]
})

needs to be changed with :

@Component({
    selector: 'dashboard',
    template: require('./dashboard.component.html'),
    styles: [require('./dashboard.component.css')]
})

Otherwise, the template would be … the url…

Special thanks

A lot of this setup and configuration was made possible thanks to angular2-webpack repository, thanks to them for the hard work put into their repo, which contains a lot more interesting stuff to see!

comments edit

This series sample will convert the Tour of heroes sample application from angular.io.

As usual, the source is available on Github here.

This part will add source map support, for easier typescript debugging using Chrome tools.

Configuring typescript compiler

The easiest way to generate source maps is to add two parameters to the tsconfig.json file :

{
  "compilerOptions": {
    "inlineSourceMap": true,
    "inlineSources": true,
  }
}

Those will generate inline source mapping and original typescript sources directly into generated javascript files.

Debugging

Running the Chrome debugger (unfortunately, not working with IE11 debugger…), notice the hero = Object {id: 12, name: “Narco”} tooltip, and the immediate watch displayed when hovering this._router !

Chrome debugger

Moving to core.js polyfills

After upgrading to latest Angular2 packages, my sample app was not working anymore with IE11. After a bit of search and fiddling, I updated the sample to use polyfills from core.js.

comments edit

This series sample will convert the Tour of heroes sample application from angular.io.

As usual, the source is available on Github here.

This part will finalize the implementation of the Tour of heroes sample.

Changing typescript compiler

I wanted to get rid of the grunt-ts dependency, in order to be able to compile using latest typescript version. This was relatively easy by using grunt-shell, and running tsc with the sources folder :

shell:{
    tsc: 'tsc -p src/ts'
}

Adding service

This part was mainly a copy and paste job from the tutorial with small adaptations : splitting templates and styles into their own files.

Adding routing

Like adding the services, the routing part was again copy and paste

Allowing deep linking

Now that routing is available to the sample application, and HTML5 mode is used (by default), the urls look like http://localhost:59128/detail/16. If the users tries to refresh his browser, a nice 404 will be displayed, as the server as no clue of what file to serve in this case.

Hopefully, url rewriting (and StackOverflow) can allow this scenario. Simply edit your web.config file, to add rewriting for all urls not requesting an existing file, and without dots in it :

<configuration>
  <system.webServer>
    <rewrite>
      <rules>
        <!--http://stackoverflow.com/questions/30945402/url-rewrite-in-asp-net-5 -->
        <rule name="Index Rule" stopProcessing="true">
          <match url=".*" />
          <conditions logicalGrouping="MatchAll">
            <!-- Do not rewrite for files, allow for 404 during dev -->
            <add input="{REQUEST_URI}" matchType="Pattern" pattern="\." negate="true" />
            <!-- Do not rewrite for file existing on disk -->
            <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
          </conditions>
          <action type="Rewrite" url="/index.html" />
        </rule>
      </rules>
    </rewrite>
  </system.webServer>
</configuration>

comments edit

This series sample will convert the Tour of heroes sample application from angular.io.

As usual, the source is available on Github here.

Getting things up and running

Starting from part 1, getting the first part of the tutorial to work was mainly copy and paste job from Hero editor.

I also updated package.json to use latests versions of libs (Angular2 version 2.0.0-beta.8), but ran into a typescript compilation issue :

Compiling...
### Fast Compile >>src/ts/app.component.ts
### Fast Compile >>src/ts/boot.ts
Using tsc v1.7.3
GitHub/Samples.Angular2/Samples.Front/node_modules/angular2/platform/browser.d.ts(77,90): error TS2304: Cannot find name 'Promise'.
GitHub/Samples.Angular2/Samples.Front/node_modules/angular2/src/core/application_ref.d.ts(83,60): error TS2304: Cannot find name 'Promise'.
GitHub/Samples.Angular2/Samples.Front/node_modules/angular2/src/core/application_ref.d.ts(83,146): error TS2304: Cannot find name 'Promise'.
... and so on ...

This was easily fixed, thanks to http://stackoverflow.com/a/35514492/971, just edit boot.ts to reference the typings !

// from : http://stackoverflow.com/a/35514492/971
/// <reference path="../../node_modules/angular2/typings/browser.d.ts" />

import {bootstrap} from 'angular2/platform/browser';
import {AppComponent} from './app.component';

bootstrap(AppComponent);

And everything is now running fine !

Adding the next parts

Adding the Master/details and Multiple components was also a quick copy/paste story.

As I didn’t lile having the css and html hardcoded into the components, I took the opportunity to move them to their own files :

@Component({
    selector: 'my-app',
    moduleId: module.id,
    templateUrl: 'app.component.html',
    styleUrls: ['app.component.css'],
    directives: [HeroDetailComponent]
})

Here you can see a moduleId property. This one is used to not have to hardcode the ‘app’ (module name) in the template and style urls. However, due to an issue with relativeUrl and SystemJS I had to create a shim.d.ts file and reference it in main.ts :

// from : https://github.com/angular/angular/issues/6053
declare var module: any;

Finally, I split the hero module into its own directory, as I like having things neatly organised.