在应用程序中分离“开发”和“生产”模式的最佳方法是什么?

问题描述 投票:2回答:1

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

我已经使用第三方模块“ dotenv”在“ process.env”中隐藏了敏感信息,但是无论我处于开发模式还是生产环境,在此处都拥有适当的信息仍然很令人舒服。例如,如果我在本地工作,则使用本地或云测试数据库,而当我处于生产模式时,我想为真实数据库提供适当的凭据。因此,它会根据当前模式自动切换。

下面您可以看到我到目前为止提出的内容。对于结构问题或实践,经验,我将不胜感激。

谢谢你!

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(`🚀Server ready at http://localhost:${port}${apolloServer.graphqlPath}`);
  });

})
  .catch((err) => {
    logger.error('Failed to load api', err);
  })


db类


import mongoose from 'mongoose';
import { environment } from "../environment";
import { logger } from './logging';

class Database {

  constructor() {
    this._database = 'MongoDB';
    this._username = environment.db.username;
    this._password = environment.db.password;
    this._dbName = environment.db.name;
  }

  connect() {
    mongoose.Promise = global.Promise;

    const url = `mongodb+srv://${this._username}:${this._password}@cocoondb-qx9lu.mongodb.net/${this._dbName}?retryWrites=true&w=majority`;

    try {
      mongoose.connect(url, { useNewUrlParser: true, useUnifiedTopology: true });
      mongoose.connection.once('open', () => logger.info(`Connected to ${this._database}`));
      mongoose.connection.on('error', err => logger.error(err));
    } catch (e) {
      logger.error(`Something went wrong trying to connect to the database: ${this._database}`)
    }
  }
}

export const database = new Database();


environment / index.js


import { development } from './develepment';
import { production } from './production';
import { merge } from "lodash"

const mode = process.env.NODE_ENV ? 'production' : 'development';
const values = process.env.NODE_ENV ? production : development;

export const environment = merge(values, { mode });

development.js


import dotenv from 'dotenv';
dotenv.config();

export const development = {
  port: 8080,
  db: {
    username: process.env.DB_USER,
    password: process.env.DB_PASSWORD,
    name: process.env.DB_NAME
  }
};


production.js


import dotenv from 'dotenv';
dotenv.config();

export const production = {
  port: process.env.PORT,
  newfromproduction: 'jkdl',
  db: {
    test: 'test'
  }
};



file structure

src
   -environment
      - index.js
      - development.js
      - production.js
   -graphql
   -models
   -utils
   server.js

.babelrc
.env
.gitignore
package.json

node.js express structure backend apollo-server
1个回答
0
投票

我认为您在正确的道路上。在我看来,抽象出特定于环境的配置是可行的方法。

这里有几句话可以增强您的代码:

  • 我认为您不一定需要dotenv中的merge甚至是lodash来确保您的应用程序代码无论在什么环境下都能运行。
  • 您从environment/index.js导出的对象在所有环境中都应具有相同的形状,在您提供的摘录中情况并非如此。
  • 我建议您在配置中使用JSON而不是JS,但这只是一个选择。
  • 我建议使用尽可能少的环境变量。您可以仅依赖NODE_ENV(或所需的任何单个环境变量名称),并确保在运行npm start脚本时已定义该名称。

这是我建议做的代码(其中ALL_CAPS字符串应替换为在该环境中运行应用所需的实际值):

development.json

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

production.json

{
  "port": 8080,
  "db": {
    "username": "PRODUCTION_USERNAME",
    "password": "PRODUCTION_PASSWORD",
    "name": "PRODUCTION_DATABASE_NAME"
  },
  "newfromproduction": "jkdl"
}

environment / index.js

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 };

package.json

"scripts": {
  "start": "NODE_ENV=production node server",
  "start:dev": "NODE_ENV=development nodemon server"
}

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

此方法有几个好处:

  • 您不必在存储库中提交development.jsonproduction.json,因此对于不需要知道密码的开发人员来说,您的密码是安全的。如果开发人员需要配置文件才能在应用程序上工作,只需与他们共享development.json的加密版本。这并不理想,但至少您的密码未以纯文本格式存储在GitHub中。
  • [如果您需要添加其他环境(例如teststage),则只需在environment文件夹中创建JSON文件并在package.json中添加脚本(例如"start:stage": "NODE_ENV=stage node server""test": "NODE_ENV=test mocha")。无需在if中添加environment/index.js语句。

缺点:-如果NODE_ENV的值是非预期环境的字符串(例如NODE_ENV=abc123),则该应用将崩溃,因为configuration.abc123undefined,但这不一定是一件坏事,您可以还改善了我提供的用于处理这种情况的代码。

© www.soinside.com 2019 - 2024. All rights reserved.