nuxtjs3使用同一个编译产物运行在多个环境中

背景

公司有多个环境部署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 .
```
相关推荐
阿丽塔~5 分钟前
react中 useEffect和useLayoutEffect的区别
前端·react.js·前端框架
飘尘17 分钟前
春天来了,来生成一棵独属自己的花树吧!
前端·javascript·canvas
旺代18 分钟前
CSS圣杯布局与双飞翼布局
前端·css
dchen7721 分钟前
前端实现大文件下载的终极解决方案!!!
前端·javascript·面试
ak啊22 分钟前
Webpack启动流程与初始化-Tapable 事件流机制
前端·webpack·源码
巴巴博一23 分钟前
Vue-admin-template安装教程
前端·javascript·vue.js
前端菜鸟来报道31 分钟前
html和css 实现元素顺时针旋转效果(椭圆形旋转轨迹)
前端·css·旋转·椭圆布局
Ustinian_31032 分钟前
【HTML】KaTeX 常用公式字符
前端·chrome·html
OpenTiny社区1 小时前
直播分享|TinyPro:一行命令,搭建包含前后端的后台管理系统
前端·vue.js·github