Reputation: 3
I'm having a problem with Angular environment variables and Azure Slots
We want to use an app service providing static Angular files and we also want to use Azure slots to make our deployments safer.
The reasons we want to use slots are:
Our Angular site only serving up static files means that slot deployments require a different build to populate the env.json environment settings differently for each slot.
The solution we're thinking of taking is to create an endpoint in the same Angular website and make a call from the Angular site back to its origin to get its configuration. This way configuration can be set differently in the staging and production slots in Azure and only one Angular build would be required.
We need some server side code to pick up these Azure Application settings and provide them back in an endpoint on the site. We are yet to make a decision about the technology we use to create that endpoint - we are thinking either .Net Core or NodeJs at the moment because they seem to fit well with the Angular product and the development team.
Does anyone have any experience of plugging in a server side component to provide configuration for a previously static Angular website?
Upvotes: 0
Views: 2158
Reputation: 690
I review all the solutions and I created one which are working on the Azure and the local machine also (localhost). It depends to build - prod
(reads from azure) or dev
(reads from local asset folder) the azure slots.
Maybe it helps to somebody.
First you need to add this small php file like Aaron Chen
mentioned.
In the Angular structure under src
folder:
src/appSettings.php
$appSettings = [];
foreach ($_SERVER as $key => $value) {
if(preg_match('/^APPSETTING_/', $key)) {
$appSettings[str_replace('APPSETTING_', '', $key)] = $value;
}
}
header('Content-Type: application/json');
echo json_encode($appSettings, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
Need to modify the angular.json
file. You need to add to assets
the "src/appSettings.php"
"assets": [
"src/favicon.ico",
"src/assets",
"src/appSettings.php"
],
This solution gets all the configuration from azure in the http://<websitename>.azurewebsites.net/appSettings.php
link.
This is working only in the Azure (need authentication). For the local development you need to create a Json file witch are contains all the Azure slots under the src/assets
folder.
`assets/config/backend.json`;
To load the configurations Json need to create
src/app/app.config.ts
import { Injectable } from '@angular/core';
import { HttpClient, HttpBackend } from '@angular/common/http';
import { AppSettings } from './models/AppSettings.model';
import { environment } from 'src/environments/environment';
@Injectable()
export class AppConfig {
static appSettings: AppSettings;
private http: HttpClient;
constructor( handler: HttpBackend) {
this.http = new HttpClient(handler);
}
public load() {
let backendConfigUrl: string;
if (environment.production) {
backendConfigUrl = window.location.origin + '/appsettings.php';
} else {
backendConfigUrl = `assets/config/backend.json`;
}
console.log(backendConfigUrl);
return new Promise<void>((resolve, reject) => {
this.http.get<AppSettings>(backendConfigUrl).toPromise().then((response: AppSettings) => {
AppConfig.appSettings = response;
resolve();
}).catch((response: any) => {
reject(`Could not load file ${backendConfigUrl}: ${JSON.stringify(response)}`);
});
});
}
}
Then modify the src/app/app.module.ts
to load the configuration before the application starts.
export function initializeApp(appConfig: AppConfig) {
return () => appConfig.load().then(() => {
console.log(AppConfig.appSettings)
});
}
providers: [
AppConfig,
{
provide: APP_INITIALIZER,
useFactory: initializeApp,
deps: [AppConfig],
multi: true
},
]
To ng build
loads the config from the local assets
folder. To ng build --prod
reads the config from Azure. Is the same to ng serve
and ng serve --prod
Upvotes: 0
Reputation: 132
Maybe somebody still need it. I propose to stay closer to chosen technology and expose node.js api similar to previous php answer.
I create endpoint http://<websitename>.azurewebsites.net/app-settings
exposed in Azure AppService as following:
Add index.js file into src directory in your Angular code:
var http = require('http');
var server = http.createServer(function (request, response) {
response.writeHead(200, { "Content-Type": "application/json" });
var result = {};
result.someAppSetting = process.env.SomeApplicationSetting;
var jsonResult = JSON.stringify(result);
response.end(jsonResult);
});
var port = process.env.PORT || 1337;
server.listen(port);
console.log("Server exposing api for reading application settings running at http://localhost:%d", port);
So, response contains json with SomeApplicationSetting
app setting retrieved from env vars by process.env.SomeApplicationSetting
. Of course you can have other strategy of exposing variables like adding only some prefixed settings to json or any other.
Add index.js to assets in angular.json:
"assets": [
"src/favicon.ico",
"src/assets",
"src/web.config",
"src/index.js"
],
Then in web.config add following rewrite rule:
<rule name="Read app settings" stopProcessing="true">
<match url="app-settings" />
<action type="Rewrite" url="index.js"/>
</rule>
Upvotes: 1
Reputation: 9950
To achieve your requirement, you can just put the following PHP file to your site root folder. Then send a GET request to endpoint http://<websitename>.azurewebsites.net/appSettings.php
via your Angular app. This will give you a JSON Object that contains all App settings.
appSettings.php
<?php
$appSettings = [];
foreach ($_SERVER as $key => $value) {
if(preg_match('/^APPSETTING_/', $key)) {
$appSettings[str_replace('APPSETTING_', '', $key)] = $value;
}
}
header('Content-Type: application/json');
echo json_encode($appSettings);
Upvotes: 3