
Automating Deployment of Angular Apps
- Posted by John Ackerman
- On April 8, 2018
- 0 Comments
- angular, build, octopus, teamcity
Automating deployment is the easiest way to create a repeatable continuous delivery process. A popular stack for automating deployment of .NET applications includes Git/TFS as source control, TeamCity for automated builds and Octopus Deploy for automating deployments. Using the same process for your Angular front-end applications, unifies your overall deployment process. Here’s how to set up this pipeline for your Angular application.
1.) Angular – Loading Environment Configuration Variables
The first step is to ensure that any environment specific Angular variables are loaded from an external configuration file. This will allow Octopus Deploy to modify these variables as part of the deployment process.
If you used Angular CLI to generate your app, you’ll already have environment specific settings in a path like src\environments\environment.ts. and src\environments\environment.prod.ts. Create a property in these objects called “production” and set as appropriate in each file.
Add a new folder, called “config” in the path src\assets\config. Within this config folder create two json files. Theses files should be called “config.deploy.json” and “config.local.json”.
Each of these files contains a simple JSON object that exposes all of the environment specific variables that your app needs. A common example of this is a base API URL which varies by environment.
The config.local.json file should contain environment variables that allow the app to run in your local environment. An example of this file might look like this.
{ "apiUrl": "http://localhost:20304/", "env": "local" }
The config.deploy.json version, should replace the values in the JSON file with placeholders instead.
{ "apiUrl": "$$apiUrl$$", "env": "$$env$$" }
In order to load configuration values from these files, a new service needs to be created. I generally call this service “app-config.service”. The app config service will import from the environment objects mentioned previously. Based on the value of the “production” property, the app config service will selectively load configuration from the correct config location. Here is the basic structure of the app config service.
import { Injectable } from "@angular/core"; import { Observable } from "rxjs/Rx"; import { environment } from "../environments/environment"; import { Http } from "@angular/http"; @Injectable() export class AppConfig { //config properties go here load() { return new Promise((resolve, reject) => { var url = "assets/config/config.local.json"; if (environment.production) { url = "assets/config/config.deploy.json"; } this.http .get(url) .map((res: any) => res.json()) .catch((error: any) => { console.log("Configuration file could not be read"); resolve(true); return Observable.throw(error.json().error || "Server error"); }) .subscribe((envResponse: any) => { //set the value of config properties here resolve(true); }); }); } constructor(private http: Http) {} }
The meat of the service is contained within the load function, which makes an HTTP request to load the appropriate config file from disk and apply the config settings as needed.
To make use of this service, some modifications need to be made to your app.module. First, import the app config service as usual. Then, create a loading function that will be used to bootstrap the app config service when the application starts up.
export function initConfig(config: AppConfig) { return () => config.load(); }
Then, in the “providers” array, add the following entry to load up your app config service.
{ provide: APP_INITIALIZER, useFactory: initConfig, deps: [AppConfig], multi: true }
Now you can make use of this service in the same was any other Angular service in order to access your environment specific variables. This can be useful even without a deployment pipeline.
2.) Angular – Add nuget package configuration
Create a new file in the root of your project called “package.nuspec”. This file represents the configuration of the nuget package that TeamCity will create for consumption by Octopus Deploy. The full nuspec reference can be found at https://docs.microsoft.com/en-us/nuget/reference/nuspec
The simplest nuget configuration should look like this.
<?xml version="1.0"?> <package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd"> <metadata> <id>AppID</id> <version>1.0</version> <authors>AuthorName</authors> <description>Description</description> </metadata> <files> <file src=".\dist\**" target="" /> </files> </package>
3.) Angular – Create build scripts
Open your package.json file and ensure that the following scripts exist. If they do not, you should add them at this stage.
"scripts": { "ng": "ng", "build": "ng build --prod --aot", }
3.) TeamCity – Create Build Definition
This post assumes that you already know the basics of creating a project in TeamCity, including setting up appropriate build triggers. The general build process follows these steps:
- Run NPM Install to install dependencies
- Run NPM build:prod to create the appropriate dist folder
- Run nuget pack to generate the nuget package in the TeamCity feed.
- Create the build in Octopus Deploy.
Here’s what those steps look like configured in our TeamCity instance.
4.) Octopus Deploy – Setup Deploy Process
The general process we use is to deploy our TeamCity nuget package to our VM that hosts our application, and then execute a file system find & replace to replace the placeholders in our config.deploy.json file as appropriate for our environment. Those two steps look like this.
Use the variable page to set up the correct value of “WebAPIUrl” (and any other relevant environment variables) to complete this setup.
Run It!
That’s the end of the process. At this point, once you kickoff a new build in TeamCity (by checkin or otherwise) you will end up with a fully released new version of your application.
0 Comments