Walkthrough: Tour of Heroes

To illustrate the deployment process, I'll reference the Angular Tour of Heroes tutorial app. A full version is available for download from the Introduction page. Unzip it into a directory named toh.

Navigate into the toh directory and run: npm install

Given that IIS is the target, you likely want the app to function on Internet Explorer as well. This requires a few additional steps. Open toh\src\polyfills.ts and activate all the imports by removing the comment markers. Keep in mind the file comments reference some extra npm packages to install:

npm install --save classlist.js
npm install --save web-animations-js

After the installation completes, you can run the Tour of Heroes app locally with this command:

ng serve

Open your browser to:
http://localhost:4200
The Tour of Heroes app should appear as expected.

Deploy an Angular Application to IIS — figure 1

The Tour of Heroes app is built with the Angular Router, allowing you to switch between the Dashboard and Heroes views. Even though this is a Single Page App, you'll notice the browser's URL updates with each view change. The Angular Router handles all the heavy lifting, making refresh, back navigation, and even direct linking to a view work seamlessly without extra effort.

Configuring Internet Information Services

To simulate a production setup, we'll deploy Tour of Heroes to IIS. Here's what's needed:

Basic Deployment

In a production setting, you won't use ng serve. Instead, perform a production build with:

ng build --prod

This command compiles the app and places the output in the outDir specified in .angular-cli.json, which is toh\dist by default.

All files in this output folder can be copied directly into your web server's root directory, and everything will function correctly. For instance, on my machine, IIS resides at C:\inetpub, making the default web root C:\inetpub\wwwroot. After building, move the contents of the dist folder from your toh project into this wwwroot directory.

Access the app via http://localhost to see the Tour of Heroes dashboard once more. Since IIS defaults to port 80, there's no need to specify a port number this time.

That was straightforward. But what if you need to deploy into a sub-folder on the server?

Sub-folder Deployment

Deploying an Angular Router application to a folder other than the web root adds a layer of complexity.

To keep things clear, empty out your IIS wwwroot folder. Then, create a directory named toh under the web root, resulting in something like C:\inetpub\wwwroot\toh. Transfer the contents of your project's toh\dist folder into this new IIS directory.

Attempting to launch the app by visiting http://localhost/toh/index.html will result in a 404 error in the console.

The base-href Flag

The Angular Deployment documentation discusses the base tag, which informs the Angular app of its deployment location. We'll look at more flexible options later, but for now, let's rebuild Tour of Heroes. This time, we'll use the base-href flag to instruct ng build that the app will live in the toh directory on our server:

ng build --base-href "/toh/" --prod

Once built, move the contents of the toh\dist folder to your IIS wwwroot\toh directory. Visiting http://localhost/toh/index.html should now display the app, allowing you to test the router links by clicking on Dashboard and Heroes.

However, there's a snag. Refreshing the page (e.g., pressing F5) will trigger an error. This happens because IIS is receiving Angular Router paths it’s not configured to process. We must add server configuration to redirect these requests back to our index.html file, allowing the Angular Router to take over.

Server Setup with web.config

The Angular Deployment guide's Server Configuration section mentions this setup, but not in great detail. Here’s a step-by-step guide to making it work.

Inside your project's toh\src folder, create a web.config file with the following rules:

<?xml version="1.0" encoding="utf-8"?>
<configuration>

<system.webServer>
  <rewrite>
    <rules>
      <rule name="Angular Routes" stopProcessing="true">
        <match url=".*" />
        <conditions logicalGrouping="MatchAll">
          <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
          <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
        </conditions>
        <action type="Rewrite" url="./index.html" />
      </rule>
    </rules>
  </rewrite>
</system.webServer>

</configuration>

This configuration isn't Tour of Heroes-specific, apart from setting index.html as the main fallback. Thus, it's reusable for any Angular application.

To ensure this file is part of the build output, we'll add it to the assets array in your project's .angular-cli.json:

"assets": [
    "assets",
    "favicon.ico",
    "web.config"
],

Now, rebuild the application:

ng build --base-href "/toh/" --prod

Confirm that web.config appears in the dist folder. Then, redeploy by copying everything from dist into your IIS wwwroot\toh directory. Navigate to http://localhost/toh/index.html in your browser.

The routing will now work correctly, and refreshing the page will no longer cause issues. Pasting a copied URL into another browser window will also load the correct view. Our Angular Router application now properly supports deep linking as intended.

Wrap-up

The Angular Router is a potent tool for Single Page Apps. While root-level deployment is simple, adding a bit of server configuration allows for flexible deployments to any sub-folder within IIS, making the process just as easy.