Node.js richtet umgebungsspezifische Konfigurationen ein, die mit everyauth verwendet werden sollen

117

Ich benutze node.js + express.js + everyauth.js. Ich habe meine gesamte Logik in eine Moduldatei verschoben

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

Darin lade ich meine oAuth-Konfigurationsdatei mit den Schlüssel / Geheimnis-Kombinationen:

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

Diese Codes sind für verschiedene Umgebungen unterschiedlich - Entwicklung / Staging / Produktion, da sich die Rückrufe auf verschiedene URLs beziehen.

Qu. Wie stelle ich diese in der Umgebungskonfiguration so ein, dass sie durch alle Module filtern, oder kann ich den Pfad direkt in das Modul übergeben?

Set in env:

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

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

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

Pass in

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

? hoffe das macht Sinn

andy t
quelle
Ich habe eine Lösung gefunden, die einige der folgenden Ideen verwendet, indem ich die Funktion module = anstelle eines Objekts habe. Ich kann process.env.NODE_ENV auswerten und das richtige Objekt für die Umgebung zurückgeben. Ein bisschen chaotisch, funktioniert aber.
Andy t
Verzeihen Sie die schamlose Eigenwerbung, aber ich habe ein Modul für node.js geschrieben, das dies über separate Dateien und einen Befehlszeilenschalter erledigt: node-configure
Randolpho

Antworten:

192

Meine Lösung,

Laden Sie die App mit

NODE_ENV=production node app.js

Dann config.jsals Funktion und nicht als Objekt einrichten

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

        case 'production':
            return {prod settings};

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

Laden Sie dann gemäß Jans-Lösung die Datei und erstellen Sie eine neue Instanz, die wir bei Bedarf als Wert übergeben können. In diesem Fall process.env.NODE_ENVist sie global und wird daher nicht benötigt.

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

Dann können wir genau wie zuvor auf die Eigenschaften des Konfigurationsobjekts zugreifen

conf.twitter.consumerKey
andy t
quelle
2
Warum verwenden Sie hier neu?
Bluehallu
5
Ich zweite @bluehallu. Ist newnotwendig?
Sung Cho
2
Das Äquivalent in Windows wäre SET NODE_ENV = Entwicklung
Mujaffars
3
Anstatt zu tun new. Ich folge in der config.js....Config = function(){...}; module.exports = Config()
Atu
Was ist, wenn ich 50 Webserver habe? In diesem Fall wird es schwierig sein, zu jedem Server zu wechseln, um das Skript manuell zu initiieren
Rajesh
60

Sie können auch eine JSON-Datei mit NODE_ENV als oberster Ebene haben. IMO, dies ist eine bessere Möglichkeit, Konfigurationseinstellungen auszudrücken (im Gegensatz zur Verwendung eines Skripts, das Einstellungen zurückgibt).

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

Beispiel für 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
quelle
Hallo, könnten Sie bitte erklären, warum Sie der Meinung sind, dass dies eine bessere Möglichkeit ist, Konfigurationseinstellungen auszudrücken (im Gegensatz zur Verwendung eines Skripts, das Einstellungen zurückgibt). ?
Venkat Kotra
14
Ich denke, es macht keinen allzu großen Unterschied. Wenn ich JSON sehe, denke ich, dass 'statische Daten' im Vergleich zu einer JS-Datei eine Logik enthalten sind. Ein weiterer Vorteil der Verwendung des Typs .json besteht darin, dass andere Sprachen dieselbe Datei importieren können.
Mattwad
1
Die @ VenkatKotra-Konfiguration wird im Allgemeinen als statisch betrachtet und daher am besten deklarativ mit Dingen wie json, yaml, ini usw. ausgedrückt. Mit einem Skript, das diesen Status liefert, muss zwangsläufig etwas Dynamisches geschehen, was schlecht wäre.
Max
9
Beachten Sie, dass diese Methode Anmeldeinformationen in der Quellcodeverwaltung verfügbar macht.
Pier-Luc Gendreau
Kann ich eine andere URL für die Inszenierung und Produktion festlegen?
Alex
34

Eine sehr nützliche Lösung ist die Verwendung des Konfigurationsmoduls .

Nach der Installation des Moduls:

$ npm install config

Sie können eine Konfigurationsdatei default.json erstellen. (Sie können ein JSON- oder JS-Objekt mit der Erweiterung .json5 verwenden.)

Beispielsweise

$ vi config/default.json

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

Diese Standardkonfiguration kann durch eine Umgebungskonfigurationsdatei oder eine lokale Konfigurationsdatei für eine lokale Entwicklungsumgebung überschrieben werden:

Production.json könnte sein:

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

development.json könnte sein:

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

Auf Ihrem lokalen PC können Sie eine local.json haben , die die gesamte Umgebung überschreibt, oder Sie können eine bestimmte lokale Konfiguration als local-Production.json oder local-development.json haben .

Die vollständige Liste der Ladereihenfolge .

In Ihrer App

In Ihrer App müssen Sie nur die Konfiguration und das erforderliche Attribut benötigen.

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

Laden Sie die App

Laden Sie die App mit:

NODE_ENV=production node app.js

oder die richtige Umgebung mit forever oder pm2 einstellen

Für immer:

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

PM2 (über Shell):

export NODE_ENV=staging
pm2 start app.js

PM2 (über .json):

process.json

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

Und dann

$ pm2 start process.json --env production

Diese Lösung ist sehr sauber und erleichtert das Einstellen verschiedener Konfigurationsdateien für die Produktions- / Staging- / Entwicklungsumgebung und auch für die lokale Einstellung.

Zauker
quelle
npm install config --save, ist es nicht besser?
Stackdave
14

In Kürze

Diese Art der Einrichtung ist einfach und elegant:

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

So führen Sie den Produktionsmodus aus: $ NODE_ENV=production node app.js


Im Detail

Diese Lösung ist aus: http://himanshu.gilani.info/blog/2012/09/26/bootstraping-a-node-dot-js-app-for-dev-slash-prod-environment/ , check it out für Mehr Details.

kris
quelle
5

Wir tun dies, indem wir beim Starten der App mit der Umgebung ein Argument übergeben. Zum Beispiel:

node app.js -c dev

In app.js laden wir dann dev.jsals Konfigurationsdatei. Sie können diese Optionen mit optparse-js analysieren .

Jetzt haben Sie einige Kernmodule, die von dieser Konfigurationsdatei abhängen. Wenn Sie sie als solche schreiben:

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

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

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

Und Sie können es dann app.jswie folgt nennen :

var Workspace = require("workspace");
this.workspace = new Workspace(config);
Jan Jongboom
quelle
Ich würde lieber die gesamte Logik im app.js- app.configure('developmentCode behalten , aber ich werde schauen, ob ich diese Lösung damit verwenden kann
andy t
Update auf diese Antwort: Architect ist ein Abhängigkeitsmanagement-Framework, das dies auf eine bessere Art und Weise löst.
Jan Jongboom
5

Eine elegante Möglichkeit besteht darin, .envDateien zu verwenden, um Produktionseinstellungen lokal zu überschreiben. Keine Notwendigkeit für Befehlszeilenschalter. Alle diese Kommas und Klammern in einer config.jsonDatei sind nicht erforderlich . Siehe meine Antwort hier

Beispiel: Auf meinem Computer .envlautet die Datei wie folgt:

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

Mein lokaler .envüberschreibt alle Umgebungsvariablen. Auf den Staging- oder Produktionsservern (möglicherweise auf heroku.com) sind die Umgebungsvariablen jedoch auf Bühne NODE_ENV=stageoder Produktion voreingestellt NODE_ENV=prod.

Benxamin
quelle
4

Legen Sie die Umgebungsvariable im Bereitstellungsserver fest (Beispiel: wie NODE_ENV = Produktion). Sie können über process.env.NODE_ENV auf Ihre Umgebungsvariable zugreifen. Suchen Sie die folgende Konfigurationsdatei für die globalen Einstellungen

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 enthält eine gemeinsame Konfiguration für alle Umgebungen.

dann in andere Module wie importieren

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

Viel Spaß beim Codieren ...

ajaykumar mp
quelle
3

Wie wäre es mit dem nodejs-config- Modul auf eine viel elegantere Art und Weise ?

Dieses Modul kann die Konfigurationsumgebung basierend auf dem Namen Ihres Computers festlegen. Wenn Sie danach eine Konfiguration anfordern, erhalten Sie einen umgebungsspezifischen Wert.

Angenommen, Sie haben zwei Entwicklungsmaschinen mit den Namen pc1 und pc2 und eine Produktionsmaschine mit dem Namen pc3. Wann immer Sie Konfigurationswerte in Ihrem Code in PC1 oder PC2 anfordern, müssen Sie die Konfiguration der Entwicklungsumgebung und in PC3 die Konfiguration der Produktionsumgebung erhalten. Dies kann folgendermaßen erreicht werden:

  1. Erstellen Sie eine Basiskonfigurationsdatei im Konfigurationsverzeichnis, sagen Sie "app.json" und fügen Sie die erforderlichen Konfigurationen hinzu.
  2. Erstellen Sie nun einfach Ordner im Konfigurationsverzeichnis, die Ihrem Umgebungsnamen entsprechen, in diesem Fall "Entwicklung" und "Produktion".
  3. Erstellen Sie als Nächstes die Konfigurationsdateien, die Sie überschreiben möchten, und geben Sie die Optionen für jede Umgebung in den Umgebungsverzeichnissen an (Beachten Sie, dass Sie nicht jede Option in der Basiskonfigurationsdatei angeben müssen, sondern nur die Optionen, die Sie überschreiben möchten Umgebungskonfigurationsdateien "kaskadieren" über die Basisdateien.).

Erstellen Sie nun eine neue Konfigurationsinstanz mit der folgenden Syntax.

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

   }
);

Jetzt können Sie jeden Konfigurationswert abrufen, ohne sich um die folgende Umgebung kümmern zu müssen:

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

Diese Antwort ist nichts Neues. Es ist ähnlich wie das, was @andy_t erwähnt hat. Aber ich benutze das folgende Muster aus zwei Gründen.

  1. Saubere Implementierung ohne externe npm-Abhängigkeiten

  2. Führen Sie die Standardkonfigurationseinstellungen mit den umgebungsbasierten Einstellungen zusammen.

Javascript-Implementierung

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

Normalerweise verwende ich Typoskript in meinem Knotenprojekt. Unten ist meine tatsächliche Implementierung kopiert.

Typoskript-Implementierung

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
quelle