In an attempt to modularize a large existing Node+Express+Mongoose application into multiple mountable apps, each developed as a separate NPM package, we're wondering whether sharing a single Mongoose instance between them is a good idea?
Let's say we have a suite of NPM packages each containing client-side assets, Mongoose models, and a REST-API implemented with Express. They do share a few common traits but are essentially to be considered separate reusable artefacts. A host application, also Express-based, mounts these under various root URIs:
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));
Now, since the events
, tickets
and discussions
apps (separate NPM packages
pulled in via the host package.json
) use Mongoose, as do the
host application itself, we figured we would pass in the host Mongoose instance
through some kind of environment
object that also include other
stuff that the host wants to share with the mounted apps.
Do you see any obvious flaws with this approach? The mounted apps
in this case would not specify Mongoose as a dependency in their
respective package.json
, and they would not require('mongoose')
as normally done but instead get the Mongoose instance from the host
which is responsible for connecting it to MongoDB.
If this is a bad idea and you suggest each sub-app declare a dependency towards Mongoose on their own, each NPM package would get their own copy of Mongoose and would each have to connect to MongoDB, right?
Some background info:
- We really do want to include the apps in a host application, running in a single process, rather that having multiple Node instances. The host contains middleware for authentication and other things.
- We do want to have the apps as separately developed NPM packages included as versioned dependencies of the various host applications that we build, rather than just copying their source to a host application.
- We realize that reusing the same Mongoose instance between multiple mounted apps will have them share the same model namespace.
Edit: To clarify the package structure after all has been npm install
ed:
host/
assets/
models/
routes/
node_modules/
express/ ...
mongoose/ ...
events/
assets/ ...
models/ ...
routes/ ...
tickets/
assets/ ...
models/ ...
routes/ ...
discussions/
assets/ ...
models/ ...
routes/ ...
That is, the events
, tickets
, and discussions
apps do not include
Mongoose (or Express) of their own but are designed to rely on an always-present
host application that suppliesd those dependencies.
We're assuming here that an NPM package like tickets
cannot simply
require
stuff from the parent, right?
I suggest you have a look at https://github.com/jaredhanson/node-parent-require, a recently published package which solved this issue for me.
The node-parent-require Readme file on the Github project page provides a detailed walkthrough using mongoose.
Basically, you need to dig in your submodule and replace this:
... with this:
Don't forget to add mongoose as a peerDependency in your submodule's package.json. For example:
You may also want to read http://blog.nodejs.org/2013/02/07/peer-dependencies/ first.
You can just require one global mongoose instance and use it anywhere.
https://www.npmjs.com/package/mongoose-global
If you want to reuse your Mongoose package between other NPM packages, the best way to do it is to install the shared package at the top level app and then use it to initialize the other NPM packages.
In the top level:
Then your events package just needs to export a function that takes the db as a parameter.