dotenv在Nx与Vite中的冲突问题

Nx 预加载环境变量导致 Vite 本地 env 覆盖失效的问题分析与解决方案

#status / growing #type / debug

[!info] related notes

dotenv在Nx与Vite中的冲突问题

这是一个非常经典的 Nx Monorepo 与 Vite 环境变量加载机制冲突的问题!

你的直觉完全正确:按照 Vite 的官方文档,.env.development.local 的优先级理应高于 .env

但为什么现在表现出来的却是 .env 优先级最高了呢?罪魁祸首是 Nx(你的 Monorepo 构建工具)

下面我为你揭秘这个“幽灵覆盖”是怎么发生的:

🔍 为什么 .env 反而“覆盖”了 .local?

程序的启动顺序其实分为两步:先启动 Nx,再由 Nx 启动 Vite

  1. 第一步:Nx 启动并抢先加载 .env** 当你运行 nx serve web 或者通过 Nx 运行任何命令时,Nx 会在整个进程的最开始,自动去读取根目录下的基础 .env 文件。 它读取到 VITE_ENABLE_MOCK_API=false 后,会直接把这个值塞进 Node.js 系统的最高级内存——process.env** 里面。
  2. **第二步:Vite 启动并执行 loadEnv** 接着 Vite 开始工作,它去乖乖地寻找 .env.development.local,并且也成功找到了里面的 VITE_ENABLE_MOCK_API=true但是! Vite 有一个铁打的规则:系统环境变量(process.env)的优先级绝对高于任何配置文件。 Vite 在合并时发现:“咦?process.env 里已经有一个 VITE_ENABLE_MOCK_API=false 了(其实是 Nx 刚才塞进去的),那我绝对不能用文件里的值去覆盖系统的原配值!”

结论: 并不是 Vite 觉得 .env 的优先级比 .env.development.local 高,而是 Nx 把 .env 里的值变成了系统的 process.env**,从而产生了降维打击**,导致你后面所有的 .local.development 文件中同名的变量全部失效。

当你把 .env 里的值改成 true 时,Nx 塞给 process.env 的就是 true,所以它恢复了。


🛠️ 如何优雅地解决这个问题?

为了让不同环境的配置文件(如 .local)能够正常发挥它们“覆盖”的作用,我们通常建议采用以下几种做法:

方法一:把特定变量从基础 .env 中移除(最推荐)

基础的 .env 文件只应该放全环境通用的配置(比如项目名称 APP_NAME=DailyUse)。 像 VITE_ENABLE_MOCK_API 这种在不同环境(本地、开发、生产)经常要变的值,不要写在最外层的 .env

  • 请把它从 .env 中删掉。
  • 默认的 false 可以写在 .env.production 里。
  • 默认的 true 可以写在 .env.development 里。
  • 本地想关掉,就在 .env.development.localfalse。 这样 Nx 启动时就不会把这个变量锁死在 process.env 里,Vite 就能完美接管环境文件优先级的合并了。

方法二:在 Nx 的 project.json 中指定 env 文件(实测没有用,还是以 .env 为准)

[!notice] (实测没有用,还是以 .env 为准) AI 给的回答,虽然方法也是 AI 给的。 Nx CLI 极其“勤快”:当你敲下 nx serve 回车的那一瞬间,Nx 的核心程序启动,它会无条件、最优先地去读取你根目录下的 .env 文件,并把里面的值全部塞进 Node 的 process.env 内存里。

如果你一定要保留在 .env 中,你可以告诉 Nx 在运行 serve 时优先加载你的 local 文件。 打开 apps/web/project.json,找到 serveoptions,配置 envFile

"targets": {
  "serve": {
    "executor": "@nx/vite:dev-server",
    "defaultConfiguration": "development",
    "options": {
      "buildTarget": "web:build",
      // 👇 强制 Nx 优先读取这个文件塞入 process.env
      "envFile": ".env.development.local" 
    }
  }
}

小提示(防低级错误)

你在提问中打字写的是 .env.develop.local,请务必确认你实际的文件名是 .env.development.local,少了一个 ment 的话,Vite 也是绝对不会去读取它的哦!

创建于 2026/2/24 更新于 2026/5/27