Reputation: 8991
I'm struggling to find a solution to what must be a fairly common problem passing a Visual Studio Team Services (VSTS) release variable into a Single Page Application (SPA) website. There are quite a few moving parts which I'll attempt to explain below.
I have created a release variable ServiceLocations.ApiBaseUri
in VSTS that is unique for each environment (dev/test/stage/prod
) and my end goal is for the value of this variable to be used by a typescript class (~/src/services/ApiService.ts
).
I can't do a text replacement as part of the webpack build because the build output is shared between environments.
I can't inject into the build output because the contents of the ~/src/
dir is transpiled by webpack as part of the build into minified/uglified ES5 bundles with dynamic filenames.
The website is hosted in a ASP.NET Core wrapper, running within IIS, otherwise I could leverage Node's filesystem library to read from a static file.
I'm able to get VSTS to write the value into appsettings.json
at the root of the project (outside wwwroot
) but not sure how the SPA can read this at runtime.
Could anyone please offer any suggestions on a practical approach?
Upvotes: 0
Views: 775
Reputation: 1549
As your SPA is hosted in a ASP.NET Core wrapper I guess you could also retrieve your app setting ApiBaseUri
in your Layout.cshtml
file and create a global js variable with this value.
Let me know if you find some disavantages with this solution.
Upvotes: 0
Reputation: 8991
The VSTS release process provides the ability to substitute variables into a JSON file as part of the IIS Site Deploy task.
We are leveraging this to write the value of ServiceLocations.ApiBaseUri
into a file (~/clientconfig/settings.json
) which has the following initial contents allowing for local development:
{
"ServiceLocations": {
"ApiBaseUri": "https://localhost:44390"
}
}
In the ASP.NET Core Startup.cs
file, we are statically hosting this file so it is available by the SPA:
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(
Directory.GetCurrentDirectory(), "clientconfig")),
RequestPath = "/clientconfig"
});
Then in the SPA's ApiService.ts
we are using fetch to create a HTTP request for the settings file:
fetch("/clientconfig/settings.json", {
method: "GET",
credentials: "omit"
}).then(response => {
return response.json();
}).then(settings => {
this._apiBaseUri = settings.ServiceLocations.ApiBaseUri;
})
Upvotes: 2
Reputation: 3784
When you create or edit the build in VSTS, besides the Tasks tab you also have a Variables tab.
There you can setup your environment variables, including the base api url - that's what we do when we build a react app on VSTS (screenshot from a real build we have)
Then in code you use it like this:
export const baseUrl = process.env.REACT_APP_BASE_API_URL;
This is Javascript, but should be something similar for Typescript.
The only downside is that you will have to have separate build definitions per environments.
Upvotes: 2
Reputation: 968
You could build the project using the --environment="ENV_NAME"
where ENV_NAME"
is the name of the environment you are targetting.
(Note that it has to be registered in the .angular-cli.json
config file under the node environments
)
You can then define different values for the same variable in the various environment file. When building, Angular will use the values from the specified env file using the --environment
flag.
To use the variable you will need to import it from the environment file doing
import { /*Your vars and/or functions */ } from "../../environments/environment";
INDEPENDENTLY from the environment you are targetting.
Upvotes: 1