0

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?

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.

  • Yes, I thought about building the frontend on the release pipeline, but the problem is how to actually get the frontend source into the release pipeline? Release jobs in TFS 2018 doesn't have a "Get Sources" step, so it cannot be fetched from the repo. We could use a command line step and pull the repo from there, but it feels hacky. The other option is publish the frontend src code as an artifact, but the node_modules folder is huge and takes a lot of time to publish. – emzero Jan 31 at 21:45
  • I still don't quite understand what you mean by "we changed the js code to fetch env vars from the server at page load". What's the server in this case? In my case the frontend is just a pure static website. The URL of the API is generated during the build by webpack. As I see it, this solution still needs a way to tell the frontend where to fetch the env. vars. from. – emzero Jan 31 at 21:47
  • A react app is a package.json that webpacks a static site. So just add something like this github.com/simbo1905/react-redux-realworld-example-app/blob/… that repo is a fork of a pure spa single page app with that small express server added to serve up env var and a minor mod to the html page to load a /env.json from that small server. – simbo1905 Jan 31 at 23:16
  • Yeah, I can't use a server. This is hosted as a pure static website in a CDN. No server-side code allowed. – emzero Feb 1 at 13:33
  • @emzero Release pipelines very much do in fact have a way to "get sources" from a Git repo. Add an artifact source that is a linked Git repository and it will perform a fetch on it before the rest of the pipeline starts such that the code artifacts from the Git repo are present. – Sumo Apr 10 at 1:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.