Convert your .NET Core with Angular SPA app to an NX environment


Interested in joining the big guys by adding NX to your .NET Core Angular App?

Here's a complete step-by-step guide that will show you exactly how to integrate .NET Core, Angular and NX (Nrwl Extensions)

Say.

With the growing power and fame of the .NET Core framework and Angular some awesome possibilities are blooming.

One of these is .NET Core's support for Angular.

Just take the .NET Core CLI and the only thing you gotta bang into that keyboard is...

dotnet new angular -o MyNextAwesomeApp

...and BOOM! It generates a simple .NET Core API server as well as an Angular SPA with amazing server-side rendering, auth options, and more.

Hot stuff if you want to know my opinion.

But what if we want to do better? And use NX to manage our Angular app(s)?

I mean, why not? All the other big guys like...

  • American Airlines
  • Microsoft
  • RedHat
  • FedEx
  • Cisco
  • Audi

...and all kinds of other cool kids are using it.

So how do we install and use NX with a .NET Core Angular SPA app?

Pre-requisites

An ASP.Net Core project with Angular SPA.

How to Install NX

Assuming that the ASP.NET Core Angular app has already been created the next step is to verify our Angular version.

  • Open your project in a terminal and cd into the ClientApp directory.
  • Type ng --version to check your global Angular version.

With NX you must install the NX version that matches the major version of your global Angular CLI. So head over to package repository and find the version you want. Then type the following command.

ng add @nrwl/package@cli.version.number

Fix the imports

The installer tries it's best to update your angular.json file but I found that it really messed my config up so I had to do some manual editing.

Basically all you should need to do is update the broken imports.

Here's a fixed angular.json example.

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "version": 1,
  "newProjectRoot": "projects",
  "projects": {
    "MyAwesomeProject": {
      "root": "apps/MyAwesomeProject",
      "sourceRoot": "apps/MyAwesomeProject/src",
      "projectType": "application",
      "prefix": "app",
      "schematics": {},
      "architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:browser",
          "options": {
            "progress": false,
            "extractCss": true,
            "outputPath": "dist",
            "index": "apps/MyAwesomeProject/src/index.html",
            "main": "apps/MyAwesomeProject/src/main.ts",
            "polyfills": "apps/MyAwesomeProject/src/polyfills.ts",
            "tsConfig": "apps/MyAwesomeProject/tsconfig.app.json",
            "assets": ["apps/MyAwesomeProject/src/assets"],
            "styles": [],
            "scripts": []
          },
          "configurations": {
            "production": {
              "fileReplacements": [
                {
                  "replace": "apps/MyAwesomeProject/src/environments/environment.ts",
                  "with": "apps/MyAwesomeProject/src/environments/environment.prod.ts"
                }
              ],
              "optimization": true,
              "outputHashing": "all",
              "sourceMap": false,
              "extractCss": true,
              "namedChunks": false,
              "aot": true,
              "extractLicenses": true,
              "vendorChunk": false,
              "buildOptimizer": true
            }
          }
        },
        "serve": {
          "builder": "@angular-devkit/build-angular:dev-server",
          "options": {
            "browserTarget": "MyAwesomeProject:build"
          },
          "configurations": {
            "production": {
              "browserTarget": "MyAwesomeProject:build:production"
            }
          }
        },
        "extract-i18n": {
          "builder": "@angular-devkit/build-angular:extract-i18n",
          "options": {
            "browserTarget": "MyAwesomeProject:build"
          }
        },
        "test": {
          "builder": "@angular-devkit/build-angular:karma",
          "options": {
            "main": "apps/MyAwesomeProject/src/test.ts",
            "polyfills": "apps/MyAwesomeProject/src/polyfills.ts",
            "tsConfig": "apps/MyAwesomeProject/src/tsconfig.spec.json",
            "karmaConfig": "apps/MyAwesomeProject/src/karma.conf.js",
            "styles": ["apps/MyAwesomeProject/src/styles.css"],
            "scripts": [],
            "assets": ["apps/MyAwesomeProject/src/assets"]
          }
        },
        "lint": {
          "builder": "@angular-devkit/build-angular:tslint",
          "options": {
            "tsConfig": ["apps/MyAwesomeProject/tsconfig.app.json", "apps/MyAwesomeProject/tsconfig.spec.json"],
            "exclude": ["**/node_modules/**"]
          }
        },
        "server": {
          "builder": "@angular-devkit/build-angular:server",
          "options": {
            "outputPath": "dist-server",
            "main": "apps/MyAwesomeProject/src/main.ts",
            "tsConfig": "apps/MyAwesomeProject/tsconfig.server.json"
          },
          "configurations": {
            "dev": {
              "optimization": true,
              "outputHashing": "all",
              "sourceMap": false,
              "namedChunks": false,
              "extractLicenses": true,
              "vendorChunk": true
            },
            "production": {
              "optimization": true,
              "outputHashing": "all",
              "sourceMap": false,
              "namedChunks": false,
              "extractLicenses": true,
              "vendorChunk": false
            }
          }
        }
      }
    },
    "MyAwesomeProject-e2e": {
      "root": "apps/MyAwesomeProject-e2e/",
      "projectType": "application",
      "architect": {
        "e2e": {
          "builder": "@angular-devkit/build-angular:protractor",
          "options": {
            "protractorConfig": "apps/MyAwesomeProject-e2e/protractor.conf.js",
            "devServerTarget": "MyAwesomeProject:serve"
          }
        },
        "lint": {
          "builder": "@angular-devkit/build-angular:tslint",
          "options": {
            "tsConfig": "apps/MyAwesomeProject-e2e/tsconfig.e2e.json",
            "exclude": ["**/node_modules/**"]
          }
        }
      }
    }
  },
  "defaultProject": "MyAwesomeProject"
}

Conclusion

Not bad! Not bad my friend! You've made a great choice by installing NX.

Interested in going further? There's a great demo app here.

Questions or comments? Don't hesitate to contact me.

Angular Consultant & Freelancer