Angular 2+ - Dynamically change base path of app Angular 2+ - Dynamically change base path of app kubernetes kubernetes

Angular 2+ - Dynamically change base path of app


It took some time but we finally managed to find an easy enough solution to cover all the points we made in the question.

The solution is quite close to the original approach of just building the Angular app offline and copying the content inside an nginx container, mixed with the build process of previously used in the init container.

Our solution then looks as follows. We first build the application offline and inject some recognisable string where the base-href and the deploy-url should be later.

ng build --prod --base-href=http://recognisable-host-name/ --deploy-url=http://recognisable-host-name/

The resulting runtime*.js and the index.html file will contain these inside the code and as the base for assets to load.

Then in the second phase the Dockerfile for a standard Angular application is adapted from

FROM nginx:1.17.10-alpineEXPOSE 80COPY conf/nginx.conf /etc/nginx/conf.d/default.confRUN rm -rf /usr/share/nginx/html/*COPY dist/ /usr/share/nginx/html/

to the new version like this

FROM nginx:1.17.10-alpineEXPOSE 80COPY conf/nginx.conf /etc/nginx/conf.d/default.confRUN rm -rf /usr/share/nginx/html/*COPY dist/ /usr/share/nginx/html/ENV CONTEXT_PATH http://localhost:80ENV ENDPOINT http://localhost/endpointENV VARIABLE foobarCMD \  mainFiles=$(ls /usr/share/nginx/html/main*.js) \  && \  for f in ${mainFiles}; do \    envsubst '${ENDPOINT},${VARIABLE}' < "$f" > "${f}.tmp" && mv "${f}.tmp" "$f"; \  done \  && \  runtimeFiles=$(grep -lr "recognisable-host-name" /usr/share/nginx/html) \  && \  for f in ${runtimeFiles}; do sed -i -E "s@http://recognisable-host-name/?@${CONTEXT_PATH}@g" "$f"; done \  && \  nginx -g 'daemon off;'

Here first we pass the substitutions we would like to make. First the CONTEXT_PATH is the full base path that will replace the http://recognisable-host-name string we injected before, by first finding all the files containing the string and then replacing the it with the sed command.

The other variables that may be environment specific can also be replaced by utilising envsubst and replacing all mentions of those variables from the main*.js files. Therefore the environments.prod.ts is prepared as follows:

export const environment = {    "endpoint": "${ENDPOINT}",    "variable": "${VARIABLE}"}

This takes care of all the main points I raced, namely:

  1. do not share the original code
  2. make a deployment fast
  3. container can be served behind any proxy (e.g. Nginx-Ingress/Kubernetes)
  4. environment variables can be injected

I hope it helps somebody else, especially because as I was researching this topic I found dozens of articles but none met all the criteria or necessitated lots of custom code that is complex or inefficient or hard to maintain.

Edit:

If somebody is interested, I set up a demo project where this solution can be tested:
https://gitlab.com/satanik-angular/base-path-problem