2

Having read the Quasar framework's description for Handling process.env, I understand that it is possible to add environment variables when building the application for development or production.

You can even go one step further. Supply it with values taken from the quasar dev/build env variables:

// quasar.config.js
build: {
  env: {
    FOO: process.env.FOO,
  }
}

Then, I can use that variable by using process.env.FOO.

For staging and production, however, I'm building a Docker image which runs an NGINX serving the final dist/spa folder. I'd like to pass an environment variable when deploying the application, so that I can configure the FOO variable depending on its value in the docker-compose.yml:

// staging
services:
  image: my-quasar-image
  environment:
    FOO: "STAGING"

// production
services:
  image: my-quasar-image
  environment:
    FOO: "PROD"

I have found some blog post which mentions that you could create a custom entrypoint.sh for the Docker image which reads env variables and adds them to the window object but I wonder if there might be a more "elegant" solution.

The primary question is: Is it possible to pass in (Docker) environment variables before the application starts and which are then available on process.env?

1 Answer 1

2

This is how I sorted my requirement that works perfectly for my use case. A quick review of what I wanted to do: Be able to pass in environment variables via a docker-compose file to a Vue.js application to allow different team members to test different development APIs depending on their assignment(localhost if running the server locally, api-dev, api-staging, api-prod).

Update public/index.html to contain following at the head:

<script>
   // CONFIGURATIONS_PLACEHOLDER
</script>

There is no need to update vue.config.js as we are using the public folder for configuration.

Create new file env.js to consume runtime variables (keep it inside src folder)

export default function getEnv(name) {
    return window?.configs?.[name] || process.env[name];
}

Create new bash file set-env-variable.sh in the root folder of the app.

#!/bin/sh
JSON_STRING='window.configs = { \
  "VUE_APP_VAR1":"'"${VUE_APP_VAR1}"'", \
  "VUE_APP_VAR2":"'"${VUE_APP_VAR2}"'" \
}'
sed -i "s@// CONFIGURATIONS_PLACEHOLDER@${JSON_STRING}@" /usr/share/nginx/html/index.html
exec "$@"

Update docker file (assuming it's in the root folder of your vue app)

# build stage
FROM node:lts-alpine as build-stage
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build

# production stage
FROM nginx:stable-alpine as production-stage
COPY --from=build-stage /app/dist /usr/share/nginx/html

COPY ./set-env-variable.sh /docker-entrypoint.d
RUN chmod +x /docker-entrypoint.d/set-env-variable.sh
RUN dos2unix /docker-entrypoint.d/set-env-variable.sh

EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

Deployment

vue-app:
    ....
    volumes:
      - "./nginx/templates/:/etc/nginx/templates/"
    environment:
      VUE_APP_VAR1: my-app
      VUE_APP_VAR2: 8080

Consuming variables in vue app

import getEnv from "./service/env.js";
var myVar = getEnv("VUE_APP_VAR1");
Sign up to request clarification or add additional context in comments.

4 Comments

This feels very dirty, putting these variables into the index.html head. They become exposed to everyone, no longer secret. Could you use a similar method and either build an .env file or fill an empty existing .env file? At least that file isn't exposed to the end user.
There is no way to secure variables for frontend web applications. If it's available to the end-user's browser in javascript then it cannot be reliably secured.
Not sure how this is supposed work. The shell script (where the env-vars are being set to the index.html) is executed on build step, but the values of the env vars are passed to the dockerfile later at run time. Am I missing something here? When doing exactly as shown above, the variables are empty.
ok i figured it out and made it work: Like I said, as the script is in the answer above, the variables are taken from the build environment and populated into the index.html. But we want to inject them at runtime. So how did it work for me? here is what I changed: Instead of executing the shell script in the dockerfile, I've set it as CMD for when the dockerfile gets executed. CMD ["/docker-entrypoint.d/set-env-variables.sh"] In the shell script I've added the line nginx -g 'daemon off;' as we still want to run nginx. this can also be added to the CMD block. might be cleaner.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.