tutorial node framework node.js dependency-injection inversion-of-control

node.js - framework - ¿Necesito inyección de dependencia en NodeJS o cómo tratar con...?



npm install express (21)

Construí Electrolyte solo para este propósito. Las otras soluciones de inyección de dependencia eran demasiado invasivas para mi gusto, y meterme con las necesidades globales es una queja particular mía.

Electrolyte abarca módulos, específicamente aquellos que exportan una función de "configuración" como se ve en Connect / Express middleware. Esencialmente, estos tipos de módulos son solo fábricas para algunos objetos que devuelven.

Por ejemplo, un módulo que crea una conexión de base de datos:

var mysql = require(''mysql''); exports = module.exports = function(settings) { var connection = mysql.createConnection({ host: settings.dbHost, port: settings.dbPort }); connection.connect(function(err) { if (err) { throw err; } }); return connection; } exports[''@singleton''] = true; exports[''@require''] = [ ''settings'' ];

Lo que se ve en la parte inferior son las anotaciones , un poco más de metadatos que utiliza Electrolyte para crear instancias e inyectar dependencias, conectando automáticamente los componentes de la aplicación.

Para crear una conexión de base de datos:

var db = electrolyte.create(''database'');

El electrolito atraviesa transitoriamente las dependencias @require ''d e inyecta instancias como argumentos a la función exportada.

La clave es que esto es mínimamente invasivo. Este módulo es completamente utilizable, independiente de Electrolyte. Eso significa que las pruebas de su unidad pueden probar solo el módulo bajo prueba , pasando objetos falsos sin necesidad de dependencias adicionales para recablear las partes internas.

Cuando se ejecuta la aplicación completa, Electrolyte interviene en el nivel intermódulo, conectando las cosas juntas sin la necesidad de elementos globales, simples o tuberías excesivas.

Actualmente estoy creando algunos proyectos experimentales con nodejs. He programado muchas aplicaciones web Java EE con Spring y aprecié la facilidad de la inyección de dependencias allí.

Ahora tengo curiosidad: ¿cómo hago la inyección de dependencia con el nodo? O: ¿Lo necesito? ¿Hay un concepto de reemplazo, porque el estilo de programación es diferente?

Estoy hablando de cosas simples, como compartir un objeto de conexión de base de datos, hasta ahora, pero no he encontrado una solución que me satisfaga.


Creo que todavía necesitamos Inyección de Dependencia en Nodejs porque relaja las dependencias entre servicios y hace que la aplicación sea más clara.

Inspirado por Spring Framework , también implementé mi propio módulo para admitir la inyección de dependencia en Nodejs. Mi módulo también puede detectar los code changes y auto reload los servicios sin reiniciar su aplicación.

Visita mi proyecto en: Buncha - Contenedor IoC

¡Gracias!


Depende del diseño de tu aplicación. Obviamente puedes hacer una inyección tipo java donde creas un objeto de una clase con la dependencia pasada en el constructor de esta manera.

function Cache(store) { this._store = store; } var cache = new Cache(mysqlStore);

Si no está haciendo OOP en javascript, puede hacer una función init que configure todo.

Sin embargo, hay otro enfoque que puede tomar que es más común en un sistema basado en eventos como node.js. Si puedes modelar tu aplicación solo (la mayoría de las veces) para actuar sobre los eventos, entonces todo lo que tienes que hacer es configurar todo (lo que hago usualmente llamando a una función de inicio) y emitir eventos desde un stub. Esto hace que las pruebas sean más fáciles y legibles.



El di.js de Google funciona en nodejs (+ navegador) (+ ES6)


La realidad es que puede probar su node.js sin contenedor de IoC porque JavaScript es un lenguaje de programación realmente dinámico y puede modificar casi todo en tiempo de ejecución.

Considera lo siguiente:

import UserRepository from "./dal/user_repository"; class UserController { constructor() { this._repository = new UserRepository(); } getUsers() { this._repository.getAll(); } } export default UserController;

Por lo tanto, puede anular el acoplamiento entre componentes en tiempo de ejecución. Me gusta pensar que deberíamos intentar desacoplar nuestros módulos de JavaScript.

La única forma de lograr un desacoplamiento real es eliminar la referencia al UserRepository :

class UserController { constructor(userRepository) { this._repository = userRepository; } getUsers() { this._repository.getAll(); } } export default UserController;

Esto significa que en otro lugar necesitarás hacer la composición del objeto:

import UserRepository from "./dal/user_repository"; import UserController from "./dal/user_controller"; export default new UserController(new UserRepository());

Me gusta la idea de delegar la composición del objeto en un contenedor IoC. Puede obtener más información sobre esta idea en el artículo El estado actual de la inversión de la dependencia en JavaScript . El artículo trata de desacreditar algunos "mitos de contenedor JavaScript IoC":

Mito 1: no hay lugar para contenedores IoC en JavaScript

Mito 2: no necesitamos contenedores IoC, ¡ya tenemos cargadores de módulos!

Mito 3: Inversión de dependencia === dependencias de inyección

Si también te gusta la idea de usar un contenedor IoC, puedes echar un vistazo a InversifyJS. La última versión (2.0.0) admite muchos casos de uso:

  • Módulos Kernel
  • Kernel middleware
  • Use clases, cadenas literales o símbolos como identificadores de dependencia
  • Inyección de valores constantes
  • Inyección de constructores de clase
  • Inyección de fábricas
  • Auto fábrica
  • Inyección de proveedores (fábrica asíncrona)
  • Controladores de activación (utilizados para inyectar proxies)
  • Inyecciones múltiples
  • Encuadernaciones etiquetadas
  • Decoradores de etiquetas personalizadas
  • Enlaces nombrados
  • Enlaces contextuales
  • Excepciones amistosas (por ejemplo, dependencias circulares)

Puede obtener más información al respecto en InversifyJS .


Para ES6 desarrollé este contenedor https://github.com/zazoomauro/node-dependency-injection

import {ContainerBuilder} from ''node-dependency-injection'' let container = new ContainerBuilder() container.register(''mailer'', ''Mailer'')

Luego puede establecer, por ejemplo, la elección del transporte en el contenedor:

import {ContainerBuilder} from ''node-dependency-injection'' let container = new ContainerBuilder() container .register(''mailer'', ''Mailer'') .addArgument(''sendmail'')

Esta clase ahora es mucho más flexible ya que ha separado la opción de transporte de la implementación y dentro del contenedor.

Ahora que el servicio de correo está en el contenedor, puede inyectarlo como una dependencia de otras clases. Si tiene una clase de NewsletterManager como esta:

class NewsletterManager { construct (mailer, fs) { this._mailer = mailer this._fs = fs } } export default NewsletterManager

Al definir el servicio newsletter_manager, el servicio de correo aún no existe. Use la clase de referencia para indicarle al contenedor que debe inyectar el servicio de correo cuando inicializa el administrador del boletín:

import {ContainerBuilder, Reference, PackageReference} from ''node-dependency-injection'' import Mailer from ''./Mailer'' import NewsletterManager from ''./NewsletterManager'' let container = new ContainerBuilder() container .register(''mailer'', Mailer) .addArgument(''sendmail'') container .register(''newsletter_manager'', NewsletterManager) .addArgument(new Reference(''mailer'')) .addArgument(new PackageReference(''fs-extra''))

También puede configurar el contenedor con archivos de configuración como archivos Yaml, Json o JS

El contenedor de servicio se puede compilar por varias razones. Estas razones incluyen la comprobación de posibles problemas, como referencias circulares y hacer que el contenedor sea más eficiente.

container.compile()


Recientemente creé una biblioteca llamada circuitbox que le permite usar la inyección de dependencia con node.js. Realiza una verdadera inyección de dependencia frente a muchas de las bibliotecas basadas en búsqueda de dependencias que he visto. Circuitbox también admite rutinas de creación e inicialización asincrónicas. A continuación hay un ejemplo:

Suponga que el siguiente código se encuentra en un archivo llamado consoleMessagePrinter.js

''use strict''; // Our console message printer // deps is injected by circuitbox with the dependencies function ConsoleMessagePrinter(deps) { return { print: function () { console.log(deps.messageSource.message()); } }; } module.exports = ConsoleMessagePrinter;

Suponga que lo siguiente está en el archivo main.js

''use strict''; // our simple message source // deps is injected by circuitbox with the dependencies var simpleMessageSource = function (deps) { return { message: function () { return deps.message; } }; }; // require circuitbox var circuitbox = require(''../lib''); // create a circuitbox circuitbox.create({ modules: [ function (registry) { // the message to be used registry.for(''message'').use(''This is the message''); // define the message source registry.for(''messageSource'').use(simpleMessageSource) .dependsOn(''message''); // define the message printer - does a module.require internally registry.for(''messagePrinter'').requires(''./consoleMessagePrinter'') .dependsOn(''messageSource''); } ] }).done(function (cbx) { // get the message printer and print a message cbx.get(''messagePrinter'').done(function (printer) { printer.print(); }, function (err) { console.log(''Could not recieve a printer''); return; }); }, function (err) { console.log(''Could not create circuitbox''); });

Circuitbox lets you define your components and declare their dependencies as modules. Once its initialized, it allows you to retrieve a component. Circuitbox automatically injects all the components the target component requires and gives it to you for use.

The project is in alpha version. Your comments, ideas and feedback are welcome.

¡Espero eso ayude!


Recientemente revisé este hilo por la misma razón que el OP: la mayoría de las librerías que he encontrado reescriben temporalmente la declaración require. He tenido varios grados de éxito con este método, así que terminé usando el siguiente enfoque.

En el contexto de una aplicación expresa: envuelvo app.js en un archivo bootstrap.js:

var path = require(''path''); var myapp = require(''./app.js''); var loader = require(''./server/services/loader.js''); // give the loader the root directory // and an object mapping module names // to paths relative to that root loader.init(path.normalize(__dirname), require(''./server/config/loader.js'')); myapp.start();

El mapa de objeto pasado al cargador se ve así:

// live loader config module.exports = { ''dataBaseService'': ''/lib/dataBaseService.js'' } // test loader config module.exports = { ''dataBaseService'': ''/mocks/dataBaseService.js'' ''otherService'' : {other: ''service''} // takes objects too... };

Entonces, en lugar de llamar directamente requiere ...

var myDatabaseService = loader.load(''dataBaseService'');

Si no hay un alias en el cargador, se convertirá en un requerimiento regular. Esto tiene dos ventajas: puedo intercambiar cualquier versión de la clase y eliminar la necesidad de usar nombres de ruta relativos en toda la aplicación (así que si necesito una lib personalizada debajo o encima del archivo actual, no necesito atravesarlo). y requerirá almacenar en caché el módulo contra la misma clave). También me permite especificar burlas en cualquier punto de la aplicación, en lugar de en el conjunto de pruebas inmediato.

Acabo de publicar un pequeño módulo npm por conveniencia:

https://npmjs.org/package/nodejs-simple-loader


Sé que este hilo es bastante viejo en este momento, pero pensé que me gustaría dar mi opinión sobre esto. El TL; DR es que debido a la naturaleza dinámica y no tipada de JavaScript, en realidad se puede hacer bastante sin recurrir al patrón de inyección de dependencia (DI) o usar un marco DI. Sin embargo, a medida que una aplicación se hace más grande y más compleja, DI definitivamente puede ayudar a la mantenibilidad de su código.

DI en C #

Para comprender por qué DI no es una necesidad tan grande en JavaScript, es útil mirar un lenguaje fuertemente tipado como C #. (Disculpe a los que no conocen C #, pero debería ser fácil seguirlo). Digamos que tenemos una aplicación que describe un automóvil y su bocina. Definirías dos clases:

class Horn { public void Honk() { Console.WriteLine("beep!"); } } class Car { private Horn horn; public Car() { this.horn = new Horn(); } public void HonkHorn() { this.horn.Honk(); } } class Program { static void Main() { var car = new Car(); car.HonkHorn(); } }

Hay algunos problemas con la escritura del código de esta manera.

  1. La clase Car está estrechamente relacionada con la implementación particular de la bocina en la clase Horn . Si queremos cambiar el tipo de bocina utilizada por el automóvil, tenemos que modificar la clase de Car aunque su uso de la bocina no cambie. Esto también dificulta las pruebas porque no podemos probar la clase Car aisladamente de su dependencia, la clase Horn .
  2. La clase Car es responsable del ciclo de vida de la clase Horn . En un ejemplo simple como este no es un gran problema, pero en las aplicaciones reales las dependencias tendrán dependencias, que tendrán dependencias, etc. La clase Car debería ser responsable de crear todo el árbol de sus dependencias. Esto no solo es complicado y repetitivo, sino que viola la "responsabilidad única" de la clase. Debería enfocarse en ser un automóvil, no crear instancias.
  3. No hay forma de reutilizar las mismas instancias de dependencia. Nuevamente, esto no es importante en esta aplicación de juguete, pero considere una conexión de base de datos. Por lo general, tendrías una única instancia compartida en tu aplicación.

Ahora, vamos a refactorizar esto para usar un patrón de inyección de dependencia.

interface IHorn { void Honk(); } class Horn : IHorn { public void Honk() { Console.WriteLine("beep!"); } } class Car { private IHorn horn; public Car(IHorn horn) { this.horn = horn; } public void HonkHorn() { this.horn.Honk(); } } class Program { static void Main() { var horn = new Horn(); var car = new Car(horn); car.HonkHorn(); } }

Hemos hecho dos cosas clave aquí. Primero, hemos introducido una interfaz que implementa nuestra clase Horn . Esto nos permite codificar la clase Car en la interfaz en lugar de la implementación particular. Ahora el código podría tomar cualquier cosa que implemente IHorn . En segundo lugar, hemos eliminado la instanciación de bocina de Car y la pasamos en su lugar. Esto resuelve los problemas anteriores y deja a la función principal de la aplicación administrar las instancias específicas y sus ciclos de vida.

Lo que esto significa es que podría introducir un nuevo tipo de cuerno para que el auto lo use sin tocar la clase Car :

class FrenchHorn : IHorn { public void Honk() { Console.WriteLine("le beep!"); } }

El principal podría simplemente inyectar una instancia de la clase FrenchHorn lugar. Esto también simplifica dramáticamente las pruebas. Podrías crear una clase MockHorn para inyectar en el constructor del Car para asegurarte de que estás probando solo la clase del Car de forma aislada.

El ejemplo anterior muestra la inyección de dependencia manual. Normalmente, DI se hace con un marco (por ejemplo, Unity o Ninject en el mundo C #). Estos marcos harán todo el cableado de la dependencia para usted al recorrer su gráfico de dependencia y crear instancias según sea necesario.

La forma estándar Node.js

Ahora veamos el mismo ejemplo en Node.js. Probablemente dividiremos nuestro código en 3 módulos:

// horn.js module.exports = { honk: function () { console.log("beep!"); } }; // car.js var horn = require("./horn"); module.exports = { honkHorn: function () { horn.honk(); } }; // index.js var car = require("./car"); car.honkHorn();

Debido a que JavaScript no está tipificado, no tenemos el mismo acoplamiento estrecho que teníamos antes. No hay necesidad de interfaces (ni existen) ya que el módulo de car simplemente intentará llamar al método de honk en cualquier cosa que el módulo de horn exporte.

Además, dado que los nodos require caché de todo, los módulos son esencialmente simples almacenados en un contenedor. Cualquier otro módulo que realice un require en el módulo de horn obtendrá exactamente la misma instancia. Esto hace que compartir objetos simples como conexiones de bases de datos sea muy fácil.

Ahora todavía existe la cuestión de que el módulo del car es responsable de buscar su propia horn dependencia. Si quería que el automóvil utilizara un módulo diferente para su bocina, tendría que cambiar la declaración de require en el módulo de car . Esto no es algo muy común de hacer, pero causa problemas con las pruebas.

La forma habitual en que las personas manejan el problema de prueba es con proxyquire . Debido a la naturaleza dinámica de JavaScript, proxyquire intercepta las llamadas para requerir y devuelve cualquier stubs / burla que proporcione en su lugar.

var proxyquire = require(''proxyquire''); var hornStub = { honk: function () { console.log("test beep!"); } }; var car = proxyquire(''./car'', { ''./horn'': hornStub }); // Now make test assertions on car...

Esto es más que suficiente para la mayoría de las aplicaciones. Si funciona para tu aplicación, entonces conéctate. Sin embargo, según mi experiencia, a medida que las aplicaciones crecen y se hacen más complejas, mantener un código como este se vuelve más difícil.

DI en JavaScript

Node.js es muy flexible. Si no está satisfecho con el método anterior, puede escribir sus módulos usando el patrón de inyección de dependencia. En este patrón, cada módulo exporta una función de fábrica (o un constructor de clase).

// horn.js module.exports = function () { return { honk: function () { console.log("beep!"); } }; }; // car.js module.exports = function (horn) { return { honkHorn: function () { horn.honk(); } }; }; // index.js var horn = require("./horn")(); var car = require("./car")(horn); car.honkHorn();

Esto es muy similar al método C # anteriormente en que el módulo index.js es responsable de los ciclos de vida y cableado de la instancia. Las pruebas unitarias son bastante simples, ya que puede pasar los simulacros / comprobantes a las funciones. Nuevamente, si esto es lo suficientemente bueno para su aplicación, vaya con eso.

Bolus DI Framework

A diferencia de C #, no existen marcos DI estándar establecidos para ayudar con su gestión de dependencia. Hay una cantidad de marcos en el registro de npm pero ninguno tiene una adopción generalizada. Muchas de estas opciones ya se han citado en las otras respuestas.

No estaba particularmente contento con ninguna de las opciones disponibles, así que escribí mi propio bolus llamado. Bolus está diseñado para trabajar con código escrito en el estilo DI anterior e intenta ser muy DRY y muy simple. Usando exactamente los mismos módulos car.js y horn.js anteriores, puede volver a escribir el módulo index.js con bolus como:

// index.js var Injector = require("bolus"); var injector = new Injector(); injector.registerPath("**/*.js"); var car = injector.resolve("car"); car.honkHorn();

La idea básica es que crees un inyector. Usted registra todos sus módulos en el inyector. Entonces simplemente resuelve lo que necesitas. Bolus recorrerá el gráfico de dependencia y creará e inyectará dependencias según sea necesario. No se ahorra mucho en un ejemplo de juguete como este, pero en grandes aplicaciones con complicados árboles de dependencia, los ahorros son enormes.

Bolus admite un montón de características ingeniosas como dependencias opcionales y pruebas globales, pero hay dos beneficios clave que he visto en relación con el enfoque estándar de Node.js. Primero, si tiene muchas aplicaciones similares, puede crear un módulo npm privado para su base que crea un inyector y registra objetos útiles en él. Luego, sus aplicaciones específicas pueden agregar, anular y resolver según sea necesario, al igual que funciona AngularJS''s inyector AngularJS''s . En segundo lugar, puede usar un bolo para administrar diversos contextos de dependencias. Por ejemplo, puede usar el middleware para crear un inyector hijo por solicitud, registrar la identificación del usuario, la identificación de la sesión, el registrador, etc. en el inyector junto con los módulos que dependen de ellos. Luego resuelva lo que necesita para atender las solicitudes. Esto le proporciona instancias de sus módulos por solicitud y evita tener que pasar el registrador, etc. junto con cada llamada a la función del módulo.


Siempre me gustó la simplicidad del concepto de IoC: "No tienes que saber nada sobre el medio ambiente, alguien te llamará cuando sea necesario"

Pero todas las implementaciones de IoC que vi hicieron exactamente lo contrario: desordenan el código con incluso más cosas que sin él. Entonces, creé mi propio IoC que funciona como me gustaría: permanece oculto e invisible el 90% del tiempo .

Se usa en el marco web de MonoJS http://monojs.org

Estoy hablando de cosas simples, como compartir un objeto de conexión de base de datos, hasta ahora, pero no he encontrado una solución que me satisfaga.

Se hace así: registrar el componente una vez en config.

app.register ''db'', -> require(''mongodb'').connect config.dbPath

Y usarlo en cualquier lugar

app.db.findSomething()

Puede ver el código de definición de componente completo (con DB Connection y otros componentes) aquí https://github.com/sinizinairina/mono/blob/master/mono.coffee

Este es el único lugar donde debe decirle a IoC qué hacer, luego todos esos componentes se crearán y cablearán automáticamente y ya no tendrá que ver el código específico de IoC en su aplicación.

El propio Io https://github.com/alexeypetrushin/miconjs


También he escrito un módulo para lograr esto, se llama rewire . Simplemente use npm install rewire y luego:

var rewire = require("rewire"), myModule = rewire("./path/to/myModule.js"); // exactly like require() // Your module will now export a special setter and getter for private variables. myModule.__set__("myPrivateVar", 123); myModule.__get__("myPrivateVar"); // = 123 // This allows you to mock almost everything within the module e.g. the fs-module. // Just pass the variable name as first parameter and your mock as second. myModule.__set__("fs", { readFile: function (path, encoding, cb) { cb(null, "Success!"); } }); myModule.readSomethingFromFileSystem(function (err, data) { console.log(data); // = Success! });

Me inspiré en la inyección de Nathan MacInnes, pero utilicé un enfoque diferente. No uso vm para evaluar el módulo de prueba, de hecho utilizo el propio requerimiento del nodo. De esta forma, su módulo se comporta exactamente igual que con require() (excepto sus modificaciones). También la depuración es totalmente compatible.


Yo investigué esto yo mismo. No me gusta introducir bibliotecas de magic care de utilities que proporcionan mecanismos para secuestrar las importaciones de mi módulo. En cambio, se me ocurrió una "guía de diseño" para que mi equipo establezca de forma más explícita qué dependencias se pueden burlar introduciendo una exportación de función de fábrica dentro de mis módulos.

Hago un uso extensivo de las características de ES6 para los parámetros y la desestructuración para evitar algunos estándares y proporcionar un mecanismo de anulación de dependencia con nombre.

Aquí hay un ejemplo:

import foo from ''./utils/foo''; import bob from ''./utils/bob''; // We export a factory which accepts our dependencies. export const factory = (dependencies = {}) => { const { // The ''bob'' dependency. We default to the standard ''bob'' imp if not provided. $bob = bob, // Instead of exposing the whole ''foo'' api, we only provide a mechanism // with which to override the specific part of foo we care about. $doSomething = foo.doSomething // defaults to standard imp if none provided. } = dependencies; return function bar() { return $bob($doSomething()); } } // The default implementation, which would end up using default deps. export default factory();

Y aquí hay un ejemplo de su uso

import { factory } from ''./bar''; const underTest = factory({ $bob: () => ''BOB!'' }); // only override bob! const result = underTest();

Disculpe la sintaxis de ES6 para quienes no estén familiarizados con ella.


require es la forma de gestionar dependencias en Node.js y seguramente es intuitiva y efectiva, pero también tiene sus limitaciones.

Mi consejo es echar un vistazo a algunos de los contenedores de Dependency Injection disponibles hoy para que Node.js tenga una idea sobre cuáles son sus ventajas y desventajas. Algunos de ellos son:

Sólo para nombrar unos pocos.

Ahora la verdadera pregunta es, ¿qué se puede lograr con un contenedor DI Node.js, comparado con un simple require ?

Pros:

  • mejor capacidad de prueba: los módulos aceptan sus dependencias como entrada
  • Inversión del control: decide cómo conectar tus módulos sin tocar el código principal de tu aplicación.
  • un algoritmo personalizable para resolver módulos: las dependencias tienen identificadores "virtuales", por lo general no están vinculados a una ruta en el sistema de archivos.
  • Mejor extensibilidad: habilitada por IoC e identificadores "virtuales".
  • Otras cosas de lujo posibles:
    • Inicialización Async
    • Gestión del ciclo de vida del módulo
    • Extensibilidad del contenedor DI en sí
    • Puede implementar fácilmente abstracciones de mayor nivel (por ejemplo, AOP)

Contras:

  • Diferente de la "experiencia" de Node.js: no usar require definitivamente sentirse como si se estuviera desviando de la forma de pensar del Nodo.
  • La relación entre una dependencia y su implementación no siempre es explícita. Una dependencia puede resolverse en tiempo de ejecución e influenciada por diversos parámetros. El código se vuelve más difícil de entender y depurar
  • Tiempo de inicio más lento
  • Madurez (por el momento): ninguna de las soluciones actuales es realmente popular en este momento, por lo que no hay tantos tutoriales, ni ecosistemas, ni pruebas de batalla.
  • Algunos contenedores DI no funcionarán bien con paquetes de módulos como Browserify y Webpack.

Como con cualquier cosa relacionada con el desarrollo de software, elegir entre DI o require depende de sus requisitos, la complejidad de su sistema y su estilo de programación.


En resumen, no necesita un contenedor de inyección de dependencia o localizador de servicios como lo haría en C # / Java. Como Node.js, aprovecha el module pattern del module pattern , no es necesario realizar la inyección del constructor o de la propiedad. Aunque todavía puedes.

Lo mejor de JS es que puedes modificar casi cualquier cosa para lograr lo que quieres. Esto es útil cuando se trata de pruebas.

He aquí mi muy mal ejemplo artificial.

MyClass.js :

var fs = require(''fs''); MyClass.prototype.errorFileExists = function(dir) { var dirsOrFiles = fs.readdirSync(dir); for (var d in dirsOrFiles) { if (d === ''error.txt'') return true; } return false; };

MyClass.test.js :

describe(''MyClass'', function(){ it(''should return an error if error.txt is found in the directory'', function(done){ var mc = new MyClass(); assert(mc.errorFileExists(''/tmp/mydir'')); //true }); });

Observe cómo MyClass depende del módulo fs ? Como se mencionó en @ShatyemShekhar, de hecho se puede hacer la inyección de constructores o propiedades como en otros idiomas. Pero no es necesario en Javascript.

En este caso, puedes hacer dos cosas.

Puede fs.readdirSync método fs.readdirSync o puede devolver un módulo completamente diferente cuando llame a require .

Método 1:

var oldmethod = fs.readdirSync; fs.readdirSync = function(dir) { return [''somefile.txt'', ''error.txt'', ''anotherfile.txt'']; }; *** PERFORM TEST *** *** RESTORE METHOD AFTER TEST **** fs.readddirSync = oldmethod;

Método 2:

var oldrequire = require require = function(module) { if (module === ''fs'') { return { readdirSync: function(dir) { return [''somefile.txt'', ''error.txt'', ''anotherfile.txt'']; }; }; } else return oldrequire(module); }

La clave es aprovechar el poder de Node.js y Javascript. Tenga en cuenta que soy un tipo de CoffeeScript, por lo que mi sintaxis JS puede ser incorrecta en alguna parte. Además, no estoy diciendo que esta sea la mejor manera, pero es una forma. Los gurús de Javascript podrían interactuar con otras soluciones.

Actualizar:

Esto debería abordar su pregunta específica con respecto a las conexiones de bases de datos. Crearía un módulo separado para que encapsule la lógica de conexión de su base de datos. Algo como esto:

MyDbConnection.js : (asegúrese de elegir un nombre mejor)

var db = require(''whichever_db_vendor_i_use''); module.exports.fetchConnection() = function() { //logic to test connection //do I want to connection pool? //do I need only one connection throughout the lifecyle of my application? return db.createConnection(port, host, databasename); //<--- values typically from a config file }

Entonces, cualquier módulo que necesite una conexión de base de datos simplemente incluirá su módulo MyDbConnection .

SuperCoolWebApp.js :

var dbCon = require(''./lib/mydbconnection''); //wherever the file is stored //now do something with the connection var connection = dbCon.fetchConnection(); //mydbconnection.js is responsible for pooling, reusing, whatever your app use case is //come TEST time of SuperCoolWebApp, you can set the require or return whatever you want, or, like I said, use an actual connection to a TEST database.

No sigas este ejemplo al pie de la letra. Es un mal ejemplo al tratar de comunicar que aproveche el patrón del module para administrar sus dependencias. Espero que esto ayude un poco más.


I discovered this question while answering to an issue on my own DI module asking why one would ever need a DI system for NodeJS programming.

The answer was clearly tending to the ones given in this thread: it depends. There are trade-offs for both approaches and reading this question''s answers give a good shape of them.

So, the real answer to this question, should be that in some situations, you would use a DI system, in others not.

That said, what you want as a developer is to not repeat yourself and reuse your services across your various applications.

This means that we should write services that are ready to be used in DI system but not tied to DI libraries. To me, it means that we should write services like this:

module.exports = initDBService; // Tells any DI lib what it expects to find in it context object // The $inject prop is the de facto standard for DI imo initDBService.$inject = [''ENV'']; // Note the context object, imo, a DI tool should bring // services in a single context object function initDBService({ ENV }) { /// actual service code }

That way your service works not matter if you use it with or without a DI tool.


I have developed a library that handles the dependency injection with a simple way, that decreases the boilerplate code. Each module is defined by a unique name and a controller function. The parameters of the controller reflects the module''s dependencies.

Read more on KlarkJS

Brief example:

KlarkModule(module, ''myModuleName1'', function($nodeModule1, myModuleName2) { return { log: function() { console.log(''Hello from module myModuleName1'') } }; });

  • myModuleName1 is the name of the module.
  • $nodeModule1 is an external library from node_module . The name resolves to node-module1 . The prefix $ indicates that it is an external module.
  • myModuleName2 is the name of an internal module.
  • The return value of the controller is used from the other internal modules, when they define the parameter myModuleName1 .

I think other posts have done a great job in the argument for using DI. For me the reasons are

  1. Inject dependencies without knowing their paths. This means that if you change a module location on disk or swap it with another, you don''t need to touch every file that depends on it.

  2. It makes it a lot easier to mock dependencies for testing without the pain of overriding the global require function in a way that works without problems.

  3. It helps you organize and reason about you application as loosely coupled modules.

But I had a really hard time finding a DI framework that my team and I can easily adopt. So I recently built a framework called deppie based on these features

  • Minimal API that can be learned in a few minutes
  • No extra code/config/annotations required
  • One to one direct mapping to require modules
  • Can be adopted partially to work with existing code

I worked with .Net, PHP and Java for long time so I wanted to have a convenient Dependency Injection in NodeJS too. People said the built-in DI in NodeJS is enough as we can get it with Module. But it didn''t satisfy me well. I wanted to keep a Module no more than a Class. Additionally, I wanted the DI to have a full support for Module life cycle management (singleton module, transient module etc.) but with Node module, I had to write manual code very often. Lastly, I wanted to make Unit Test easier. That''s why I created a Dependency Injection for myself.

If you are looking for a DI, give it a try. It can be found here: https://github.com/robo-creative/nodejs-robo-container . It''s fully documented. It also addresses some common problems with DI and how to solve them in OOP way. Espero eso ayude.


It should be flexible and simple like this:

var MyClass1 = function () {} var MyClass2 = function (myService1) { // myService1.should.be.instanceof(MyClass1); } container.register(''myService1'', MyClass1); container.register(''myService2'', MyClass2, [''myService1'']);

I have written article about Dependency Injection in node.js.

I hope it can help you with this.


Node.js requires DI as much as any other platform. If you are building something big, DI will make it easier to mock the dependencies of your code and test your code thoroughly.

Your database layer modules for example, shouldn''t just get required at your business code modules because, when unit testing these business code modules, the daos will load and connect to the database.

One solution would be to pass the dependencies as module parameters:

module.exports = function (dep1, dep2) { // private methods return { // public methods test: function(){...} } }

This way dependencies can be mocked easily and naturally and you can stay focused on testing your code, without using any tricky 3rd party library.

There are other solutions out there (broadway, architect etc) which can help you with this. although they may do more than what you want or use more clutter.