Как я могу получить доступ к переменным среды в Vue, которые передаются в контейнер во время выполнения, а не во время сборки?
Стек выглядит следующим образом:
Существуют предлагаемые решения для stackoverflow и в других местах для использования файла .env для передачи переменных (и использования режима), но это во время сборки и запекается в образе докера.
Я хотел бы передать переменную во Vue во время выполнения следующим образом:
Я пробовал следующее в helloworld.vue:
<template>
<div>{{displayURL}}
<p>Hello World</p>
</div>
</template>
<script>
export default {
data() {
return {
displayURL: ""
}
},
mounted() {
console.info("check 1")
this.displayURL=process.env.VUE_APP_ENV_MyURL
console.info(process.env.VUE_APP_ENV_MyURL)
console.info("check 3")
}
}
</script>
Я получаю "undefined" в журнале консоли, а на странице helloworld ничего не отображается.
Я также пробовал передать значение в файл vue.config и прочитать его оттуда. Тот же результат "undefined" в console.info
<template>
<div>{{displayURL}}
<p>Hello World</p>
</div>
</template>
<script>
const vueconfig = require('../../vue.config');
export default {
data() {
return {
displayURL: ""
}
},
mounted() {
console.info("check 1")
this.displayURL=vueconfig.VUE_APP_MyURL
console.info(vueconfig.VUE_APP_MyURL)
console.info("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 describe pod
process.env.VUE_APP_MyURL, похоже, не может успешно получить значение.
Для чего это стоит ... Я могу успешно использовать process.env.VUE_APP_3rdURL для передачи значений в приложение Node.js во время выполнения.
FWIW, если у вас есть доступ к файлу, содержащему переменные env, вы можете использовать FileReader API для его анализа
Спасибо @varcorb, я встраиваю код vue в статический html / js
в соответствии с тем, что вы спрашиваете, ответ Хендрика Малкоу делает это, и было очень полезно, что он подробно рассказал, как это добавить. Пожалуйста, отметьте это как правильный ответ! Чтобы быть ясным, у меня есть конфигурационная карта k8s, которая вводится во время выполнения и позволяет мне передавать базовый URL-адрес поверх URL-адреса из process.env
У меня была такая же проблема в моем текущем проекте, и я обнаружил, что в настоящий момент невозможно получить доступ к переменным среды во время выполнения, поэтому я получаю решение создания файлов .env или локальных переменных среды, которые, как вы сказали, используются во время сборки.
Автор этого сообщения объясняет, что нет смысла пытаться передать переменную в статический код html.js. Наконец-то я понял! reddit.com/r/vuejs/comments/8sbosc/…
Создайте файл 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 = "<%= BASE_URL %>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. Вуаля!
где мне разместить config.js и как импортировать конфигурацию, когда я использую ее в коде?
Я просто добавил более подробное объяснение. это помогает?
@HendrikMHalkow Не могли бы вы добавить tree
того, как выглядит структура вашего проекта?
Привет, это решение работает, если объект config
необходимо указать в файле Typescript? Спасибо.
Я добавляю сюда свой рабочий раствор, для тех, у кого все еще возникают проблемы. Я действительно думаю, что ответ @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;'
Это позволяет мне иметь настраиваемый образ во время выполнения, который я могу запускать во многих средах. Я знаю, что это что-то вроде взлома. Но видел, как многие люди поступают так.
Надеюсь, это кому-то поможет.
Привет, @NehaM, я только что добавил более подробное объяснение к предлагаемому мной решению. Надеюсь, это вам поможет. Я рекомендую избегать написания сценариев для вашей точки входа, поскольку это не работает с образами без дистрибутива. Взгляните на github.com/SDA-SE/nginx - изображение NGINX размером менее 6 МБ. Если вы не можете избежать написания сценариев, поместите exec
перед последней командой, чтобы процесс оболочки был заменен вашим процессом nginx.
Спасибо за предложение и за импровизированный ответ. Я все еще использую решение, которое придумал. Я добавил небольшие улучшения в код.
Я заставил его работать с решением, предложенным @Hendrik M Halkow.
Но я сохранил config.js в статической папке. Поступая так, мне не нужно заботиться о том, чтобы файл не уменьшился.
Затем включите это так:
<script src = "<%= BASE_URL %>static/config.js"></script>
и используйте эту конфигурацию монтирования тома:
...
volumeMounts:
- name: config-volume
mountPath: /usr/share/nginx/html/static/config.js
subPath: config.js
В общей папке: общедоступный / config.js
const config = (() => {
return {
"VUE_CONFIG_APP_API": "...",
};
})();
Обновите общедоступный / index.html, чтобы в конце заголовка содержалось следующее:
<!-- docker configurable variables -->
<script src = "<%= BASE_URL %>config.js"></script>
Нет необходимости обновлять vue.config.js, поскольку мы используем общую папку для конфигурации.
ESLint выдал бы нам ошибку использования неопределенной переменной. Поэтому мы определяем глобальную переменную в файле .eslintrc.js:
globals: {
config: "readable",
},
Например. в магазине src / store / user.js
export const actions = {
async LoadUsers({ dispatch }) {
return await dispatch(
"axios/get",
{
url: config.VUE_CONFIG_APP_API + "User/List",
},
{ root: true }
);
},
...
apiVersion: v1
kind: ConfigMap
metadata:
name: fe-config
namespace: ...
data:
config.js: |
var config = (() => {
return {
"VUE_CONFIG_APP_API": "...",
};
})();
apiVersion: apps/v1
kind: Deployment
metadata:
...
spec:
...
template:
...
spec:
volumes:
- name: config-volume
configMap:
name: fe-config
containers:
- ...
volumeMounts:
- name: config-volume
mountPath: /usr/share/nginx/html/config.js
subPath: config.js
Вы встраиваете код vue в статический html / js или запускаете его как
dev
в докере?