Passando argumentos para requerer (ao carregar o módulo)

113

É possível passar argumentos ao carregar um módulo usando require?

Eu tenho o módulo, login.js, que fornece funcionalidade de login. Ele requer uma conexão de banco de dados e eu quero que a mesma conexão de banco de dados seja usada em todos os meus módulos. Agora exporto uma função login.setDatabase (...) que me permite especificar uma conexão de banco de dados e que funciona perfeitamente. Mas prefiro passar o banco de dados e quaisquer outros requisitos ao carregar o módulo.

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

Eu sou muito novo com NodeJS e normalmente desenvolvo usando Java e o Spring Framework, então sim ... esta é uma injeção de construtor :) É possível fazer algo como o código que forneci acima?

Andreas Selenwall
fonte
Eu também recomendo olhar para as respostas a esta pergunta. Conforme apontado em minha resposta, um idioma comum é passar o appobjeto para os módulos necessários.
David Weldon
Em vez de passar todo esse argumento para db, você poderia usar uma implementação de singleton e chamar db.getInstance () onde necessário.
wulfgarpro

Respostas:

236

Com base em seus comentários nesta resposta , faço o que você está tentando fazer assim:

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

Eu estruturo praticamente todos os meus módulos assim. Parece funcionar bem para mim.

floatingLomas
fonte
O appargumento é necessário ou posso omiti-lo? Meu módulo não fará uso explícito desse argumento do app, mas não sei se ele é exigido pelo node.js para alguma coisa interna. Se estiver tudo bem, minha declaração de módulo ficaria assim:module.exports = function (db) {
Ulysses Alves
Isso era específico para um aplicativo Express, então definitivamente não é necessário.
floatingLomas de
@floatingLomas O mecanismo de serialização em python é chamado pickle: stackoverflow.com/questions/11218477/…
SadSeven
1
Então, o que acontece se você fizer referência ao módulo várias vezes? O primeiro require(mymodule)(myargs)forneceria um módulo para trabalhar. No entanto, se você referenciá-lo em outro lugar de outro módulo ?? no sistema básico parece haver um cache envolvido, mas neste sistema, o cache retornaria o método do gerador vazio nas chamadas subsequentes para require(), e se você passasse args pararequire()(someargs) você receberia um módulo diferente de volta ... talvez eu não esteja algo
Tom H
2
@TomH Nesse caso, você deseja armazená-lo em cache. Para fazer isso, você teria que var module;sair da função de exportação e, assim que entrar na, verificar semodule já está definido e, em caso afirmativo, basta retorná-lo (e se não, inicializá-lo). Isso faz sentido?
flutuanteLomas
37

Não tenho certeza se isso ainda será útil para as pessoas, mas com ES6 eu tenho uma maneira de fazer isso que considero limpa e útil.

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

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

E então você obtém o comportamento esperado.

var MyClass = require('/MyClass.js')( arg1, arg2, arg3 )
vovkman
fonte
32

Sim. Em seu loginmódulo, apenas exporte uma única função que tenha o dbcomo seu argumento. Por exemplo:

module.exports = function(db) {
  ...
};
David Weldon
fonte
1
Eu tentei isso. Em login.js, module.exports = function(app,db) { ... } module.exports.auth = function(req,res) { ... authentication stuff } ele chama a função "anônima" e define as variáveis appe db, mas, ao fazer isso, meu aplicativo não encontrará a authfunção. O que estou fazendo de errado? Se eu remover a função anônima, a authfunção ficará acessível novamente.
Andreas Selenwall,
Como tudo em javascript, exportsé um objeto. Você pode atribuir propriedades a ele (várias exportações) ou pode atribuí-lo a um valor. Parece que você atribuiu exportações a uma função, mas então atribuiu auth como uma propriedade da função que atribuiu às exportações. Portanto, você precisa fazer o var auth = require("./login.js").authque pode não ser o que você pretendia. Se você quiser usar o padrão da pergunta original, provavelmente é melhor manter um único valor de exportação. Se isso ainda não fizer sentido, recomendo postar uma ideia geral para eu dar uma olhada.
David Weldon,
1
Depois de ler isso novamente, parece que você pode ter atribuído authcomo uma propriedade do exportsobjeto e, posteriormente, no módulo que atribuiu exportsa uma função (substituindo assim a atribuição anterior). Se você inverter a ordem da atribuição, poderá acessar a authfunção conforme o esperado. Novamente, é difícil saber sem realmente ver o código.
David Weldon,
1
Muito obrigado por sua ajuda. O que eu não percebi era exatamente o que você queria com require ('login'). Auth. Achei que não houvesse diferença em var login = require('login')e var login = require('login')(app), mas há uma enorme diferença, não há mágica na função anônima retornada, é apenas outra função / objeto. Em vez de ter um module.exports.auth, a função retorna anomymous agora a função de autenticação (amongs outros), ou seja return { auth: authFunction, login: loginFunction}. Então agora funciona. Obrigado.
Andreas Selenwall