Совместное использование экземпляра 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 и использовать его где угодно.