背景
公司有多个环境部署nuxtjs3架构的前端项目,以往需要配合dotenv配置多个环境的.env.*
文件,每个环境都需要执行一次编译打包流水线,虽然部署流程已经完全自动化,但打包构建过程依旧漫长。
于是就有了这样的一个需求,仅需执行一次编译打包的过程,所有环境(dev、test、staging、sit、uat、prod)都是用同一次编译打包的产物,大大节省了部署时间、减少了编译环境的差异性。
我们知道.env.*
中的配置会在编译阶段将对应的值编译到产物代码中固定,运行时不会更改,最大的问题是如何将配置在编译阶段修改成在运行阶段传入,我们也要放弃掉编译成静态文件运行的场景,只能使用node或pm2等管理软件来运行nuxtjs项目。
以下方法只是提供一种方案,并不是对每个项目都是最优解,仅供参考。
下面我们利用nuxtjs的runtime-config
来实现这个需求。
代码托管在nuxtjs-demo
前端框架
环境变量
nodejs会使用process.env.*
的方式来获取环境变量,前提是操作系统中必须配置好了对应的环境变量, 例如,使用在类unix操作系统中执行命令export API_PREFIX=/api
设置环境变量API_PREFIX的值等于/api
,nodejs可以通过process.env.API_PREFIX
获取到值/api
,nuxtjs正是使用这个特性来实现环境变量注入。
shell
const apiPrefix = process.env.API_PREFIX
但问题是在编译阶段,代码中的任何process.env.*
都会被编译成对应的字符串,webpack中NODE_ENV
都不在这里讨论的范围里,今天只讨论nuxtjs中的环境变量。
nuxt.config.ts
nuxtjs架构提供了配置nuxt.config.ts 供用户配置,其中runtimeConfig 的配置需要符合nuxt配置规范,runtimeConfg.public 中的 key使用小驼峰命名,value留空,nuxt 会自动注入带NUXT_PUBLIC_ 的环境变量,并需要配置在 .env.*
中。
如果不按nuxt的规范来配置,就只能通过process.env.*
的方式来获取配置,并且在编译阶段就编译到产物代码中,又回到开头了。
下面是按规范和不按规范配置环境变量。
shell
# .env
NUXT_PUBLIC_API_PREFIX=/api
NUXT_PUBLIC_BASE_SERVICE_URL=http://192.168.1.20:8080/
NUXT_PUBLIC_USER_SERVICE_URL=http://192.168.1.21:8080/
# 不按规范,没有NUXT_PUBLIC前缀
OFFICIAL_WEBSITE_URL=https://www.example.com
私密配置规范
ini
# 按照规范配置NUXT前缀
NUXT_PUBKEY=公钥
nuxt.config.js
ruby
{
// 添加 runtimeConfig 配置
runtimeConfig: {
public: {
// @see https://nuxt.com/docs/guide/going-further/runtime-config#example
apiPrefix: '', // 可以被NUXT_PUBLIC_API_PREFIX环境变量覆盖
baseServiceUrl: '', // 可以被NUXT_PUBLIC_BASE_SERVICE_URL环境变量覆盖
userServiceUrl: '', // 可以被NUXT_PUBLIC_USER_SERVICE_URL环境变量覆盖
official_website_url: process.env.OFFICIAL_WEBSITE_URL, // 仅能够通过process.env来获取,并在编译阶段编译进代码
},
},
}
ecosystem.config.cjs
ecosystem.config.cjs
是给docker 运行 pm2 时读取的配置文件,apps.env
会将 docker 中的环境变量注入,env 中的 key 需要和 nuxt.config.ts
中的 runtimeConfig
成对使用,如果是 runtimeConfig.public
的变量,注入时必须带 NUXT_PUBLIC_
前缀
yaml
module.exports = {
apps: [
{
name: 'website-nuxt',
exec_mode: 'cluster',
instances: '1',
script: '.output/server/index.mjs',
args: 'start',
env: {
NUXT_PUBLIC_API_PREFIX: process.env.API_PREFIX,
NUXT_PUBLIC_COLLEGE_URL: process.env.COLLEGE_URL,
NUXT_PUBLIC_LOGIN_REGISTER_URL: process.env.LOGIN_REGISTER_URL,
},
},
],
};
客户端会将配置渲染到html中
xml
<script>
window.__NUXT__.config = {
public: {
apiPrefix: '/api',
collegeUrl: 'http://192.168.0.212:85/',
loginRegisterUrl: 'http://192.168.0.212:82/',
}
}
</script>
而组件内编写代码时正常使用就行。
xml
<template>
<div>
{{ message }}
</div>
</template>
<script setup lang="ts">
import { onMounted } from 'vue'
const message = ref('')
const runtimeConfig = useRuntimeConfig()
onMounted(() => {
console.log(runtimeConfig.public)
message.value = runtimeConfig.public
// test()
})
</script>
本地开发
如果是本地开发,依旧正常使用dotenv就行了。 本地建议从.env.example
复制一个.env.local
,在.env.local
中配置参数,它会和.env
合并,并且.env.local
优先级高于.env
。 .env.local
不提交到仓库。 其余提交到仓库的.env.*
不应该包含敏感信息。
shell
NUXT_PUBLIC_API_PREFIX=/api
NUXT_PUBLIC_COLLEGE_URL=http://192.168.0.212:85/
NUXT_PUBLIC_LOGIN_REGISTER_URL=http://192.168.0.212:82/
部署
docker部署多环境
运行时的环境变量参考ecosystem.config.cjs
中的 env,ecosystem.config.cjs
的 env 参考nuxt.confg.ts
中的 runtimeConfig
中的 public 变量.
编译 docker 镜像
bash
docker build --pull --rm -f "Dockerfile" -t nuxtjs-demo:latest "."
运行
bash
# 环境1
docker run -e "API_PREFIX=/api" \
-e "COLLEGE_URL=http://192.168.0.212:85/" \
-e "LOGIN_REGISTER_URL=http://192.168.0.212:82/" \
-it -p 127.0.0.1:3002:3000 -d --rm --name nuxtjs-demo nuxtjs-demo:latest
# 环境2
docker run -e "API_PREFIX=/api" \
-e "COLLEGE_URL=地址1" \
-e "LOGIN_REGISTER_URL=地址 2" \
-it -p 127.0.0.1:3002:3000 -d --rm --name nuxtjs-demo1 nuxtjs-demo:latest
注意如果你的是 arm 系统,比如苹果芯片的 mac,可能会出现平台兼容的警告,甚至无法运行。
WARNING: The requested image's platform (linux/amd64) does not match the detected host platform (linux/arm64/v8) and no specific platform was requested
你可以通过下面你的方式来指定
设置 Docker 默认平台
为了在运行或构建镜像时默认使用 AMD64 平台,您可以设置环境变量 DOCKER_DEFAULT_PLATFORM
:
go
```
bash
export DOCKER_DEFAULT_PLATFORM=linux/amd64
```
您可以将此行添加到 `~/.bashrc` 或 `~/.zshrc` 文件中,以便在每次启动终端时自动设置。
运行或构建 Docker 镜像
go
现在,您可以运行或构建指定平台的 Docker 镜像。例如,运行一个 AMD64 的 Ubuntu 镜像:
```bash
docker run --rm -it --platform=linux/amd64 ubuntu:latest
```
或者构建一个镜像,指定平台为 AMD64:
```bash
docker build --platform=linux/amd64 -t myimage:latest .
```