1

So I have an application that contains an ASP.NET Core backend and a React frontend (pure static).

In our TFS 2018, we have created a Build that does the following:

  • Get sources from the repo
  • Get Nuget packages (backend)
  • Build the backend
  • Run backend tests
  • Get NPM packages (frontend)
  • Build the frontend
  • Run frontend tests
  • Generate and publish artifacts

Then, a Release pickups those artifacts and deploy them to an Azure AppService (backend) and an Azure Storage v2 account (frontend).

We currently have only one environment, but we need to support multiple ones. The problem is that the frontend build depends on some environment variables which are not present during the build stage. The build doesn't know where is it going to be deployed yet.

So there are a few options here:

  • Generate the frontend build in a Release. This needs a way for the Release to get access to the sources, either via Git or by getting it from an artifact. Latest is really slow because of all the npm_modules.
  • Build should produce builds artifacts for all posible environments and each Release environment will pick up the proper one.

What's the recommended approach to handle this on TFS 2018?

empz
  • 87
  • 2
  • 8

1 Answers1

1

This is a general issue with react apps that is independent of what CI/CD stack you use that is discussed at https://stackoverflow.com/questions/49975735/rendering-an-environment-variable-to-the-browser-in-a-react-js-redux-production

With the Azure family of CI/CD products it is expected you create a release artefact then release that same artefact into environments using a release workflow. That is a typical best practice and expected by ”enterprise” release management processes. The general manifesto of native cloud apps is 12factor.net, and it also advises to ”build once, deploy many times, configured by environment variables”. So its a bit of a surprise to me that the best practices isn't really known in the react community so you have to hunt around for solutions.

In my case at that link above I didn't want to make deployments of our react apps different from our backend microservices where we have ”build once, run anywhere”. So we chanced the js code to fetch env vars from the server at page load. Also with this approach and by using containers we are guaranteed to always run the same front end libraries everywhere even if the front end build tool is misconfigured or buggy in terms of not always using the exact same dependency on every run.

In your case you do have a release workflow where you can use all the same built-in and marketplace tasks of a build workflow. This means its straight forward to add a front-end compile task to the release workflows.

On the downside a frontend build of a large react app can take a lot of time and a lot of memory. Memory probably won't be an issue for you. The time taken will be a little annoying. Yet the approach wouldn't be invasive so I would recommend it may be the least effort to set up and the easiest for colleagues to troubleshoot and maintain in the future as long as you have a stable frontend build. Historically npm was less reliable than other frontend builds at giving the exact same lib versions every run for the same package.json (e.g., npm vs. yarn). So you need to study that aspect and ensure that you are certain that every time you run the frontend build it is guaranteed to use the same exact dependency versions.

simbo1905
  • 1,172
  • 5
  • 14