Node.js “最好的分离方法是什么?”;发展";及;prod";应用程序中的模式?

Node.js “最好的分离方法是什么?”;发展";及;prod";应用程序中的模式?,node.js,express,structure,backend,apollo-server,Node.js,Express,Structure,Backend,Apollo Server,今天我试图找到一种方法来分离模式之间的全局变量:prod和dev 我已经使用第三方模块“dotenv”在“process.env”中隐藏了敏感信息,但无论我处于开发模式还是生产模式,在那里都可以获得适当的信息。例如,如果我在本地工作,我使用的是本地或云测试数据库,当我处于prod模式时,我希望拥有真实数据库的正确凭据。因此,它会根据当前模式自动切换 下面你可以看到我到目前为止的想法。如果您能就结构问题或实践、经验提出任何建议,我将不胜感激 提前谢谢你 server.js import { en

今天我试图找到一种方法来分离模式之间的全局变量:prod和dev

我已经使用第三方模块“dotenv”在“process.env”中隐藏了敏感信息,但无论我处于开发模式还是生产模式,在那里都可以获得适当的信息。例如,如果我在本地工作,我使用的是本地或云测试数据库,当我处于prod模式时,我希望拥有真实数据库的正确凭据。因此,它会根据当前模式自动切换

下面你可以看到我到目前为止的想法。如果您能就结构问题或实践、经验提出任何建议,我将不胜感激

提前谢谢你

server.js


import { environment } from "./environment";
import { apiExplorer } from "./graphql";
import express from "express";
import { ApolloServer } from "apollo-server-express";
import { database } from "./utils/database";
import { logger } from "./utils/logging";
import { verify } from "./utils/jwt";

database.connect();

apiExplorer.getSchema().then((schema) => {

  // Configure express
  const port = environment.port;
  const app = express();

  // Configure apollo
  const apolloServer = new ApolloServer({
    schema,
    context: ({ req, res }) => {
      const context = [];

      // verify jwt token
      context.authUser = verify(req, res);

      return context;
    },

    formatError: (error) => {
      logger.error(error);
      return error;
    },

    debug: true

  });
  apolloServer.applyMiddleware({ app });

  app.listen({ port }, () => {
    logger.info(`I think you're on the right path. Abstracting away the environment-specific configuration is the way to go in my opinion.

Here are a couple of remarks to enhance your code:

  • I don't think you necessarily need
    dotenv
    or even
    merge
    from
    lodash
    to make sure that your application code runs regardless of the environment it is in.
  • The object you export from
    environment/index.js
    should have the same shape for all environments to avoid errors that occur only in one environment, which is not the case in the snippets you provided.
  • I would suggest using JSON instead of JS for your config, but that's just a preference.
  • I would advise to use as little environment variables as possible. You can simply rely on
    NODE_ENV
    (or whatever single environment variable name you want) and make sure that it is defined when you run your
    npm start
    script.
Here is the code of what I would recommend to do (where ALL_CAPS strings should be replaced by the actual values you need for your app to run in that environment):

development.json

{
  "port": 8080,
  "db": {
    "username": "DEVELOPMENT_USERNAME",
    "password": "DEVELOPMENT_PASSWORD",
    "name": "DEVELOPMENT_DATABASE_NAME"
  },
  "newfromproduction": ""
}

从“/environment”导入{environment};
从“/graphql”导入{apiExplorer};
从“快递”导入快递;
从“阿波罗服务器快车”导入{ApolloServer};
从“/utils/database”导入{database}”;
从“/utils/logging”导入{logger};
从“/utils/jwt”导入{verify}”;
connect();
apiExplorer.getSchema()。然后((架构)=>{
//配置express
const port=environment.port;
常量app=express();
//配置阿波罗
const阿波罗服务器=新阿波罗服务器({
模式,
上下文:({req,res})=>{
常量上下文=[];
//验证jwt令牌
context.authUser=验证(req,res);
返回上下文;
},
formatError:(错误)=>{
记录器错误(error);
返回误差;
},
调试:正确
});
apolloServer.applyMiddleware({app});
app.listen({port},()=>{

logger.info(`我认为您走的是正确的道路。在我看来,抽象出特定于环境的配置是一种方法

下面是几句话来增强您的代码:

  • 我认为您不一定需要
    dotenv
    或甚至
    merge
    from
    lodash
    来确保您的应用程序代码在任何环境下都能运行
  • environment/index.js
    导出的对象对于所有环境都应该具有相同的形状,以避免仅在一个环境中发生错误,而您提供的代码段中并非如此
  • 我建议在配置中使用JSON而不是JS,但这只是一种偏好
  • 我建议使用尽可能少的环境变量。您可以简单地依赖
    NODE_ENV
    (或任何您想要的单个环境变量名称),并确保在运行
    npm start
    脚本时定义它
以下是我建议执行的操作代码(所有的_CAPS字符串都应该替换为应用程序在该环境中运行所需的实际值):

development.json

production.json

环境/index.js

package.json

您可以将
server.js中的代码保持不变

这种方法有几个好处:

  • 您不必在存储库中提交
    development.json
    production.json
    ,因此您的密码对不需要知道密码的开发人员来说是安全的。如果开发人员需要配置文件来处理应用程序,只需与他们共享一个加密版本的
    development.json
    。这并不理想,但至少是t您的密码未以明文形式存储在GitHub中
  • 如果需要添加其他环境(如
    test
    stage
    ),只需在
    environment
    文件夹中创建一个JSON文件,并在
    package.JSON
    中添加一个脚本(例如
    “start:stage”:“NODE_ENV=stage NODE server”
    “test”:“NODE_ENV=test mocha”
    )。无需在
    environment/index.js
    中添加
    if
    语句
一个小缺点:

  • 如果
    NODE_ENV
    的值是一个不符合预期的环境的字符串(例如
    NODE_ENV=abc123
    ),则应用程序将因
    配置而崩溃。abc123
    未定义的
    ,但这不一定是坏事(拥有意外的环境不是一个好主意)您还可以改进我提供的用于处理这种情况的代码

非常感谢您的评论!我只是认为敏感信息应该存储在系统环境中的某个地方,并且可以忽略(不包括.env文件)。在浏览了大量推荐使用DOTENV的文章之后,我从来没有使用过environment。我真的很想在没有它的情况下编写一个小偷派对模块,只是为了提高我的技能。我使用LODASH,因为一开始我认为会有很多信息需要合并。是的!我同意这两种环境s应该与相同的结构相似。我也在这方面,但首先想听听其他人的意见。是的,我在启动appAs时在脚本中设置了变量,我在“此方法的好处”中提到过,您不必提交配置。请确保在对其进行否决表决之前阅读并理解答案。您可以使用
dotenv
lodash
如果您愿意,但这不是必要的,即使对于复杂的配置文件也是如此。在过去的两年中,我一直在使用在AWS上的多个环境中运行的应用程序,因此我对这一主题有所了解。事实上,使用AWS Secrets Manager之类的工具更适合存储敏感信息。如果您d一个比这个更好的方法,我很想听到。事实上,当它已经被否决时,我投了更高的票。我感谢你的帮助,我也一直很想听到其他人的声音。我想提高我的编程技能和经验,听到在这个领域有技能和经验的人对我来说非常重要
{
  "port": 8080,
  "db": {
    "username": "PRODUCTION_USERNAME",
    "password": "PRODUCTION_PASSWORD",
    "name": "PRODUCTION_DATABASE_NAME"
  },
  "newfromproduction": "jkdl"
}
import development from './development.json';
import production from './production.json';

const { NODE_ENV: mode } = process.env;

const configuration = {
  development,
  production
};

// using a little bit of destructuring magic but that is not necessary
export default { ...configuration[mode], mode };
"scripts": {
  "start": "NODE_ENV=production node server",
  "start:dev": "NODE_ENV=development nodemon server"
}