3

How to externalize and consume environment variables from a Vue App:

  • Created with VueCLI3
  • Deployed in a docker container
  • Using NGINX

Some details:

The project is built once and deployed to test and live environments. So, I want to externalize some variables which change through the environments (like URLs to call, domains, usernames etc.). The classical usage with .env file variations with VUE_APP_ prefixed does not help this issue as their values are injected in the code during the build stage: They are not variables once it is built.

Trying it out, I have found a blog post making use of dotenv and some extra configuration; but I could not put it together with the configuration in this VueCLI 3 official guide. The solution does not need to adopt a similar approach though, I am just trying to make a way out.

Probably not a useful information, but I am planning to define those environment variables in Config Maps in Kubernetes configuration.

1 Answer 1

3

I think I've accomplished to overcome this case. I am leaving the resolution here.

  1. Define your environment-specific environment variables in .env.development (for development purposes) and add them also to the Pod configuration with correxponding values.

  2. Add a configuration.js file somewhere in your Vue project source folder. It would act as a wrapper for determining whether the runtime is development (local) or production (container). It is like the one shown here, but importing/configuring dotenv is not required:

    export default class Configuration {
      static get EnvConfig () {
        return {
          envKey1: '$ENV_KEY_1',
          envKey2: '$ENV_KEY_2'
        }
      }
    
      static value (key) {
        // If the key does not exist in the EnvConfig object of the class, return null
        if (!this.EnvConfig.hasOwnProperty(key)) {
          console.error(`Configuration: There is no key named "${key}". Please add it in Configuration class.`)
          return
        }
    
        // Get the value
        const value = this.EnvConfig[key]
    
        // If the value is null, return
        if (!value) {
          console.error(`Configuration: Value for "${key}" is not defined`)
          return
        }
    
        if (!value.startsWith('$VUE_APP_')) {
          // value was already replaced, it seems we are in production (containerized).
          return value
        }
    
        // value was not replaced, it seems we are in development.
        const envName = value.substr(1) // Remove $ and get current value from process.env
        const envValue = process.env[envName]
    
        if (!envValue) {
          console.error(`Configuration: Environment variable "${envName}" is not defined`)
          return
        }
    
        return envValue
      }
    }
    
    
  3. Create an entrypoint.sh. With some modification, it would look like follows:

    #!/bin/bash
    
    function join_by { local IFS="$1"; shift; echo "$*"; }
    
    # Find vue env vars
    vars=$(env | grep VUE_APP_ | awk -F = '{print "$"$1}')
    vars=$(join_by ',' $vars)
    echo "Found variables $vars"
    
    for file in /app/js/app.*;
    do
      echo "Processing $file ...";
    
      # Use the existing JS file as template
      cp $file $file.tmpl
      envsubst "$vars" < $file.tmpl > $file
      rm $file.tmpl
    done
    
    nginx -g 'daemon off;'
    
  4. In your Dockerfile, add a CMD for running this entrypoint.sh script above as a bootstrapping script during container creation. So that, every time you start a container, it will get the environment variables from the pod configuration and inject it to the Configuration class shown in Step 2.

    # build stage
    FROM node:lts-alpine as build-stage
    
    # make the 'app' folder the current working directory
    WORKDIR /app
    
    # Copy package*.json and install dependencies in a separaate step to enable caching
    COPY package*.json ./
    RUN npm install
    
    # copy project files and folders to the current working directory
    COPY ./ .
    
    # install dependencies and build app for production with minification
    RUN npm run build
    
    # Production stage
    FROM nginx as production-stage
    
    RUN mkdir /app
    
    # copy 'dist' content from the previous stage i.e. build
    COPY --from=build-stage /app/dist /app
    
    # copy nginx configuration
    COPY nginx.conf /etc/nginx/nginx.conf
    
    # Copy the bootstrapping script to inject environment-specific values and pass it as argument current to entrypoint
    COPY entrypoint.sh entrypoint.sh
    
    # Make the file executable
    RUN chmod +x ./entrypoint.sh
    
    CMD ["./entrypoint.sh"]
    
    

Finally, instead of process.env use our wrapper configuration class like Configuration.value('envKey1'). And voila!

Sign up to request clarification or add additional context in comments.

Comments

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.