Node.js configura configuraciones específicas del entorno para usar con everyauth

117

Estoy usando node.js + express.js + everyauth.js. He movido toda mi lógica de everyauth a un archivo de módulo

var login = require('./lib/everyauthLogin');

dentro de esto, cargo mi archivo de configuración oAuth con las combinaciones de clave / secreto:

var conf = require('./conf');
.....
twitter: {
    consumerKey: 'ABC', 
    consumerSecret: '123'
}

Estos códigos son diferentes para diferentes entornos: desarrollo / preparación / producción, ya que las devoluciones de llamada son a diferentes URL.

Qu. ¿Cómo configuro estos en la configuración ambiental para filtrar a través de todos los módulos o puedo pasar la ruta directamente al módulo?

Establecer en env:

app.configure('development', function(){
  app.set('configPath', './confLocal');
});

app.configure('production', function(){
  app.set('configPath', './confProduction');
});

var conf = require(app.get('configPath'));

Aconteció en

app.configure('production', function(){
  var login = require('./lib/everyauthLogin', {configPath: './confProduction'});
});

? espero que tenga sentido

Andy t
fuente
Encontré una solución que usa algunas de las ideas de abajo, al tener la función module = en lugar de un objeto, puedo evaluar process.env.NODE_ENV y devolver el objeto correcto para el entorno. Un poco desordenado pero funciona.
andy t
Disculpe la autopromoción descarada, pero escribí un módulo para node.js que hará esto a través de archivos separados y un interruptor de línea de comandos: node-configure
Randolpho

Respuestas:

192

Mi solución,

cargar la aplicación usando

NODE_ENV=production node app.js

Luego configúrelo config.jscomo una función en lugar de un objeto

module.exports = function(){
    switch(process.env.NODE_ENV){
        case 'development':
            return {dev setting};

        case 'production':
            return {prod settings};

        default:
            return {error or other settings};
    }
};

Luego, según la solución de Jans, cargue el archivo y cree una nueva instancia que podríamos pasar en un valor si es necesario, en este caso process.env.NODE_ENVes global, por lo que no es necesario.

var Config = require('./conf'),
    conf = new Config();

Entonces podemos acceder a las propiedades del objeto de configuración exactamente como antes

conf.twitter.consumerKey
Andy t
fuente
2
¿Por qué estás usando nuevo aquí?
bluehallu
5
Yo segundo @bluehallu. Es newnecesario?
Sung Cho
2
el equivalente en Windows sería SET NODE_ENV = desarrollo
mujaffars
3
En lugar de hacer new. Lo sigo en el config.js....Config = function(){...}; module.exports = Config()
Atu
¿Qué sucede si tengo 50 servidores web, en cuyo caso será difícil ir a cada servidor para iniciar manualmente el script
Rajesh
60

También podría tener un archivo JSON con NODE_ENV como nivel superior. En mi opinión, esta es una mejor manera de expresar los ajustes de configuración (en lugar de usar un script que devuelve ajustes).

var config = require('./env.json')[process.env.NODE_ENV || 'development'];

Ejemplo de env.json:

{
    "development": {
        "MONGO_URI": "mongodb://localhost/test",
        "MONGO_OPTIONS": { "db": { "safe": true } }
    },
    "production": {
        "MONGO_URI": "mongodb://localhost/production",
        "MONGO_OPTIONS": { "db": { "safe": true } }
    }
}
mattwad
fuente
Hola, ¿podría explicar por qué cree que esta es una mejor manera de expresar los ajustes de configuración (en lugar de utilizar un script que devuelve ajustes)? ?
Venkat Kotra
14
Supongo que no hace mucha diferencia. Mentalmente, cuando veo JSON, pienso en 'datos estáticos' frente a cuando veo un archivo JS, creo que hay algo de lógica dentro de él. Además, otro beneficio de usar el tipo .json es que otros idiomas pueden importar el mismo archivo.
mattwad
1
La configuración de @VenkatKotra generalmente se considera estática y, por lo tanto, se expresa mejor de manera declarativa con cosas como json, yaml, ini, etc. Hecho imperativamente, con un script que produce ese estado, implica que algo dinámico está sucediendo, lo cual sería malo.
máximo
9
Tenga en cuenta que este método expone las credenciales en el control de código fuente.
Pier-Luc Gendreau
¿Puedo hacer una URL diferente para la puesta en escena y la producción?
Alex
34

Una solución muy útil es usar el módulo de configuración .

después de instalar el módulo:

$ npm install config

Puede crear un archivo de configuración default.json . (puede usar un objeto JSON o JS usando la extensión .json5)

Por ejemplo

$ vi config/default.json

{
  "name": "My App Name",
  "configPath": "/my/default/path",
  "port": 3000
}

Esta configuración predeterminada puede ser anulada por el archivo de configuración del entorno o un archivo de configuración local para un entorno de desarrollo local:

production.json podría ser:

{
  "configPath": "/my/production/path",
  "port": 8080
}

development.json podría ser:

{
  "configPath": "/my/development/path",
  "port": 8081
}

En su PC local, podría tener un local.json que anule todo el entorno, o podría tener una configuración local específica como local-production.json o local-development.json .

La lista completa de orden de carga .

Dentro de tu aplicación

En su aplicación, solo necesita requerir config y el atributo necesario.

var conf = require('config'); // it loads the right file
var login = require('./lib/everyauthLogin', {configPath: conf.get('configPath'));

Cargar la aplicación

cargar la aplicación usando:

NODE_ENV=production node app.js

o configurar el entorno correcto con forever o pm2

Siempre:

NODE_ENV=production forever [flags] start app.js [app_flags]

PM2 (a través de shell):

export NODE_ENV=staging
pm2 start app.js

PM2 (a través de .json):

process.json

{
   "apps" : [{
    "name": "My App",
    "script": "worker.js",
    "env": {
      "NODE_ENV": "development",
    },
    "env_production" : {
       "NODE_ENV": "production"
    }
  }]
}

Y entonces

$ pm2 start process.json --env production

Esta solución es muy limpia y facilita la configuración de diferentes archivos de configuración para el entorno de producción / puesta en escena / desarrollo y también para la configuración local.

Zauker
fuente
npm install config - guardar, ¿no es mejor?
stackdave
14

En breve

Este tipo de configuración es simple y elegante:

env.json

{
  "development": {
      "facebook_app_id": "facebook_dummy_dev_app_id",
      "facebook_app_secret": "facebook_dummy_dev_app_secret",
  }, 
  "production": {
      "facebook_app_id": "facebook_dummy_prod_app_id",
      "facebook_app_secret": "facebook_dummy_prod_app_secret",
  }
}

common.js

var env = require('env.json');

exports.config = function() {
  var node_env = process.env.NODE_ENV || 'development';
  return env[node_env];
};

app.js

var common = require('./routes/common')
var config = common.config();

var facebook_app_id = config.facebook_app_id;
// do something with facebook_app_id

Para ejecutar en modo de producción: $ NODE_ENV=production node app.js


En detalle

Esta solución es de: http://himanshu.gilani.info/blog/2012/09/26/bootstraping-a-node-dot-js-app-for-dev-slash-prod-environment/ , compruébalo para mas detalle.

kris
fuente
5

La forma en que hacemos esto es pasando un argumento al iniciar la aplicación con el entorno. Por ejemplo:

node app.js -c dev

En app.js cargamos dev.jscomo nuestro archivo de configuración. Puede analizar estas opciones con optparse-js .

Ahora tiene algunos módulos centrales que dependen de este archivo de configuración. Cuando los escribes como tales:

var Workspace = module.exports = function(config) {
    if (config) {
         // do something;
    }
}

(function () {
    this.methodOnWorkspace = function () {

    };
}).call(Workspace.prototype);

Y puedes llamarlo entonces app.jscomo:

var Workspace = require("workspace");
this.workspace = new Workspace(config);
Jan Jongboom
fuente
Preferiría mantener toda la lógica dentro del app.configure('developmentcódigo app.js , pero echaré un vistazo para ver si puedo usar esta solución con eso
andy t
Actualice esta respuesta: Architect es un marco de gestión de dependencias que resuelve esto de una manera más agradable.
Jan Jongboom
5

Una forma elegante es utilizar el .envarchivo para anular localmente la configuración de producción. No se necesitan interruptores de línea de comando. No hay necesidad de todas esas comas y corchetes en un config.jsonarchivo. Mira mi respuesta aqui

Ejemplo: en mi máquina, el .envarchivo es este:

NODE_ENV=dev
TWITTER_AUTH_TOKEN=something-needed-for-api-calls

Mi local .envanula cualquier variable de entorno. Pero en los servidores de preparación o producción (tal vez estén en heroku.com) las variables de entorno están preestablecidas para la etapa NODE_ENV=stageo la producción NODE_ENV=prod.

Benxamin
fuente
4

establezca la variable de entorno en el servidor de implementación (por ejemplo, como NODE_ENV = producción). Puede acceder a su variable de entorno a través de process.env.NODE_ENV. Busque el siguiente archivo de configuración para la configuración global

const env = process.env.NODE_ENV || "development"

const configs = {
    base: {
        env,
        host: '0.0.0.0',
        port: 3000,
        dbPort: 3306,
        secret: "secretKey for sessions",
        dialect: 'mysql',
        issuer : 'Mysoft corp',
        subject : '[email protected]',
    },
    development: {
        port: 3000,
        dbUser: 'root',
        dbPassword: 'root',

    },
    smoke: {
        port: 3000,
        dbUser: 'root',
    },
    integration: {
        port: 3000,
        dbUser: 'root',
    },
    production: {
        port: 3000,
        dbUser: 'root',
    }
};

const config = Object.assign(configs.base, configs[env]);

module.exports= config;

base contiene una configuración común para todos los entornos.

luego importar en otros módulos como

const config =  require('path/to/config.js')
console.log(config.port)

Codificación feliz ...

ajaykumar mp
fuente
3

¿Qué tal hacer esto de una manera mucho más elegante con el módulo nodejs-config ?

Este módulo puede establecer el entorno de configuración según el nombre de su computadora. Después de eso, cuando solicite una configuración, obtendrá un valor específico del entorno.

Por ejemplo, supongamos que tiene dos máquinas de desarrollo llamadas pc1 y pc2 y una máquina de producción llamada pc3. Siempre que solicite valores de configuración en su código en pc1 o pc2, debe obtener la configuración del entorno de "desarrollo" y en pc3 debe obtener la configuración del entorno de "producción". Esto se puede lograr así:

  1. Cree un archivo de configuración base en el directorio de configuración, digamos "app.json" y agregue las configuraciones requeridas.
  2. Ahora simplemente cree carpetas dentro del directorio de configuración que coincida con el nombre de su entorno, en este caso "desarrollo" y "producción".
  3. A continuación, cree los archivos de configuración que desea anular y especifique las opciones para cada entorno en los directorios del entorno (observe que no tiene que especificar todas las opciones que se encuentran en el archivo de configuración base, sino solo las opciones que desea anular. Los archivos de configuración del entorno se "caen en cascada" sobre los archivos base).

Ahora cree una nueva instancia de configuración con la siguiente sintaxis.

var config = require('nodejs-config')(
   __dirname,  // an absolute path to your applications 'config' directory
   {
      development: ["pc1", "pc2"],
      production: ["pc3"],

   }
);

Ahora puede obtener cualquier valor de configuración sin preocuparse por el entorno como este:

config.get('app').configurationKey;
Harish Anchu
fuente
0

Esta respuesta no es nueva. Es similar a lo que ha mencionado @andy_t. Pero utilizo el siguiente patrón por dos razones.

  1. Implementación limpia sin dependencias externas de npm

  2. Fusionar la configuración predeterminada con la configuración basada en el entorno.

Implementación de Javascript

const settings = {
    _default: {
       timeout: 100
       baseUrl: "http://some.api/",
    },
    production: {
       baseUrl: "http://some.prod.api/",
    },
}
// If you are not using ECMAScript 2018 Standard
// https://stackoverflow.com/a/171256/1251350
module.exports = { ...settings._default, ...settings[process.env.NODE_ENV] }

Normalmente uso mecanografiado en mi proyecto de nodo. A continuación se muestra mi implementación real copiada y pegada.

Implementación de TypeScript

const settings: { default: ISettings, production: any } = {
    _default: {
        timeout: 100,
        baseUrl: "",
    },
    production: {
        baseUrl: "",
    },
}

export interface ISettings {
    baseUrl: string
}

export const config = ({ ...settings._default, ...settings[process.env.NODE_ENV] } as ISettings)
Faraj Farook
fuente