如何在nextjs中使用不同的.env文件?

67

我希望为环境变量拥有不同的配置文件,并能在我的下一个项目中使用它们。我看到了使用dotenv的示例。

但我不喜欢在.env文件中定义变量,也在config.next.js文件中定义它们。如果由于某种原因我把变量放在.env文件中,但忘记将它们放在config.next.js文件中,代码就会出现问题。是否有一种更有效的方法?

我的package.json脚本:

"scripts": {
    "dev": "next",
    "build": "next build",
    "start": "next start",
    "lint": "eslint pages --ext .ts,.tsx,.js",
    "test": "jest",
    "commit": "git-cz",
    "dev:production": "dotenv next"
},

我的 .env 变量

TITULO=react, typescript, material ui App

组件

import { NextPage }          from 'next';
import { FunctionComponent } from 'react';

interface HelloWorldProps {
  nombre: string,
  saludo?: string
}


const HelloWorld: FunctionComponent<HelloWorldProps> = ({ nombre, saludo = 'noches' }: HelloWorldProps) => (
  <>
    <h1>Hola {nombre} buenas {saludo}</h1>
    {/* eslint-disable-next-line multiline-ternary */}
    <h2>{process.env.TITULO ? 'hola' : 'adios'}</h2>
  </>
);

const Home: NextPage = () => <HelloWorld nombre="cristian" />;

export default Home;


我在这里回答了一个类似的帖子-https://dev59.com/nFMH5IYBdhLWcg3w92Mu#76724510 - KeshavDulal
12个回答

85

Next 9.4支持内置.env文件:https://nextjs.org/docs/basic-features/environment-variables

但是,如果你想要使用多个.env文件,例如:

  • .env.development
  • .env.staging
  • .env.prestaging
  • .env.production

那么使用内置的环境变量支持就不可能实现。目前只有3种官方支持的环境,它们是:“development”、“test”、“production”。next dev使用“development”,而next build && next start使用“production”环境。

如果您需要为生产环境构建,但是需要使用“.env.staging”等文件,则需要添加env-cmd包,并将此行添加到package.json中:

"build:staging": "env-cmd -f .env.staging yarn build && yarn start"

接下来将使用".env.staging"变量进行生产构建。


6
在下一个开发阶段中,您将使用 "development" 环境,在运行 "build" 和 "start" 命令时将使用 "production" 环境。那么要如何在 "test" 环境中运行呢? - bugwheels94
3
可以,但如果要在任何地方运行 Docker 构建,则需要使用不同的命令进行构建。这是解决方案:https://github.com/andrewmclagan/react-env - AndrewMcLagan
4
关于 cmd-env 的技巧很不错。顺便说一下,看起来在 Next.js 中应该成为一个选项 =) - Wendell Pereira
11
它确实如此,我们需要安装外部库来处理环境,这太荒谬了--' - Matheus Ribeiro
3
这个无法与 next: 9.5.3env-cmd: ^10.1.0 一起使用。无论提供给 env-cmd 的环境是什么,它都会继续加载生产环境: $ env-cmd -f .env.development next start info - Loaded env from /Users/username/projects/ex/.env.production - Phạm Tuấn Anh
显示剩余4条评论

31

这些答案的问题在于它们违反了“一次构建,到处运行”的原则,实际上我们大多数人都使用Docker容器来构建和运行。像这样有多个构建命令是不可能的,而且这样做是不好的实践。

最好在运行时使您的环境可用。我们创建了一个软件包,通过 window.__ENV 实现下一个静态优化并仍然具有运行时环境变量。

https://github.com/andrewmclagan/react-env

这是通过从白名单环境变量生成环境配置对象来实现的:

{
  ...
  "scripts": {
    "dev": "react-env -- next dev", // where .env.${APP_ENV}
    "start": "react-env --env APP_ENV -- next start" // where .env.${APP_ENV}
  }
  ...
}

14
来自其他环境并对NextJS的这种做法感到非常惊讶,感谢你成为理性之声。 - kevlarr
我已经在谷歌上搜索了一段时间,只是对Next中处理环境的“默认”方式感到困惑 - 谢谢。 - Phantomwhale
如何从构建过程环境中选择API基础URL?如果实际URL在构建期间未知,并将在启动时传递给Docker容器? - Alexander Pravdin
请查看此软件包的文档。你可以做到的。 - AndrewMcLagan
1
我非常沮丧地发现NextJS希望我为分别的暂存和生产环境构建单独的包,这个软件包是解决常见问题的绝佳方法,应该成为核心框架的一部分。 - linked

20
您可以通过以下两种方式在nextjs中使用不同的.env文件: 1.使用env-cmd包 在脚本中提供环境文件的路径,例如:
"scripts": {
    "start": "env-cmd path/to/prod/env/file next start",
    "start:dev": "env-cmd path/to/prod/env/file next dev",   
    "build:dev": "env-cmd path/to/dev/env/file next build",
    "build:test": "env-cmd path/to/test/env/file next build",
    "build:stage": "env-cmd path/to/stage/env/file next build",
    "build": "env-cmd path/to/stage/prod/file next build",        
},

2. 使用dotenv包

在你的 next.config.js 文件中添加以下内容:

require("dotenv").config({ path: `${process.env.ENVIRONMENT}` });

module.exports = {
      // your configs
}

在你的脚本中,提供类似于以下的 ENVIRONMENT 变量:

"scripts": {
    "start": "ENVIRONMENT=path/to/prod/env/file next start",
    "start:dev": "ENVIRONMENT=path/to/dev/env/file next dev",
    "build:dev": "ENVIRONMENT=path/to/dev/env/file next build",
    "build:test": "ENVIRONMENT=path/to/test/env/file next build",
    "build:stage": "ENVIRONMENT=path/to/stage/env/file next build",
    "build": "ENVIRONMENT=path/to/stage/prod/file next build",        
},

注意:不要将 .env* 文件放在根文件夹中,否则 NEXT 将自动从您的 .env* 文件中选择,并且仅支持生产和开发阶段。因此,它将忽略其他 .env.my-stage 文件。


你好。env-cmd 是否需要用于 next start 命令?我认为变量在构建期间被内联,而 next start 只是运行该构建,我对吗? - Richard Trembecký
1
@RichardTrembecký,是的,没错。如果没有生产构建,next start 就无法工作,而 env-cmd 则在构建期间注入变量。 - Vrajpal Jhala
模块未找到:错误:无法解析“C:\ admin \ node_modules \ dotenv \ lib”中的“fs” - Sunil Garg
对于env-cmd,如果您的env在根目录上,可以使用-f强制使用特定的env文件:“env-cmd -f .env.dev next build”。 - Alon Laniado

6
这个时代,你不需要安装任何额外的东西来实现多环境配置!查看GitHub仓库NextJS模板与配置管理Next.js v9.4及以上版本有一种更直观和人性化的方式来添加环境变量
{
  "name": "package.json",
  "scripts": {
    "dev": "next dev",
    "build": "next build && next export",
    "build-dev": "TARGET_ENV=development next build && next export",
    "build-staging": "TARGET_ENV=staging next build && next export",
    "test": "jest --watch"
  }
}

{
  "name": "env.json",
  "development": {
    "APP_ENV": "development"
  },
  "production": {
    "APP_ENV": "production"
  },
  "staging": {
    "APP_ENV": "staging"
  },
  "test": {
    "APP_ENV": "test"
  }
}

// next.config.js v9.4+
const envConfig = require('./env.json')
const environment = process.env.TARGET_ENV || process.env.NODE_ENV

const nextConfig = {
  env: envConfig[environment], // getEnvConfig()
}
module.exports = nextConfig

function getEnvConfig() { // for multi-file config
  try {
    return require(`./env-${environment}.json`)
  } catch (err) {
    return require('./env.json')
  }
}

npm run dev # process.env.APP_ENV=development
npm run build # process.env.APP_ENV=production
npm run build-dev # process.env.APP_ENV=development
npm run build-staging # process.env.APP_ENV=staging
npm run test # process.env.APP_ENV=test

2
在容器化的世界中,这对我来说并没有太多意义。我们不应该按环境构建。构建应该只有一个,并在运行时使用 ENV 变量,这就是 ENV 变量的作用,对吧? - JorgeeFG
不喜欢就离开吧,今天仍有许多组织在生产中使用静态站点导出,随意倾倒到任何云存储桶中。 - piouson

4

对于任何有兴趣使用 .yml 文件简化环境变量管理的人,这里是我的做法。

devDependencies中安装一个插件yenv

next.config.js中添加以下配置:

const path = require("path");
const yenv = require("yenv");
const { PHASE_DEVELOPMENT_SERVER } = require("next/constants");

module.exports = (phase) => {
  const isDev = phase === PHASE_DEVELOPMENT_SERVER;
  const NEXT_ENV = isDev ? "development" : process.env.APP_ENV;
  const rawEnv = yenv(path.resolve(".env.yml"), { raw: true, env: NEXT_ENV });
  
  return {
    ...some other config,
    env: getEnvVars(rawEnv, isDev).raw,
    compress: true,
  };
};

function getEnvVars(rawEnv, dev) {
  const NEXT_PUBLIC = /^NEXT_PUBLIC_/i;
  const raw = Object.keys(rawEnv)
    .filter((key) => NEXT_PUBLIC.test(key))
    .reduce((env, key) => {
      env[key] = rawEnv[key];
      return env;
    }, {});
  // Stringify all values so we can feed into Webpack DefinePlugin
  const stringified = {
    "process.env": Object.keys(raw).reduce((env, key) => {
      env[key] = JSON.stringify(raw[key]);
      return env;
    }, {}),
  };
  return { raw, stringified };
}

现在只需根据环境添加不同的构建命令到 package.json 脚本中即可。
"scripts": {
    "dev": "node server.js",
    "build:production": "APP_ENV=production next build",
    "build:staging": "APP_ENV=staging next build",
    "start": "NODE_ENV=production node server.js"
  },

现在你可以通过一个名为.env.yml的单个文件来使用你的环境变量,就像这样:
base:
  NEXT_PUBLIC_SECRET_KEY : ""
  NEXT_PUBLIC_ANOTHER_SECRET: ""

development:
  ~compose: base
  NEXT_PUBLIC_SECRET_KEY: "bnbnfjf"

staging:
  ~compose: base
  NEXT_PUBLIC_SECRET_KEY: "absadsad"

production:
  ~compose: base
  NEXT_PUBLIC_SECRET_KEY: "lasjdasodsdsad"


现在,您可以调用npm run build:production来加载生产环境变量,并调用npm run build:staging来加载暂存环境变量。
这样做的好处是您可以根据需要使用任意数量的环境。您只需添加一个构建命令并更新.env.yml中的环境变量即可开始使用。

谢谢,与其他方案相比,这看起来对我来说是一个非常优雅的解决方案。 - Rohith Balaji

4

npm i dotenv

然后将以下代码添加到next.config.js,重新启动应用程序,即可使用!

// next.config.js

require('dotenv').config()
const webpack = require('webpack')

module.exports = {
  webpack: (config) => {
    config.plugins.push(
      new webpack.EnvironmentPlugin(process.env)
    )
    return config
  }
}

如果您的 .env 文件不在与 next.config.js 相同的文件夹中,请像下面这样将路径添加到您的配置中:
require('dotenv').config({ path: 'path/to/.env' })

在 Next 9.4.0 中,添加 config.plugins.push 行对我有用;谢谢! - James Hooper

3

简短回答

  1. 将开发环境的秘密信息放在.env.dev文件中。
  2. 将生产环境的秘密信息放在.env.prod文件中。
  3. 不要将秘密信息保存在.env.local文件中。它们会被带到那里。
  4. 将以下内容添加到你的package.json脚本中。
"build-dev": "cp .env.dev .env.local && yarn build",
"build-prod": "cp .env.prod .env.local && yarn build"
  1. 如果有效,请点赞并享受。

此外,

  1. 您可能想要添加一个变量APP_ENV
  2. 根据文件将其设置为developmentproduction
  3. 根据您的脚本调用访问process.env.APP_ENV

长答案

嗯,现在是2023年中期了,我希望有一个简单明了的解决方案。以下是我从React/vite转到Nextjs时使用的适用于两个不同环境文件的方法。


使用 Rodrigo's answer,我首先将以下文件重命名:

  • .env.development 重命名为 .env.dev
  • .env.production 重命名为 .env.prod

这样,next.js 在构建过程中不会自动选择它们,而是保留在本地系统上。

如果我不这样做,那么优先级会生效,并且在部署到我的dev环境时会选择.env.production,而我并不希望如此。

接下来,我修改了package.json中的脚本:

"build":"yarn build"

"predeploy": "cp .env.dev .env.local",
"deploy": "firebase use development && firebase hosting:channel:deploy dev",

"predeployprod": "cp .env.prod .env.local",
"deployprod": "firebase use production && firebase deploy -P production"

简要了解 Next JS Precedence Order

这样做的基础是根据我的“调用”是否要部署到开发/生产环境,它会向.env.local文件提供正确的密钥。

例如,如果我想要部署到dev。 我运行yarn deploy -> 自动运行yarn predeploy,首先将我的dev-secrets设置为.env.local。其次它运行构建。

你可能会想下一个的构建命令在哪里? firebase deploy会处理并在幕后运行它。

如果您没有使用firebase,以下内容可能就足够了。

"build-dev": "cp .env.dev .env.local && yarn build",
"build-prod": "cp .env.prod .env.local && yarn build"

最初的回答在这里。

在Windows PowerShell中运行npm run build-dev会显示"cp不是内部或外部命令",但在bash中可以正常工作。 - undefined
@abitcode 你需要使用一个兼容Linux的shell。 - undefined
在哪里告诉不同的Firebase项目使用不同的脚本来构建或启动? - undefined

1

如果您想在没有任何第三方库的情况下使用它,您可以直接从脚本中使用NEXT_PUBLIC_来公开它,例如:

"scripts": {
  "start": "NEXT_PUBLIC_APP_ENV=development next dev"
}

然后与之使用

console.log(process.env.NEXT_PUBLIC_APP_ENV); // >>> development

我猜可能是有人做错了,或者版本问题,但我在很多项目中都在使用它。 - x-magix

0

对于那些仍在寻找解决方案的人,就像我一样,我的npm运行dev脚本是“next dev src/”,立即摆脱它开始为我加载.env文件。也许你可以试试。

我可爱的修复截图


0

您可以使用dotenv-cli,然后在package.json中为不同的环境设置不同的.env文件。例如:

{
  ...
  "scripts": {
    "dev:production": "dotenv next", // Uses .env file
    "dev:staging": "dotenv -e .env.staging next" // Uses .env.staging file
  }
  ...
}

1
它给我一个“dotenv未找到”的错误。虽然我已经安装了它,并且在本地文件中正常工作。 - Rehan Sattar
1
dotenv -e .env.development next build 仍然加载生产配置。 - Dariusz Bacinski
它仍然加载生产环境。最终我只能在生产环境文件中进行注释/取消注释变量。太荒谬了!!! - Phạm Tuấn Anh
1
NODE_ENV决定了是否加载.env.development.env.production文件。 你应该通过使用.env.app.development.env.app.production等不同的环境文件名来为你的"应用环境"使用不同的环境文件。 - Metu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接