Node.js imposta configurazioni specifiche dell'ambiente da utilizzare con everyauth


117

Sto usando node.js + express.js + everyauth.js. Ho spostato tutta la mia logica everyauth in un file di modulo

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

all'interno di questo carico il mio file di configurazione oAuth con le combinazioni chiave / segreto:

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

Questi codici sono diversi per ambienti diversi: sviluppo / messa in scena / produzione poiché i callback sono per URL diversi.

Qu. Come li imposto nella configurazione ambientale per filtrare attraverso tutti i moduli o posso passare il percorso direttamente nel modulo?

Impostato in env:

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

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

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

Passa

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

? spero che abbia un senso


Ho trovato una soluzione che utilizza alcune delle idee dal basso, avendo il module = function piuttosto che un oggetto posso valutare process.env.NODE_ENV e restituire l'oggetto corretto per l'ambiente. Un po 'disordinato ma funziona.
andy t

Perdonate la spudorata autopromozione, ma ho scritto un modulo per node.js che lo farà tramite file separati e un interruttore della riga di comando: node-configure
Randolpho

Risposte:


192

La mia soluzione

caricare l'app utilizzando

NODE_ENV=production node app.js

Quindi imposta config.jscome una funzione piuttosto che un oggetto

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

        case 'production':
            return {prod settings};

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

Quindi, come per la soluzione Jans, caricare il file e creare una nuova istanza che potremmo passare in un valore se necessario, in questo caso process.env.NODE_ENVè globale quindi non necessario.

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

Quindi possiamo accedere alle proprietà dell'oggetto di configurazione esattamente come prima

conf.twitter.consumerKey

2
Perché stai usando nuovo qui?
bluehallu

5
Secondo @bluehallu. È newnecessario?
Sung Cho

2
l'equivalente in Windows sarebbe SET NODE_ENV = development
mujaffars

3
Invece di fare new. config.jsConfig = function(){...}; module.exports = Config()
Seguo

E se avessi 50 server web, nel qual caso sarà difficile accedere a ciascun server per avviare manualmente lo script
Rajesh

60

Potresti anche avere un file JSON con NODE_ENV come livello superiore. IMO, questo è un modo migliore per esprimere le impostazioni di configurazione (invece di utilizzare uno script che restituisce le impostazioni).

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

Esempio per env.json:

{
    "development": {
        "MONGO_URI": "mongodb://localhost/test",
        "MONGO_OPTIONS": { "db": { "safe": true } }
    },
    "production": {
        "MONGO_URI": "mongodb://localhost/production",
        "MONGO_OPTIONS": { "db": { "safe": true } }
    }
}

Salve, potresti spiegare perché ritieni che questo sia un modo migliore per esprimere le impostazioni di configurazione (invece di utilizzare uno script che restituisce le impostazioni). ?
Venkat Kotra

14
Immagino che non faccia molta differenza. Mentalmente, quando vedo JSON penso a "dati statici" rispetto a quando vedo un file JS, penso che ci sia una logica al suo interno. Inoltre, un altro vantaggio dell'utilizzo del tipo .json è che altre lingue possono importare lo stesso file.
mattwad

1
Configurazione @VenkatKotra è generalmente considerato statico, e quindi esprime al meglio in modo dichiarativo con le cose come JSON, YAML, ini, ecc Fatto imperativamente, con uno script che i rendimenti quello stato, implica sortof qualcosa di dinamico sta accadendo, che sarebbe male.
max

9
Tenere presente che questo metodo espone le credenziali nel controllo del codice sorgente.
Pier-Luc Gendreau

posso fare diffrence url per staging e produzione?
Alex

35

Una soluzione molto utile è utilizzare il modulo di configurazione .

dopo aver installato il modulo:

$ npm install config

È possibile creare un file di configurazione default.json . (puoi usare un oggetto JSON o JS usando l'estensione .json5)

Per esempio

$ vi config/default.json

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

Questa configurazione predefinita potrebbe essere sovrascritta dal file di configurazione dell'ambiente o da un file di configurazione locale per un ambiente di sviluppo locale:

production.json potrebbe essere:

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

development.json potrebbe essere:

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

Nel tuo PC locale potresti avere un local.json che sovrascrive tutto l'ambiente, oppure potresti avere una configurazione locale specifica come local-production.json o local-development.json .

L' elenco completo dell'ordine di caricamento .

Nella tua app

Nella tua app devi solo richiedere la configurazione e l'attributo necessario.

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

Carica l'app

caricare l'app utilizzando:

NODE_ENV=production node app.js

o impostando l'ambiente corretto con forever o pm2

Per sempre:

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

PM2 (tramite shell):

export NODE_ENV=staging
pm2 start app.js

PM2 (tramite .json):

process.json

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

E poi

$ pm2 start process.json --env production

Questa soluzione è molto pulita e rende facile impostare diversi file di configurazione per l'ambiente di produzione / gestione temporanea / sviluppo e anche per l'impostazione locale.


npm install config --save, non è meglio?
stackdave

15

In breve

Questo tipo di configurazione è semplice ed 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

Per eseguire in modalità di produzione: $ NODE_ENV=production node app.js


In dettaglio

Questa soluzione proviene da: http://himanshu.gilani.info/blog/2012/09/26/bootstraping-a-node-dot-js-app-for-dev-slash-prod-environment/ , dai un'occhiata per più dettaglio.


5

Il modo in cui lo facciamo è passare un argomento quando si avvia l'app con l'ambiente. Per esempio:

node app.js -c dev

In app.js cariciamo quindi dev.jscome nostro file di configurazione. Puoi analizzare queste opzioni con optparse-js .

Ora hai alcuni moduli principali che dipendono da questo file di configurazione. Quando li scrivi come tali:

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

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

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

E puoi chiamarlo quindi in app.jscome:

var Workspace = require("workspace");
this.workspace = new Workspace(config);

Preferirei mantenere tutta la logica all'interno del app.configure('developmentcodice app.js , ma darò un'occhiata per vedere se posso usare questa soluzione con quella
andy t

Aggiornamento a questa risposta: Architect è un framework di gestione delle dipendenze che risolve questo problema in un modo migliore.
Jan Jongboom

5

Un modo elegante consiste nell'usare il .envfile per sovrascrivere localmente le impostazioni di produzione. Non sono necessarie opzioni della riga di comando. Non c'è bisogno di tutte quelle virgole e parentesi in un config.jsonfile. Vedi la mia risposta qui

Esempio: sulla mia macchina il .envfile è questo:

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

Il mio locale .envsovrascrive qualsiasi variabile di ambiente. Ma sui server di staging o di produzione (forse sono su heroku.com) le variabili di ambiente sono preimpostate per la fase NODE_ENV=stageo la produzione NODE_ENV=prod.


4

imposta la variabile di ambiente nel server di distribuzione (es: come NODE_ENV = produzione). È possibile accedere alla variabile ambientale tramite process.env.NODE_ENV. Trova il seguente file di configurazione per le impostazioni globali

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 : 'some@user.com',
    },
    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 configurazione comune per tutti gli ambienti.

quindi importa in altri moduli come

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

Codifica felice ...


3

Che ne dici di farlo in un modo molto più elegante con il modulo nodejs-config .

Questo modulo è in grado di impostare l'ambiente di configurazione in base al nome del computer. Dopodiché, quando richiedi una configurazione otterrai un valore specifico per l'ambiente.

Ad esempio, supponiamo di avere due macchine di sviluppo denominate pc1 e pc2 e una macchina di produzione denominata pc3. Ogni volta che si richiedono valori di configurazione nel codice in pc1 o pc2, è necessario ottenere la configurazione dell'ambiente di "sviluppo" e in pc3 è necessario ottenere la configurazione dell'ambiente di "produzione". Questo può essere ottenuto in questo modo:

  1. Crea un file di configurazione di base nella directory config, diciamo "app.json" e aggiungici le configurazioni richieste.
  2. Ora crea semplicemente delle cartelle all'interno della directory di configurazione che corrisponde al nome del tuo ambiente, in questo caso "sviluppo" e "produzione".
  3. Successivamente, crea i file di configurazione che desideri sovrascrivere e specifica le opzioni per ogni ambiente nelle directory dell'ambiente (nota che non devi specificare tutte le opzioni che si trovano nel file di configurazione di base, ma solo le opzioni che desideri sovrascrivere. i file di configurazione dell'ambiente "si sovrappongono" ai file di base.).

Ora crea una nuova istanza di configurazione con la seguente sintassi.

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

   }
);

Ora puoi ottenere qualsiasi valore di configurazione senza preoccuparti dell'ambiente in questo modo:

config.get('app').configurationKey;

0

Questa risposta non è qualcosa di nuovo. È simile a ciò che ha menzionato @andy_t. Ma utilizzo lo schema seguente per due motivi.

  1. Implementazione pulita senza dipendenze npm esterne

  2. Unisci le impostazioni di configurazione predefinite con le impostazioni basate sull'ambiente.

Implementazione 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] }

Di solito uso il dattiloscritto nel mio progetto nodo. Di seguito è riportata la mia implementazione effettiva con copia incollata.

Implementazione del dattiloscritto

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)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.