Skip to content

Monorepo + Nextjs 管理 .envport

July 30, 2024 by ccforeverd

使用 @dotenvx/dotenvx 管理 .env port

项目结构

  • apps
  • libs
  • packages
  • package.json
  • .env

简单描述

通过根路径的 .env 文件控制全局的环境

通过各自目录下的 .env 文件控制局部的环境

在我的项目中, 所有项目的端口号都在根路径的 .env 中管理

apps 中有使用构建工具的项目, 比如 vite, rsbuild 等, 可以在配置文件中通过自带的 loadEnv 或类似方法导入 (因为基本都内置了 dotenv), 然后配置端口号

但在 next 里, next.config.js 里不支持 port 的配置, 只能通过命令行传参的方式, 比如 next dev -p 8200

所以, 只能在命令行中加载 .env 到环境变量中, 再启动 next 服务, 这里我选择了官方推荐的 dotenvx 作为工具

主要代码

apps/next-web/package.json
{
  "scripts": {
    "dev": "next dev -p $BF_PORT_NEXT_DEV", 
    "dev:bad": "dotenvx run -f ../../.env -- next dev -p $BF_PORT_NEXT_DEV"
  }
} 
package.json (root)
{
  "scripts": {
    "dev:next": "dotenvx run --quiet -- pnpm -F \"./apps/next-web\" dev", 
    "dev:next:bad": "pnpm -F \"./apps/next-web\" dev:bad",
    "dev:a": "pnpm -F \"./apps/react-a\" dev",
    "dev:b": "pnpm -F \"./apps/react-b\" dev"
  }
}
.env (root)
BF_PORT_NEXT_DEV=8200
vite.config.ts
// apps/react-a/vite.config.ts
export default defineConfig(({ mode }) => {
  const env: Record<string, string> = {
    ...loadEnv(mode, '.'),
    ...loadEnv(mode, '../..', 'BF'), 
  }
  
  // ...
})
 
// apps/react-b/rsbuild.config.ts
export default defineConfig(({ env, envMode, command }) => {
  logger.info('env:', env)
  logger.info('envMode:', envMode)
  logger.info('command:', command)
 
  logger.log()
 
  const { parsed: innerAppEnvs } = loadEnv({ mode: envMode, prefixes: ['BF_'] })
  const { parsed: rootEnvs } = loadEnv({
    mode: envMode,
    prefixes: ['BF_'],
    cwd: path.resolve(process.cwd(), '../../'), 
  })
 
  const envs = {
    ...rootEnvs,
    ...innerAppEnvs,
  }
 
  // ...
})

问题解释

里面 next 有两个开发命令 dev:nextdev:next:bad

dev:next 是正常的, 多次尝试后的结果

dev:next:bad 是不正常的, 让我感到困惑的, 报错如下:

Terminal
[dotenvx@0.37.1] injecting env (4) from ../../.env
error: option '-p, --port <port>' argument missing

第一行是 dotenvx 的, 第二行是 next 的, 可能是安全防护, 不能加载父级目录吧, 还不清楚如何修改, 提了 issue