Friday, April 24, 2015

Modular MVC using LoopBack/Express

Express is pretty simple to use, and simplicity comes at a price. For me, that price is organization. All the views are in one big folder, as are public assets. I prefer a modular organization, and reading this post (https://strongloop.com/strongblog/bypassing-express-view-rendering-for-speed-and-modularity/) pointed out that the key is that the rendering engine breaks modularity.

So I created a top level folder named application, and moved the views out of the server folder, and static content out of clent:

project
| -- application                modules
|     | -- index.coffee  module bootstrap
|     | -- modules.json  module config
|     + -- user          
|           | -- client/public
|           | -- server/boot
|           | -- server/views
|     + -- game          
|           | -- client/public
|           | -- server/boot
|           | -- server/views
| -- client                     not used
| -- common/modules   unchanged
| -- server                     removed views
| -- .bowerrc                   the usual
| -- .gitignore                 ditto

In the main server/server.coffee, after the standard boot:

boot app, __dirname
...
modules = require('../application')
modules app

This runs application/index.coffee, which boots each module, based on the config:
./modules.json:

{
  "user": true,
  "game": true
}

./index.coffee:
fs = require('fs')
path = require('path')
loopback = require("loopback")

module.exports = (app) ->

  for name, enabled of require('./modules.json')

    # -- Boot the module scripts  --
    if enabled
      do (name) ->  # closure on name value
        mod = {}    # and for communication within module

        for filename in fs.readdirSync(path.join(__dirname, name, 'server/boot'))
          if path.extname(filename) in ['.coffee','.js']
            boot = require(path.join(__dirname, name, 'server/boot', filename))
            boot(app, mod)

    # -- Mount static files --
    app.use loopback.static(path.join(__dirname, name, 'client/public'))


All of the content is created from each applications server/view and client/public folders.
Each application has it's own server/boot folder, where I put controllers and rendering engine.
And if I do it right, I can drop my used module into another project and be good to go.

An extra benefit - my user module uses jade templating, while my game module is using liquid templating. Why would you want more than 1 templating engine? Well, I'm lazy. My user module is essentially the loopback-example-passport github repo that I'm tweaking a bit. All of their views use jade. But, I prefer using liquid for my own development.

The full project (wip) is over here - https://github.com/darkoverlordofdata/games. 

No comments:

Post a Comment