Node.js的dotenv无法与PM2一起使用。

38

我有一个应用程序,在本地(不使用pm2)中,.env 文件中的所有环境变量都可以很好地使用 dotenv

但是在我使用 pm2 运行该应用程序的服务器上,环境变量仍然为 undefined

我在服务器上使用的 pm2 命令是:

pm2 start myapp/app.js
pm2 startup
pm2 save
8个回答

91

dotenv会读取当前目录中的.env文件。

当您调用pm2 start myapp/app.js时,它不会搜索myapp/.env文件。

.env // It will try to load this, which doesn't exist
myapp/
   app.js

所以你有两个解决方案

使用 path 选项:

const path = require('path'); 
require('dotenv').config({ path: path.join(__dirname, '.env') });

或者在myapp/内部调用您的脚本。
pm2 start app.js

1
@MarcosCasagrande 非常感谢。这节省了我很多时间! - Abdalla Arbab
这个很好用,谢谢!虽然我不确定为什么你需要路径库来连接字符串。require('dotenv').config({path: `${__dirname}/.env`});也可以正常工作。 - Chris Broski
1
@ChrisBroski,因为硬编码目录分隔符是不好的实践。path.join会处理它,并且在任何操作系统中都可以工作。 - Marcos Casagrande
我从未说过字符串字面量在某些操作系统上不起作用... 我说硬编码目录分隔符是一种不好的做法。你的代码在Windows上无法工作,而我的示例可以,这就是我使用path.join的原因,因为它是通用答案。 - Marcos Casagrande
1
你的Windows可能会宽容一些,但要知道它并不适用于所有情况,所以建议始终使用路径函数来正确构建路径。 - Marcos Casagrande
显示剩余8条评论

35

一种好的做法是从代码中删除dotenv,并在命令行上“require”它。这使得您的代码在任何环境(包括基于云的环境)之间很方便地移植 - 这是环境变量的主要特点之一。

注意:在服务器上运行时,仍需要通过npm在项目中安装dotenv。

a)将.env文件与脚本(例如app.js)放在一起编写代码

b)如果要在没有pm2的情况下运行脚本:

node -r dotenv/config app.js

c) 在 pm2.config.js 文件中:

module.exports = {
  apps : [{
    name      : 'My Application',
    script    : 'app.js',
    node_args : '-r dotenv/config',
    ...
  }],
}

然后执行pm2 start pm2.config.js

注意:在命令行上使用dotenv/config是dotenv本身推荐的最佳实践之一

2021年更新:为了完整起见,由于我的答案得到了一些赞,我想将第4个选项添加到列表中:

d) 合并pm2/env配置

module.exports = { apps : [{
  name      : 'My Application',
  script    : 'app.js',
  env       : {
    PORT: 5010,
    DB_STRING: 'mongodb://localhost:27017',
    ...
  },
}]};

如果你将你的pm2.config视为环境配置并且不使用git等工具,这将非常有用。它消除了单独使用.env文件的需求,这可能适合你。它完全取代了dotenv,因为pm2会将env变量注入到你的脚本进程中。


4
对不起,似乎我没有理解您的要求。您需要我翻译这句话吗?如果是的话,它的意思是“对我而言无法工作:错误:找不到模块'dotenv/config'”。 - IvanZh
嗨,你能帮我解决这个问题吗?https://stackoverflow.com/questions/56617733/issue-with-pm2-and-dotenv-not-working-on-ubuntu-server。先谢谢了。 - Channaveer Hakari
嘿 @Ivan2h,听起来你还没有安装 dotenv - 它仍然需要在你的 node_modules 中 - 运行 npm install dotenv。 - Andy Lorenz
如果您没有设置 node_args: '-r dotenv/config',则会出现错误。 - sarfarazsajjad
谢谢 @Saifee,我已经修复了。奇怪的是我错过了-r标志,因为我自己的配置脚本中有它! - Andy Lorenz
对我来说,选项C最好。我的所有设置已经存在于.env文件中了,我不想再管理一个.env文件和pm2.config.js文件了。谢谢!<3 - TJBlackman

17

你需要先停止你的PM2进程

尝试

pm2 kill

然后使用以下命令重新启动pm2

pm2 start app.js

5

我曾经遇到过同样的问题,但是解释不够清楚,于是根据GitHub用户vmarchaud的评论得出了解决方案。 这个方法也可以修复人们在@Andy Lorenz解决方案中遇到的问题。

在我的情况下,我想要为多个应用程序创建一个生态系统文件,但是我一直遇到以下问题:

Error: Cannot find module 'dotenv/config'

解决方案很简单。你需要声明cwd,也就是dotenv/config将要读取的项目文件夹。

module.exports = {
  apps: [{
    name: 'app1 name',
    script: 'app1.js',
    cwd: '/path/to/folder/',
    exec_mode: 'fork_mode',
    node_args: '-r dotenv/config',
  }, {
    name: 'app2 name',
    script: 'app2.js',
    cwd: '/path/to/folder/',
    instances: 'max',
    exec_mode: 'cluster',
    node_args: '-r dotenv/config',
  }],
};

3
你可以使用 dotenv 库解析 .env 文件,并在 ecosystem.config.js 中手动设置它们。

ecosystem.config.js:

const { calcPath, getEnvVariables } = require('./helpers');

module.exports = {
  apps: [
    {
      script: calcPath('../dist/app.js'),
      name: 'dev',
      env: getEnvVariables(),
    },
  ],
};

helpers.js:

const path = require('path');
const dotenv = require('dotenv');
const fs = require('fs');

function calcPath(relativePath) {
  return path.join(__dirname, relativePath);
}

// this function will parce `.env` file but not set them to `process.env`
const getEnvVariables = () => {
  const envConfig = dotenv.parse(fs.readFileSync(calcPath('.env')));

  const requiredEnvVariables = ['MODE'];

  for (envVariable of requiredEnvVariables) {
    if (!envConfig[envVariable]) {
      throw new Error(`Environment variable "${envVariable}" is not set`);
    }
  }

  return envConfig;
};

1

对我来说这些都不起作用,因为我正在使用集群模式。

我将dotenv作为开发依赖项安装在根目录下(我也使用了yarn工作区)。

然后我做了这个:

require('dotenv').config({ path: 'path/to/your/.env' })

module.exports = {
    apps: [
        {
            name: 'app',
            script: 'server/dist/index.js',
            instances: 2,
            exec_mode: 'cluster',
            instance_var: 'APP_INSTANCE_SEQ',
            // listen_timeout: 10000,
            // restart_delay: 10000,
        }
    ]
}


0

这是我的项目设置..

/src/app.ts

然后编译成 dist 文件夹。

/dist/app.js

我的 .env 文件在 dist 文件夹外面,所以它是无法访问的。

这是我尝试的命令。 pm2 start app.js --env=.env


1
好了,它起作用了吗? - Miguel Stevens
是的,我的 .env 文件位于 app.ts 文件中。 - Subham kuswa

0
我使用了一个更简单的版本,基于@Marcos的答案:
.env
app.js

例如,我们需要将令牌存储在.env文件中,并将其传递到app.js中: 在.env文件内部。
token=value

在 app.js 中:
require('dotenv').config();
console.log(process.env.token)

另外,不要忘记。如果您将.env文件添加到.gitignore中,然后在VPS或其他地方上使用git pull,您需要手动复制.env文件,否则您的应用程序将无法正常工作。

在某些情况下,您使用配置的区域很重要,因此请确保将NODE_ENV=production字符串添加到您的.env文件中。

最后,您可以直接从应用程序文件夹中使用pm2 start app.js


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