Übergeben von Argumenten erforderlich (beim Laden des Moduls)

113

Ist es möglich, Argumente beim Laden eines Moduls mit require zu übergeben?

Ich habe das Modul login.js, das Anmeldefunktionen bietet. Es erfordert eine Datenbankverbindung, und ich möchte, dass in allen meinen Modulen dieselbe Datenbankverbindung verwendet wird. Jetzt exportiere ich eine Funktion login.setDatabase (...), mit der ich eine Datenbankverbindung angeben kann, und das funktioniert einwandfrei. Aber ich würde lieber die Datenbank und andere Anforderungen übergeben, wenn ich das Modul lade.

var db = ...
var login = require("./login.js")(db);

Ich bin ziemlich neu in NodeJS und entwickle normalerweise mit Java und dem Spring Framework, also ja ... das ist eine Konstruktorinjektion :) Ist es möglich, so etwas wie den Code zu machen, den ich oben angegeben habe?

Andreas Selenwall
quelle
Ich würde auch empfehlen, die Antworten auf diese Frage zu lesen. Wie in meiner Antwort ausgeführt, besteht eine übliche Redewendung darin, das appObjekt an die erforderlichen Module zu übergeben.
David Weldon
Anstatt all diese Argumente für db zu übergeben, können Sie eine Singleton- Implementierung verwenden und bei Bedarf db.getInstance () aufrufen.
Wulfgarpro

Antworten:

236

Basierend auf Ihren Kommentaren in dieser Antwort mache ich das, was Sie versuchen, so:

module.exports = function (app, db) {
    var module = {};

    module.auth = function (req, res) {
        // This will be available 'outside'.
        // Authy stuff that can be used outside...
    };

    // Other stuff...
    module.pickle = function(cucumber, herbs, vinegar) {
        // This will be available 'outside'.
        // Pickling stuff...
    };

    function jarThemPickles(pickle, jar) {
        // This will be NOT available 'outside'.
        // Pickling stuff...

        return pickleJar;
    };

    return module;
};

Ich strukturiere so ziemlich alle meine Module so. Scheint gut für mich zu funktionieren.

floatLomas
quelle
Ist das appArgument notwendig oder kann ich es weglassen? Mein Modul verwendet dieses App-Argument nicht explizit, aber ich weiß nicht, ob es von node.js für eine interne Sache benötigt wird. Wenn es in Ordnung ist, würde meine Moduldeklaration so aussehen:module.exports = function (db) {
Ulysses Alves
Das war spezifisch für eine Express-App, also definitiv nicht notwendig.
FloatingLomas
@floatingLomas Der Serialisierungsmechanismus in Python heißt pickle
SadSeven
1
Was passiert also, wenn Sie das Modul mehrmals referenzieren? Das erste require(mymodule)(myargs)würde Ihnen ein Modul geben, mit dem Sie arbeiten können. Wenn Sie jedoch von einem anderen Modul auf eine andere Stelle verweisen? Im Basissystem scheint es sich um einen Cache zu handeln, aber in diesem System würde der Cache bei nachfolgenden Aufrufen die Bare-Generator-Methode zurückgeben require(), und wenn Sie Argumente an übergeben, erhalten require()(someargs)Sie ein anderes Modul zurück ... Vielleicht fehlt es mir etwas
Tom H
2
@ TomH In diesem Fall möchten Sie es zwischenspeichern. Um dies zu tun, hätten Sie var module;außerhalb der Exportfunktion, und sobald Sie in die kommen, möchten Sie überprüfen, ob modulebereits definiert ist, und wenn ja, geben Sie es einfach zurück (und wenn nicht, initialisieren Sie es). Ist das sinnvoll?
FloatingLomas
37

Ich bin mir nicht sicher, ob dies für Menschen noch nützlich sein wird, aber mit ES6 habe ich eine Möglichkeit, die ich sauber und nützlich finde.

class MyClass { 
  constructor ( arg1, arg2, arg3 )
  myFunction1 () {...}
  myFunction2 () {...}
  myFunction3 () {...}
}

module.exports = ( arg1, arg2, arg3 ) => { return new MyClass( arg1,arg2,arg3 ) }

Und dann bekommen Sie Ihr erwartetes Verhalten.

var MyClass = require('/MyClass.js')( arg1, arg2, arg3 )
Vovkman
quelle
32

Ja. loginExportieren Sie in Ihrem Modul einfach eine einzelne Funktion, dbderen Argument das Argument ist. Beispielsweise:

module.exports = function(db) {
  ...
};
David Weldon
quelle
1
Ich habe es ausprobiert. In login.js module.exports = function(app,db) { ... } module.exports.auth = function(req,res) { ... authentication stuff } ruft es die "anonyme" Funktion auf und setzt die appund dbVariablen, aber wenn ich dies tue, findet meine Anwendung die authFunktion nicht. Was mache ich falsch? Wenn ich die anonyme Funktion entferne, wird die authFunktion wieder zugänglich.
Andreas Selenwall
Wie alles in Javascript exportsist es ein Objekt. Sie können ihm Eigenschaften zuweisen (mehrere Exporte) oder einem Wert zuweisen. Es hört sich so an, als hätten Sie einer Funktion Exporte zugewiesen, dann aber auth als Eigenschaft der Funktion zugewiesen, die Sie Exporten zugewiesen haben. Sie müssten also etwas tun, var auth = require("./login.js").authwas möglicherweise nicht das ist, was Sie beabsichtigt haben. Wenn Sie das Muster aus der ursprünglichen Frage verwenden möchten, ist es wahrscheinlich am besten, sich an einen einzelnen Exportwert zu halten. Wenn dies immer noch keinen Sinn ergibt, würde ich empfehlen, einen Kern zu veröffentlichen, den ich mir ansehen kann.
David Weldon
1
Nach dem erneuten Lesen klingt es so, als hätten Sie möglicherweise autheine Eigenschaft des exportsObjekts zugewiesen und später in dem Modul, das Sie exportseiner Funktion zugewiesen haben (wodurch die vorherige Zuweisung überschrieben wurde). Wenn Sie die Reihenfolge der Zuordnung umkehren, sollten authSie wie erwartet auf die Funktion zugreifen können . Wieder ist es schwer zu sagen, ohne den Code tatsächlich zu sehen.
David Weldon
1
Vielen dank für Deine Hilfe. Was mir nicht klar war, war genau das, was Sie mit require ('login') anstrebten. Auth. Ich dachte, es gab keinen Unterschied in var login = require('login')und var login = require('login')(app), aber es gibt einen großen Unterschied, es gibt keine Magie in der zurückgegebenen anonymen Funktion, es ist nur eine andere Funktion / ein anderes Objekt. Anstelle von a module.exports.authgibt die anomymische Funktion jetzt (unter anderem) die Auth-Funktion zurück, d return { auth: authFunction, login: loginFunction}. H. Jetzt funktioniert es also. Vielen Dank.
Andreas Selenwall