在运行时将环境变量传递到Vue应用中

时间:2018-10-26 13:40:26

标签: docker vue.js kubernetes

如何在Vue中访问在运行时而不是在构建过程中传递到容器的环境变量?

堆栈如下:

  • VueCLI 3.0.5
  • Docker
  • Kubernetes

在stackoverflow和其他地方提出了建议的解决方案,以使用.env文件传递变量(以及使用模式),但这是在构建时被烘焙到docker映像中的。

我想在运行时将变量传递给Vue,如下所示:

  • 创建Kubernetes ConfigMap(我正确了)
  • 运行部署yaml文件时,将ConfigMap值传递到K8s pod env变量中(我没错)
  • 从上面创建的env变量读取,例如VUE_APP_MyURL并在我的Vue App中使用该值执行某项操作(我不正确)

我在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.config文件中的VUE_APP_MyURL中,它将成功显示在helloworld页面上。

VUE_APP_ENV_MyURL在查询时已成功填充了正确的值:kubectl describe pod

process.env.VUE_APP_MyURL似乎无法成功检索该值。

对于它的价值...我能够在运行时成功使用process.env.VUE_APP_3rdURL将值传递到Node.js应用中。

5 个答案:

答案 0 :(得分:5)

在我当前的项目中,我遇到了同样的问题,并且发现目前无法在运行时访问环境变量,因此我最终找到了创建.env文件或本地环境变量的解决方案,正如您所说的那样,在构建时使用。

答案 1 :(得分:4)

我在这里添加我的工作解决方案,以帮助那些仍然遇到麻烦的人。我确实认为@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。[profile] 文件设置环境变量。 例如.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;'

这使我拥有可以在许多环境中运行的运行时可配置映像。我知道这有点骇人听闻。但是,已经看到许多人这样做。

希望这对某人有帮助。

答案 2 :(得分:1)

我可以使用@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

答案 3 :(得分:0)

使用所需的配置创建文件config.js

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中,添加脚本块以手动加载文件:

`<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": "...",
      };
    })();

...并在您的部署中使用它:

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

答案 4 :(得分:0)

创建配置文件

在公用文件夹中:different profiles shown in gitKraken

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

更新index.html

更新public/config.js,使其在末尾包含以下内容:

  <!-- docker configurable variables -->
  <script src="<%= BASE_URL %>config.js"></script>

由于我们使用公用文件夹进行配置,因此无需更新vue.config.js。

ESLint

ESLint会给我们使用未定义变量的错误。因此,我们在public/index.html文件中定义了全局变量:

  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 }
    );
  },
...

K8S ConfigMap:

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