Совместное использование экземпляра Mongoose между несколькими пакетами NPM

В попытке модульно объединить большое существующее приложение Node+Express+Mongoose в несколько монтируемых приложений, каждое из которых разработано как отдельный пакет NPM, мы задаемся вопросом, является ли хорошей идеей совместное использование одного экземпляра Mongoose между ними?

Допустим, у нас есть набор пакетов NPM, каждый из которых содержит клиентские ресурсы, модели Mongoose и REST-API, реализованный с помощью Express. Они действительно имеют несколько общих черт, но по сути должны рассматриваться как отдельные артефакты многократного использования. Хост-приложение, также основанное на Express, монтирует их под различными корневыми URI:

var discussions = require('discussions'),
    tickets     = require('tickets'),
    events      = require('events'),
    express     = require('express'),
    app         = express();

var environment = { ...see below... };

...

app.use('/events-api', events(environment));
app.use('/tickets-api', tickets(environment));
app.use('/discussions-api', discussions(environment));

Теперь, так как events, tickets а также discussions приложения (отдельные пакеты NPM загружаются через хост package.json) использовать Mongoose, так же как и само приложение хоста, мы решили, что будем передавать в экземпляр Mongoose хоста через какую-то environment объект, который также включает в себя другие вещи, которые хост хочет поделиться с подключенными приложениями.

Видите ли вы какие-либо очевидные недостатки этого подхода? Монтируемые приложения в этом случае не будут указывать Mongoose как зависимость в соответствующих package.jsonи они не будутrequire('mongoose')как обычно, но вместо этого получите экземпляр Mongoose от хоста, который отвечает за его подключение к MongoDB.

Если это плохая идея, и вы предлагаете, чтобы каждое подпрограмма объявляла зависимость от Mongoose самостоятельно, каждый пакет NPM получал бы свою собственную копию Mongoose и каждый должен был бы подключаться к MongoDB, верно?

Некоторая справочная информация:

  • Мы действительно хотим включить приложения в хост-приложение, работающее в одном процессе, а не с несколькими экземплярами Node. Хост содержит промежуточное ПО для аутентификации и прочего.
  • Мы хотим, чтобы приложения как отдельно разработанные пакеты NPM включались в качестве версионных зависимостей различных хост-приложений, которые мы создаем, а не просто копировали их источник в хост-приложение.
  • Мы понимаем, что повторное использование одного и того же экземпляра Mongoose между несколькими подключенными приложениями приведет к тому, что они будут использовать одно и то же пространство имен модели.

Изменить: чтобы уточнить структуру пакета после того, как все было npm installизд:

host/
  assets/
  models/
  routes/
  node_modules/
    express/ ...
    mongoose/ ...
    events/
      assets/ ...
      models/ ...
      routes/ ...
    tickets/
      assets/ ...
      models/ ...
      routes/ ...
    discussions/
      assets/ ...
      models/ ...
      routes/ ...

Это events, tickets, а также discussions Приложения не включают в себя Mongoose (или Express), но разработаны так, чтобы полагаться на всегда присутствующее хост-приложение, которое предоставляет эти зависимости.

Здесь мы предполагаем, что пакет NPM, такой как tickets не может простоrequire материал от родителей, верно?

3 ответа

Решение

Если вы хотите повторно использовать ваш пакет Mongoose между другими пакетами NPM, лучший способ сделать это - установить общий пакет в приложение верхнего уровня, а затем использовать его для инициализации других пакетов NPM.

На верхнем уровне:

var db = require('myMongooseDb'),
    events = require('events')(db),
    ...

Тогда вашему пакету событий просто нужно экспортировать функцию, которая принимает БД в качестве параметра.

Я предлагаю вам взглянуть на https://github.com/jaredhanson/node-parent-require, недавно опубликованный пакет, который решил эту проблему для меня.

Файл Readme для node-parent-require на странице проекта Github предоставляет подробное пошаговое руководство с использованием mongoose.

По сути, вам нужно покопаться в вашем подмодуле и заменить это:

mongoose = require("mongoose");

... с этим:

try {
  var mongoose = require('mongoose');
} catch (_) {
  // workaround when `npm link`'ed for development
  var prequire = require('parent-require')
    , mongoose = prequire('mongoose');
}

Не забудьте добавить mongoose в качестве peerDependency в package.json вашего подмодуля. Например:

"peerDependencies": {
  "mongoose": "3.x"
}

Вы также можете сначала прочитать http://blog.nodejs.org/2013/02/07/peer-dependencies/.

const mongoose = require('mongoose-global')();

Вы можете просто потребовать один глобальный экземпляр Mongoose и использовать его где угодно.

https://www.npmjs.com/package/mongoose-global

Другие вопросы по тегам