Configurable frontend apps with docker and env-serve

Photo by Laurent Perren on Unsplash

Recently everyone speaks about Docker. There is a lot of articles on the web which in brief saying how docker helps scaling, sharing and running backend apps, but what about frontend?

First big disadvantage and difference between backend and frontend is that backend, even after build to some executable, is still application. You can run it and control from outside by parameters or environment variables passed on the initial phase while frontend application is only a bunch of static files served by other app, mostly server like Nginx or Apache.

For better understanding what problem we discuss let’s say you put a variable color in index.js file which holds a primary color for UI components. When you have single version of app this is not a problem, you can change variable and it’ll affect whole interface in every app version. But it becomes a problem when app could be running at the same time in many color variants.

Let’s assume you have “Client A” and “Client B”. Client A uses green variant of your app, but here comes Client B and says “App looks great, but hey! My logo is red, I want to have your tool in my company colors!”.
Client A is good with green, Client B wants red. At this moment, for the purposes of experiment, we assuming that app will be served on two different ports for each client and client can’t switch between color schemes dynamically. In this situation you may think “Okay, we’ll build conditionally basing on env variables” — and it’s great move! Let’s do this, something like: EXPORT PRIMARY_COLOR=red; node scripts/build.js

Then in your build.js file:

Seems legit, it works. Now you can build your frontend app in two different color variants. But there are also disadvantages of above solution:

  • It can’t be changed without rebuild whole app
  • when it comes to run app in docker, you also need to install all dependencies and after that again rebuild app , in brief — it takes a lot of time to build version with only one, small change in color variable

above problems are aftermath of mentioned at the beginning difference: frontend apps are only bunch of static files, you can not communicate with them at runtime like with other apps.

According to this problem I wrote small server called env-serve which helps you configure frontend apps on runtime, it may be useful especially when you work with docker.

Example app with docker

Full code available on GitHub: https://github.com/dawiidio/env-serve-example

For the beginning let’s take a look on the Dockerfile:

What are we doing here:

  1. declare custom env vars
  2. copy app source code from host to container
  3. install dependencies, env-serve then build app
  4. expose app port (default 3000)
  5. change directory do app/src . In real app it would be directory with output from bundler eg. app/dist
  6. and set env-serve as entrypoint

to work with env-serve you need also entry file, eg. index.html . One important thing to remember about entry file — it must contains initial shape of config object, like:

<script>
window.appConfig = {
"CLIENT_NAME": "Client A",
"PRIMARY_COLOR": "green"
};
</script>

env-serve will be looking for window.appConfig in entry file and then will try match it’s keys with env vars, if it finds for example CLIENT_NAME then replace it’s initial value with value provided in the env var. If eg.PRIMARY_COLOR wasn’t provided then it stays untouched.

Above configuration gives you ability to build your frontend once, and then configure on runtime, just like backend apps. Thanks to this you can run many variants of your app faster.

# build it once
docker build -t frontend:latest .
# then run many different variants in seconds without rebuild
docker run -p 3000:3000 -e CLIENT_NAME="Client A" frontend:latest
docker run -p 3001:3000 -e CLIENT_NAME="Client B" frontend:latestdocker run -p 3002:3000 -e CLIENT_NAME="Client C" frontend:latest

I wrote a small docker-compose.yaml to put both version together and run by single docker-compose up command

I have a few lines of JS in my index.html to pull informations from data passed by env-serve to my initial config declared also in the same file. Here’s content of it

How you can see above, I’ve declared shape of my config, then I pulls needed informations from it and basing on them customize interface. Simple :)

After run docker-compose up I can see something like this in console:

And this the final result in my browser, after open localhost on declared in docker-compose.yaml ports.

When you shouldn’t use env-serve?

There are some cases, which still should be done on the build phase. For example: if client A asks you for feature X but client B shouldn’t see it, probably because he don’t pay for it, you should add some env variable and join feature code conditionally basing on it, also you shouldn’t put any sensitive data to config (eg. passwords) because anyone can see it.

Summary

We discussed main difference between built backend and frontend, how it affects further work with Docker and in general how it may complicate process of adjusting and delivering app for many different clients . We also tried solution called env-serve which addresses some of the problems.

If you have any problems or suggestions please let me know here or on twitter https://twitter.com/Caridina_multid :)

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Dawid Wojda

Engineer (Wizard) 🧙Ex CEO and CTO, now mostly programming and frontend. My spirit animal is mix of cat, Moss Maurice and Geralt of Rivia