Ofcourse I want to follow the 12 factor app rules as much as possible, and ofcourse I also want to deploy my apps in Cloud Foundry.
When it comes to https://12factor.net/config (Store config in the environment) and an Angular app this becomes sort of a problem. The most obvious buildpack to use for Angular is the staticfile buildpack, but since it only serves static content there is no way to get to the environment variables you set with your Cloud Foundry app.
Or is there...
The staticfile buildpack is using nginx for its webengine, so maybe that could solve something? Well, turns out that nginx in a CF buildpack can be tricked to spit out environment vars.. by adding this to the config:
location /inject {
default_type application/json;
return 200 '<%= ENV["INJECT"] %>';
}
And the staticfile buildpack configuration allows us to add custom location parts in the nginx config, see here: https://docs.cloudfoundry.org/buildpacks/staticfile/index.html. So I set out to test this...
My app folder looks like this:
The staticfile contains only this:
root: public
location_include: includes/*.conf
Lets test this with a simple cf push static
aaaaaannnnnd..
close, but no sigar..
Turns out the location is included in the nginx config this way:
{{if ne .LocationInclude ""}}
include {{.LocationInclude}};
{{end}}
(here: https://github.com/cloudfoundry/staticfile-buildpack/blob/master/src/staticfile/finalize/data.go)
Which apparently does not get evaluated this way.
Next thing to try is to fork the staticfile_buildpack repo and directly edit the data.go
to include my location part:
location /inject {
default_type application/json;
return 200 '<%= ENV["INJECT"] %>';
}
This angular-buildpack repo can be used directly to push your apps to CF this way:
cf push static -b https://github.com/floreseken/angular-buildpack
Annnnnnddddd:
Success!! There is one downside to this, you need an online connection. In a next post I'll try to build this into an offline buildpack.
Now, a nice trick to get these values into Angular (or any other SPA for that matter) without a delaying network call is to use the power of [SSI].(https://nl.wikipedia.org/wiki/Server_Side_Includes)
SSI can be enabled in the buildpack with a Staticfile
in the root of the deployment, with this content:
ssi: enabled
Now edit the index.html
file of your Angular app to include this:
<html>
<head>
<script type="text/javascript">window["INJECT"] =
<!--#include virtual="/inject" -->
</script>
This will render this way:
Awesome!!! The Enviroment variables set with my Cloud Foundry app directly available in javascript. What more could you wish for..
Oh yeah.. an offline buildback maybe.. but remember you could also host this repo on-premise.. the changes are minimal