Как предоставить зависимости, такие как db, logger и т. Д., Базовой библиотеке?

#javascript #node.js #dependency-injection #dependency-management

#javascript #node.js #внедрение зависимостей #управление зависимостями

Вопрос:

Настройка

Я создаю базовую библиотеку для распределенного приложения. Вот структура:

 core_project/
    lib/
        index.js
        module1.js
        module2.js
        ...
    package.json
  

Многие другие части моего приложения будут использовать эту библиотеку следующим образом:

 consumer_project/
    node_modules/
        core_project/
            ...
    app.js
    package.json
  

Проблема

Я хочу, чтобы некоторые общие зависимости, такие как обработчик DB, предоставлялись потребительским приложением. После инициализации я хочу, чтобы все мои основные модули приложения могли использовать эти зависимости.

Попытка решения

Я попытался создать функцию инициализации модуля в каждом модуле основного приложения: core_project/lib/module1.js

 var cfg = {db: null};

module.exports = {
    // ...
    'initModule': function (db) {
        cfg.db = db;
    }
}
  

И это мой индексный файл основного модуля:
core_project/lib/index.js

 var modules = {
    'module1': require('./module1'),
    'module1': require('./module2'),
    // ...
};

function create(db) {
    var app = {};
    init(app, modules, db);
    return app;
}

function init(app, mods, db) {
    var m;
    for (m in mods) {
        if (mods.hasOwnProperty(m)) {
            if (mods[m].hasOwnProperty('initModule')) {
                mods[m].initModule(db);
            }

            app[m] = mods[m];
        }
    }
}

module.exports = create;
  

Теперь мое потребительское приложение может передавать зависимости следующим образом:
consumer_project/app.js

 var core = require('core_project');
var db = // initialize db

var app = core(db);

// Start using
app.module1.run();
  

Проблемы с попыткой решения

  1. Я должен добавлять cfg = {db: null} и экспортировать initModule функцию в каждый модуль, для которого требуются зависимости.
  2. Я должен прикрепить каждый модуль к основному объекту приложения в core_project/lib/index.js

Вопрос

Есть ли лучший способ предоставить потребительские зависимости, такие как db, logger, для базовой библиотеки и всех ее модулей?

Комментарии:

1. если вы не хотите / have_чтобы изобрести собственное решение, проверьте component framework github.com/component/component или новая модульная система ES6, некоторые преимущества, упомянутые в addyosmani.com/writing-modular-js

Ответ №1:

Передача зависимостей в качестве аргументов (т. Е. Внедрение зависимостей) является вполне допустимым способом достижения этой цели, хотя вы можете упростить инициализацию с помощью замыкания:

core_project/lib/module1.js:

 module.exports = function(db) {
  return function() {
    // closure scoped with dependencies
    // can use db object
  };
}
  

Тогда ваша функция инициализации создаст закрытие:

 app[m] = mods[m](db);
  

Передача dep, подобная этой, Обычно желательна для клиентов базы данных, поэтому одно и то же соединение используется во всех ваших модулях, однако другие типы dep, такие как регистраторы, могут быть лучше импортировать с использованием стандартного require() метода модульной системы, например require('winston')

Комментарии:

1. Это то, что я в итоге использовал. Что касается регистраторов, я бы определенно использовал require (‘winston’), Но я бы хотел настроить регистратор (файлы / сокеты для использования) на клиенте и передать настроенный регистратор в качестве dep в ядро.