1. 概述
现代 Web 应用通常需要在不修改代码的前提下灵活适应不同环境。对于许多 Vue.js 开发者来说,在运行时修改 API 密钥或基础 URL 等设置非常关键。因为默认情况下,环境变量是打包进构建产物中的,这限制了灵活性。
本文将探讨如何在 Vue 应用中运行时传递环境变量。我们会演示一个实用方案,动态注入这些变量,并配置应用读取它们。
2. 前置条件
开始之前,需准备好以下组件:
- 已安装 Node.js 和 npm 或 yarn
- 已安装 Docker 和 Docker Compose
- 已注册 ExchangeRate API Key 用于运行货币转换项目
准备好后,我们就可以开始了。
3. 理解 Vue.js 中的运行时环境变量
Vue.js 与大多数前端框架一样,在构建时处理环境变量。应用构建时,*.env* 文件或 process.env
中的值会被直接嵌入到 JavaScript 打包文件中。这意味着在不重新构建应用的前提下,这些值无法更改。
这种机制在需要动态配置时会成为限制。例如,API 的基础 URL 或密钥可能在不同环境(开发、测试、生产)之间变化。如果这些变量是在构建时固定的,每次更改都需要重新构建和部署,效率低下且耗时。
此外,这种做法在多环境部署时也缺乏灵活性。设想将同一个应用部署到多个服务器上,每个服务器配置不同,若不能在运行时调整变量,会增加部署流程的复杂性。
4. 构建运行时环境配置
为了让 Vue.js 应用支持动态配置,我们需要一种机制,在运行时注入环境变量,而不是在构建时嵌入。我们可以通过生成、提供和集成运行时变量的设置来实现这一点。
这个方案主要涉及三个文件:config.js、entrypoint.sh 和 nginx.conf。在深入这些文件之前,我们先搭建一个基础项目,包含实现所需的基础文件和配置。
4.1. 克隆基础项目
首先,克隆基础项目仓库,它包含一个简单的 Vue.js 项目——一个货币转换器应用:
$ git clone https://github.com/Baeldung/ops-tutorials.git
进入项目目录:
$ cd ops-tutorials/docker-modules/passing-env-vars-to-vue-app-at-runtime/vue-env-vars-starter
安装依赖:
$ npm install
或
$ yarn install
运行 npm run dev
,在浏览器中访问 http://localhost:5173 验证本地环境是否正常工作。
4.2. 创建 config.js 文件
config.js
是运行时变量的来源。与构建时注入不同,这个文件在运行时动态生成,以反映当前环境。
在项目 public 目录下创建该文件:
$ touch public/config.js
打开文件,添加如下内容:
window.config = {};
这样即使变量尚未注入,应用也能正常加载。
接下来,在 index.html 中引用这个文件。打开 index.html,在 </body>
标签前插入以下脚本:
<script src="/config.js"></script>
这样每次访问应用时,都会加载 config.js。
4.3. 创建和配置 entrypoint.sh 文件
entrypoint.sh
脚本用于在运行时将环境变量动态注入到 config.js 中。这种灵活性使得应用可以在不同环境(如开发、测试、生产)中运行,而无需重新构建。
在项目根目录创建该文件:
$ touch entrypoint.sh
打开文件并添加以下内容:
#!/bin/sh
# config.js 文件路径
CONFIG_FILE=/usr/share/nginx/html/config.js
# 替换 config.js 中的占位符
echo "生成运行时配置文件 $CONFIG_FILE"
cat <<EOF > $CONFIG_FILE
window.config = {
VUE_APP_API_URL: "${VUE_APP_API_URL:-undefined}"
};
EOF
# 启动 Nginx
nginx -g "daemon off;"
这个脚本完成了几个关键功能:
- 定义了 config.js 的路径(位于 Nginx 服务目录中)
- 使用
cat
命令将运行时变量写入 config.js - 占位符
${VUE_APP_API_URL:-undefined}
会使用环境变量值,若未设置则为undefined
- 最后启动 Nginx,并以前台模式运行
4.4. 配置 nginx.conf
nginx.conf 是另一个关键配置文件。它确保 Nginx 正确提供 Vue.js 应用和动态生成的 config.js,并正确处理客户端路由。
在项目根目录创建该文件:
$ touch nginx.conf
添加如下配置:
worker_processes 1;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name localhost;
# 提供主应用
location / {
root /usr/share/nginx/html;
index index.html;
try_files $uri /index.html;
}
# 提供 config.js
location /config.js {
root /usr/share/nginx/html;
default_type application/javascript;
}
}
}
这段配置优化了 Nginx 性能:
- 设置 worker 进程和连接数
- 第一个
location
块确保所有请求都通过index.html
处理,这对 Vue.js 客户端路由至关重要 - 第二个
location
块确保 config.js 作为 JavaScript 文件提供,以便应用在运行时加载使用
下一节我们将手动测试环境变量注入。
5. 手动注入环境变量
在容器化应用之前,我们先在本地环境中测试运行时变量注入功能。
5.1. 准备环境
在项目根目录创建 .env 文件:
$ touch .env
添加如下内容:
VUE_APP_API_URL=https://v6.exchangerate-api.com/v6/API_KEY/latest/USD
这个变量将在运行时注入到应用中。
5.2. 运行 entrypoint.sh 脚本
现在使用 entrypoint.sh 脚本生成包含环境变量的 config.js 文件。
在运行前,需将 entrypoint.sh 中的 CONFIG_FILE 路径临时改为 ./public/config.js
,因为本地测试时 /usr/share/nginx/html/config.js
不存在。
修改如下:
CONFIG_FILE=./public/config.js
然后赋予脚本执行权限:
$ chmod +x entrypoint.sh
导出环境变量:
$ export VUE_APP_API_URL=https://v6.exchangerate-api.com/v6/API_KEY/latest/USD
运行脚本:
$ ./entrypoint.sh
脚本会在 public 目录下生成 config.js 文件。查看其内容应如下:
window.config = {
VUE_APP_API_URL: "https://v6.exchangerate-api.com/v6/API_KEY/latest/USD"
};
确认无误后,记得将 CONFIG_FILE 路径改回 /usr/share/nginx/html/config.js
再进行容器化操作。
6. 容器化应用
完成运行时环境配置后,现在我们将其容器化。
6.1. 创建 Dockerfile
Dockerfile 定义了将 Vue.js 应用构建并打包为容器的指令。我们将使用多阶段构建以减小最终镜像大小。
创建 Dockerfile:
$ touch Dockerfile
添加如下内容:
# 构建阶段
FROM node:18-alpine as build-stage
RUN apk add --no-cache python3 make g++
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
# 生产阶段
FROM nginx:stable-alpine as production-stage
WORKDIR /usr/share/nginx/html
COPY --from=build-stage /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/nginx.conf
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
EXPOSE 80
CMD ["/entrypoint.sh"]
多阶段构建确保最终镜像只包含生产所需文件,优化大小和性能。
6.2. 配置 docker-compose.yml
docker-compose.yml 简化了容器管理流程,并提供一种便捷方式传入环境变量。
创建 docker-compose.yml 文件:
$ touch docker-compose.yml
添加如下内容:
version: "3.8"
services:
vue-app:
build:
context: .
dockerfile: Dockerfile
ports:
- "8080:80"
env_file:
- .env
该配置:
- 指定构建上下文和 Dockerfile 路径
- 映射主机 8080 端口到容器 80 端口
- 从 .env 文件加载环境变量
准备就绪后,即可构建并运行容器。
7. 测试运行时变量注入
配置好 docker-compose.yml 后,现在构建并运行容器化应用。
创建 .env 文件:
$ touch .env
添加如下内容:
VUE_APP_API_URL=https://v6.exchangerate-api.com/v6/your_api_key/latest/USD
⚠️ 请将 your_api_key
替换为你的实际 API Key
构建镜像:
$ docker-compose up --build
访问以下地址验证:
http://localhost:8080/config.js
应该看到如下内容:
window.config = {
VUE_APP_API_URL: "https://v6.exchangerate-api.com/v6/your_api_key/latest/USD"
};
✅ 验证成功。
若需更新变量,修改 .env 文件后重启容器即可:
$ docker-compose down
$ docker-compose up
刷新 /config.js
确认更新生效。
至此,我们完成了容器化和运行时变量注入的整个流程。
8. 适配生产环境
现在我们已成功容器化并运行 Vue.js 应用,接下来探讨如何适配生产环境。
8.1. 生产环境中的环境变量管理
生产环境中,建议以下两种方式管理环境变量:
- 使用 .env 文件:适用于非敏感变量,敏感变量应使用更安全的方式管理,如 Docker Secrets
- Kubernetes 中使用 ConfigMap / Secrets:标准做法,用于管理非敏感(ConfigMap)和敏感(Secrets)数据。例如:
apiVersion: v1
kind: ConfigMap
metadata:
name: vue-config
data:
VUE_APP_API_URL: "https://api.production.example.com"
这些可以作为环境变量挂载到 Pod 中。
8.2. 无缝更新环境变量
根据部署平台,有以下更新方式:
- Kubernetes:使用滚动更新策略逐步替换 Pod
- Docker Compose / Swarm:使用蓝绿部署或最小中断重启服务
8.3. config.js 的缓存处理
生产环境中,缓存可能导致加载旧版本 config.js。可采取以下措施:
- 在 index.html 中添加时间戳参数:
<script src="./config.js?v=<%= Date.now() %>"></script>
- 修改 Nginx 配置禁用缓存:
location /config.js {
default_type application/javascript;
add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0";
return 200 "window.config = { VUE_APP_API_URL: '${VUE_APP_API_URL}' };";
}
8.4. 安全性保障
生产环境中,需重点关注以下安全措施:
- 使用 AWS Secrets Manager、HashiCorp Vault 或 Kubernetes Secrets 存储敏感数据
- 若 config.js 包含敏感信息,限制 IP 或启用身份验证
- 应用和配置均应通过 HTTPS 提供,防止中间人攻击
以上措施确保应用在生产环境中灵活、安全、可靠地运行。
9. 总结
本文演示了如何在 Vue.js 应用中运行时传递环境变量,解决了构建时配置的局限性。我们实现了一个实用方案,使应用无需重新构建即可动态注入和访问变量。同时,我们还容器化了应用,并探讨了如何适配生产环境。
这种方式确保应用在复杂部署环境中依然灵活易维护。
完整代码请参考 GitHub 仓库。