在运行时将环境变量传递到Vue App

Joh*_*ann 19 docker vue.js kubernetes

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

堆栈如下:

  • VueCLI 3.0.5
  • 搬运工人
  • Kubernetes

有关stackoverflow和其他地方的建议解决方案,使用.env文件传递变量(和使用模式),但这是在构建时,并被烘焙到docker镜像中.

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

  • 创建Kubernetes ConfigMap(我明白了)
  • 运行部署yaml文件时,将ConfigMap值传递给K8s pod env变量(我明白了)
  • 从上面创建的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>
Run Code Online (Sandbox Code Playgroud)

我在控制台日志中找回"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>
Run Code Online (Sandbox Code Playgroud)

vue.config看起来像这样:

module.exports = {
    VUE_APP_MyURL: process.env.VUE_APP_ENV_MyURL
}
Run Code Online (Sandbox Code Playgroud)

如果我将值硬编码到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应用程序.

Hen*_*kow 31

config.js使用所需的配置创建一个文件。我们稍后将使用它来创建我们部署到 Kubernetes 的配置映射。将它放入您的 Vue.js 项目中,其他 JavaScript 文件所在的位置。虽然我们稍后会从缩小中排除它,但将它放在那里是有用的,以便 IDE 工具可以使用它。

const config = (() => {
  return {
    "VUE_APP_ENV_MyURL": "...",
  };
})();
Run Code Online (Sandbox Code Playgroud)

现在确保您的脚本被排除在缩小之外。为此,请使用以下内容创建一个文件 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'
              },
            }
          ]
        }
      ]
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

在 index.html 中,添加一个脚本块以手动加载配置文件。请注意,配置文件将不存在,因为我们只是将其排除在外。稍后,我们会将它从 a 挂载ConfigMap到我们的容器中。在这个例子中,我们假设我们将把它挂载到与 HTML 文档相同的目录中。

<script src="<%= BASE_URL %>config.js"></script>
Run Code Online (Sandbox Code Playgroud)

更改您的代码以使用我们的运行时配置:

this.displayURL = config.VUE_APP_ENV_MyURL || process.env.VUE_APP_ENV_MyURL 
Run Code Online (Sandbox Code Playgroud)

在 Kubernetes 中,创建一个使用配置文件内容的配置映射。当然,您想从配置文件中读取内容。

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

在您的部署中引用配置映射。这会将配置映射作为文件安装到您的容器中。在mountPath已经包含了我们的minified的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
Run Code Online (Sandbox Code Playgroud)

现在您可以访问配置文件,<Base URL>/config.js您应该会看到您放入 ConfigMap 条目的确切内容。您的 HTML 文档会加载该配置映射,因为它会加载您缩小的 Vue.js 代码的其余部分。瞧!

  • 你好,如果需要在 Typescript 文件中引用 `config` 对象,这个解决方案是否有效?谢谢。 (3认同)

Neh*_*haM 17

我在这里添加我的工作解决方案,供那些仍然有问题的人使用。我确实认为@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,
}
Run Code Online (Sandbox Code Playgroud)

只需从配置文件中查找值即可在项目中使用它。

import { baseURL } from '@/app.config';
Run Code Online (Sandbox Code Playgroud)

然后我使用标准的.env.[profile]文件来设置环境变量。例如.env.development

VUE_APP_API_BASE_URL=http://localhost:8085/radar-upload
VUE_APP_CLIENT_ID=test-client
Run Code Online (Sandbox Code Playgroud)

然后对于生产,我将字符串常量设置为值。例如.env.production

VUE_APP_API_BASE_URL=VUE_APP_API_BASE_URL
VUE_APP_CLIENT_ID=VUE_APP_CLIENT_ID
Run Code Online (Sandbox Code Playgroud)

请不要在这里该值可以是任何唯一的字符串。为了保持可读性更容易,我只是将环境变量名称替换为值。这将像开发模式一样被编译和捆绑。

在 my 中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;"]

Run Code Online (Sandbox Code Playgroud)

然后创建一个./docker/entrypoint.sh文件,如下所示。

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

export default {
  clientId,
  baseURL,
}
Run Code Online (Sandbox Code Playgroud)

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

希望这可以帮助某人。

  • 嗨@NehaM,我刚刚为我提出的解决方案添加了一些更详细的解释。我希望它对你有帮助。我建议避免编写入口点脚本,因为它不适用于 distroless 图像。看一下 https://github.com/SDA-SE/nginx – 一个小于 6MB 的 NGINX 镜像。如果您无法避免编写脚本,请在最后一个命令之前放置一个 exec ,以便 shell 进程将被您的 nginx 进程替换。 (2认同)

Sch*_*ltz 11

创建配置文件

在公共文件夹中:public/config.js

const config = (() => {
  return {
    "VUE_CONFIG_APP_API": "...",
  };
})();
Run Code Online (Sandbox Code Playgroud)

更新index.html

更新public/index.html以在头部末尾包含以下内容:

  <!-- docker configurable variables -->
  <script src="<%= BASE_URL %>config.js"></script>
Run Code Online (Sandbox Code Playgroud)

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

ESLint

ESLint 会给我们使用未定义变量的错误。因此我们在.eslintrc.js文件中定义全局变量:

  globals: {
    config: "readable",
  },
Run Code Online (Sandbox Code Playgroud)

用法

例如。在商店 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 }
    );
  },
...
Run Code Online (Sandbox Code Playgroud)

K8S 配置图:

apiVersion: v1
kind: ConfigMap
metadata:
  name: fe-config
  namespace: ...
data:
  config.js: |
    var config = (() => {
      return {
        "VUE_CONFIG_APP_API": "...",
      };
    })();
Run Code Online (Sandbox Code Playgroud)

部署

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
Run Code Online (Sandbox Code Playgroud)


Jos*_*lva 5

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

  • 这篇文章的作者解释说,尝试将变量传递到静态 html.js 代码中是没有意义的。我终于明白了!https://www.reddit.com/r/vuejs/comments/8sbosc/how_to_access_environment_variables_passed_to_a/ (2认同)