Передача переменной среды в приложение Vue во время выполнения

Как я могу получить доступ к переменным среды в Vue, которые передаются в контейнер во время выполнения, а не во время сборки?

Стек выглядит следующим образом:

  • VueCLI 3.0.5
  • докер
  • Kubernetes

Существуют предлагаемые решения для stackoverflow и в других местах для использования файла .env для передачи переменных (и использования режима), но это во время сборки и запекается в образ докера.

Я хотел бы передать переменную в Vue во время выполнения следующим образом:

  • Создайте Kubernetes ConfigMap (я правильно понял)
  • Передайте значение ConfigMap в переменную env K8s pod при запуске файла развертывания yaml (я правильно понял)
  • Чтение из переменной env, созданной выше, например. VUE_APP_MyURL и сделайте что-нибудь с этим значением в моем приложении Vue (я не понимаю это правильно)

Я попробовал следующее в helloworld.vue:

<template>
<div>{{displayURL}}
  <p>Hello World</p>
</div>
</template>
<script>
export default {  
        data(){
            return{
                displayURL:""
        }
    },
    mounted(){
        console.log("check 1")
        this.displayURL=process.env.VUE_APP_ENV_MyURL
        console.log(process.env.VUE_APP_ENV_MyURL)
        console.log("check 3")
     }
}
</script>

Я возвращаю "undefined" в журнале консоли и ничего не отображается на странице helloworld.

Я также попытался передать значение в файл vue.config и прочитать его оттуда. Тот же "неопределенный" результат в console.log

<template>
<div>{{displayURL}}
  <p>Hello World</p>
</div>
</template>
<script>
const vueconfig = require('../../vue.config');
export default {  
        data(){
            return{
                displayURL:""
        }
    },
    mounted(){
        console.log("check 1")
        this.displayURL=vueconfig.VUE_APP_MyURL
        console.log(vueconfig.VUE_APP_MyURL)
        console.log("check 3")
     }
}
</script>

С vue.config выглядит так:

module.exports = {
    VUE_APP_MyURL: process.env.VUE_APP_ENV_MyURL
}

Если я жестко закодирую значение в VUE_APP_MyURL в файле vue.config, оно будет успешно отображено на странице helloworld.

VUE_APP_ENV_MyURL успешно заполняется правильным значением, когда я его опрашиваю: kubectl description pod

process.env.VUE_APP_MyURL, похоже, не может успешно получить значение.

Для чего это стоит... Я могу успешно использовать process.env.VUE_APP_3rdURL для передачи значений в приложение Node.js во время выполнения.

Ответ 1

У меня была та же проблема в моем текущем проекте, и я обнаружил, что в данный момент невозможно получить доступ к переменным среды, поэтому я в итоге решил создать файлы .env или локальные переменные среды, которые, как вы сказали, используются во время сборки.

Ответ 2

Я добавляю свое рабочее решение сюда для тех, у кого все еще проблемы. Я действительно думаю, что ответ @Hendrik M Halkow более элегантный, хотя мне не удалось решить его с помощью этого, просто из-за моего недостатка опыта в webpack и Vue. Я просто не мог понять, куда поместить конфигурацию файл и как его ссылаться.

Мой подход состоит в том, чтобы использовать переменные окружения с константами (фиктивными значениями), чтобы построить их для production, а затем заменить эти константы в изображении, используя собственный скрипт entrypoint. Решение выглядит следующим образом.

Я инкапсулировал все конфиги в один файл с именем app.config.js

export const clientId = process.env.VUE_APP_CLIENT_ID
export const baseURL = process.env.VUE_APP_API_BASE_URL

export default {
  clientId,
  baseURL,
}

Это используется в проекте просто путем поиска значения в конфигурационном файле.

import { baseURL } from '@/app.config';

Затем я использую стандартные .env. [профиль] файлы для установки переменных среды. например .env.development

VUE_APP_API_BASE_URL=http://localhost:8085/radar-upload
VUE_APP_CLIENT_ID=test-client

Затем для производства я установил строковые константы в качестве значений. например .env.production

VUE_APP_API_BASE_URL=VUE_APP_API_BASE_URL
VUE_APP_CLIENT_ID=VUE_APP_CLIENT_ID

Пожалуйста, не здесь значение может быть любой уникальной строкой. Просто для удобства чтения я просто заменяю имя переменной среды в качестве значения. Это будет просто скомпилировано и упаковано, как в режиме разработки.

В моем Dockerfile я добавляю entrypoint, который может читать эти константы и заменять их значениями переменных среды.

Мой Dockerfile выглядит следующим образом (это довольно стандартно)

FROM node:10.16.3-alpine as builder

RUN mkdir /app
WORKDIR /app

COPY package*.json /app/
RUN npm install

COPY . /app/

RUN npm run build --prod

FROM nginx:1.17.3-alpine

# add init script
COPY ./docker/nginx.conf /etc/nginx/nginx.conf

WORKDIR /usr/share/nginx/html

COPY --from=builder /app/dist/ .

COPY ./docker/entrypoint.sh /entrypoint.sh

# expose internal port:80 and run init.sh
EXPOSE 80

ENTRYPOINT ["/entrypoint.sh"]
CMD ["nginx", "-g", "daemon off;"]

Затем создайте файл ./docker/entrypoint.sh, как показано ниже.

#!/bin/sh

ROOT_DIR=/usr/share/nginx/html

# Replace env vars in JavaScript files
echo "Replacing env constants in JS"
for file in $ROOT_DIR/js/app.*.js* $ROOT_DIR/index.html $ROOT_DIR/precache-manifest*.js;
do
  echo "Processing $file ...";

  sed -i 's|VUE_APP_API_BASE_URL|'${VUE_APP_API_BASE_URL}'|g' $file 
  sed -i 's|VUE_APP_CLIENT_ID|'${VUE_APP_CLIENT_ID}'|g' $file

done

echo "Starting Nginx"
nginx -g 'daemon off;'

Это позволяет мне иметь настраиваемый образ во время выполнения, который я могу запускать во многих средах. Я знаю, что это немного взломать. Но многие люди видели, как это происходит.

Надеюсь, это кому-нибудь поможет.

Ответ 3

Создайте файл config.js с желаемой конфигурацией. Мы будем использовать это позже, чтобы создать карту конфигурации, которую мы развернем в Kubernetes. Поместите его в свой проект Vue.js, где находятся другие ваши файлы JavaScript. Хотя мы исключим его позже из минификации, полезно иметь его там, чтобы инструменты IDE работали с ним.

const config = (() => {
  return {
    "VUE_APP_ENV_MyURL": "...",
  };
})();

Теперь убедитесь, что ваш скрипт исключен из минификации. Для этого создайте файл vue.config.js со следующим содержимым, в котором будет сохранен наш файл конфигурации.

const path = require("path");
module.exports = {
  publicPath: '/',
  configureWebpack: {
    module: {
      rules: [
        {
          test: /config.*config\.js$/,
          use: [
            {
              loader: 'file-loader',
              options: {
                name: 'config.js'
              },
            }
          ]
        }
      ]
    }
  }
}

В вашем index.html добавьте блок скрипта для ручной загрузки файла конфигурации. Обратите внимание, что файл конфигурации не будет там, поскольку мы просто исключили его. Позже мы смонтируем его из ConfigMap в наш контейнер. В этом примере мы предполагаем, что мы будем монтировать его в тот же каталог, что и наш HTML-документ.

<script src="config.js"></script>

Измените свой код, чтобы использовать нашу конфигурацию времени выполнения:

this.displayURL = config.VUE_APP_ENV_MyURL || process.env.VUE_APP_ENV_MyURL 

В Kubernetes создайте карту конфигурации, которая использует содержимое вашего файла конфигурации. Конечно, вы хотите прочитать содержимое из вашего конфигурационного файла.

apiVersion: v1
kind: ConfigMap
metadata:
  ...
data:
  config.js: |
    var config = (() => {
      return {
        "VUE_APP_ENV_MyURL": "...",
      };
    })();

Ссылка на карту конфигурации в вашем развертывании. Это монтирует карту конфигурации в виде файла в ваш контейнер. mountPath уже содержит наш уменьшенный index.html. Мы монтируем файл конфигурации, на который мы ссылались ранее.

apiVersion: apps/v1
kind: Deployment
metadata:
  ...
spec:
  ...
  template:
    ...
    spec:
      volumes:
        - name: config-volume
          configMap:
            name: ...
      containers:
        - ...
          volumeMounts:
                - name: config-volume
                  mountPath: /usr/share/nginx/html/config.js
                  subPath: config.js

Теперь вы можете получить доступ к файлу конфигурации на <Base URL>/config.js, и вы должны увидеть точное содержимое, которое вы поместили в запись ConfigMap. Ваш HTML-документ загружает эту карту конфигурации, так как он загружает остальную часть вашего уменьшенного кода Vue.js. Вуаля!