meanjs-core

MEAN.JS - Core services for the MEAN.JS boilerplate. Full-Stack JavaScript Using MongoDB, Express, AngularJS, and Node.js From Creators of MEAN.IO - http://meanjs.org

mean-core

MEAN.JS - Core services for the MEAN.JS boilerplate. Full-Stack JavaScript Using MongoDB, Express, AngularJS, and Node.js From Creators of MEAN.IO - http://meanjs.org

This is a proposal to:

  • Separate boilerplate example code from core functionality
  • Standardize a way for contributed modules.
  • Use npm package manager to update core code w/o requiring a git merge

Code

Status: psuedocode

To play with this code:

  1. fork boilerplate: git@github.com:MichaelJCole/mean.git
  2. checkout meanjs-core branch
  3. npm install && grunt build
  4. grunt

It's stored in 3 repos.

  • boilerplate: meanjs-core branch, forked repo: git@github.com:MichaelJCole/mean.git
  • mean-core: master branch, this repo you're reading: git@github.com:MichaelJCole/mean-core.git
  • mean-module: master branch, this repo: git@github.com:MichaelJCole/mean-module.git

This will download and install mean-core and mean-module from github.

How to use mean-core:

mean-core functionality is in a separate npm package from the Yoeman boilerplate.

The boilerplate includes mean-core:

"dependencies": {
  // ...
  "mean-core": "git://github.com/MichaelJCole/mean-core",
  // ...
}

mean-core's functionality is exposed in several places:

app.config
app.core.[module].[export]
req.config
req.core.[module].[export]

The boilerplate uses these core functions, allowing the end developer to add, delete, re-mix, and mash them up as needed:

// Core and Module functions are exposed on app.core and req.core objects.
 
// e.g. In users.server.controllers.js, use req.core.[modulename].[export]
exports.signup = function(req, res) {
  // ...
  // 
  // Then save the user 
  user.save(function(err) {
    if (err) {
      // ...
    } else {
      // ...
      // Send confirmation email
      req.core.users.sendConfirmEmail(user, req.config);
    }
  });
 
// e.g. In users.server.routes.js, use app.core.[modulename].[export]
module.exports = function(app) {
  // User Routes
  // ...
  app.route('/auth/confirm/:confirmationCode').get(app.core.users.confirmEmailLink);
  // ...
}

An open question is how to organize the module exports. I'm aware of three modules: users, core, and articles.

Using a contributed MEAN.JS module 'myModule'

"dependencies": {
  // ...
  "mean-core": "git://github.com/MichaelJCole/mean-core",
  "mean-module": "git://github.com/MichaelJCole/mean-module"
  // ...
}

In the boilerplate server.js:

// Note: developers add modules here:
var meanModules = [
  require('mean-module')(db, config) // pass db and config if needed.
];
 
// ...
 
// Init the express application
var app = require('./config/express')(db, config, meanModules);

server.js is intended for the end developer to customize.

config/express.js wires these modules into:

app.mean.[module].[export]
req.mean.[module].[export]

Creating your own MEAN.JS module

To extend mean-core with a module of your own:

  1. create a github repo for your myModule.
  2. expose your functionality via exports.
exports.name = 'moduleName';
 
exports.myModule.controller.myFunc(req, res, next) {
  console.log("hello world");
  next();
}

To use:

// e.g. In users.server.routes.js, use app.core.[modulename].[export]
module.exports = function(app) {
  // User Routes
  // ...
  app.route('/auth/confirm/:confirmationCode').get(app.mean.betterUsers.betterConfirmLink);
  // ...
}

Summary:

This allows for:

  • package.json and server.js are files for dev to add contributed modules.
  • config/express.js is still boilerplate, but most likely won't be customized (easier updates)
  • namespaces aren't poluted:
// Config
app.config
req.config
// Core functionality
app.core.[module].[export]
req.core.[module].[export]
// Contributed modules
app.mean.[module].[export]
req.mean.[module].[export]

Note: it may be worth separating config for core and contributed, but that's another topic.

How's it work:

  1. Add dependencies to package.json
  2. Changes to server.js:
var meanModules = [
  require('mean-module')(config) // edit config files if needed.
];
// ...
var app = require('./config/express')(db, config, meanModules);
 

The file config/express.js :

  // ...
 
  // Get core exports
  var core = require('mean-core')(db, config)
 
  // Apply exports to app
  app.set('config', config);
  app.set('core', core);
  app.set('mean', meanModules);
 
  // Middleware to adjust req
  app.use(function(req, res, next) {
    res.locals.url = req.protocol + ':// ' + req.headers.host + req.url;
    // Add application config to all incoming requests
    req.config = config;
    req.core = coreExports;
    req.mean = meanExports;
    next();
  });
 
  // ...

How to develop in mean-core:

  1. Clone your own repo
  2. Use npm-link to link to your local mean-core https://www.npmjs.org/doc/cli/npm-link.html http://justjs.com/posts/npm-link-developing-your-own-npm-modules-without-tears
cd mean-core
sudo npm link
cd ../mean-module
sudo npm link
cd ../project
npm link meanjs-core
npm link meanjs-module

Now, when you require('mean-core'), Node.js will find a symlink to your local copies.

Core versioning and compatibility promises:

TBD.

Etc.

Express modules like mean-seo could also be added in express.js, if they were defined like this:

exports.middleware = function()

Module names should not collide, unless the modules are drop-in replacements for one another.

Data models should be strictly boilerplate. This prevents the need for inheritance, sub-classing, or baloney like that.

Core and Contrib modules can store/read data in the model.decor attribute(?) as a sub-document.

core.[moduleName].property
mean.[moduleName].property

More complex data requirements will require customizing the models by hand.

Angular modules. Haven't figured this out yet. Ideas? PHP's Symfony project handled client modules via symlinks.