Skip to content

Instantly share code, notes, and snippets.

@doublemarked
Last active May 2, 2016 00:40
Show Gist options
  • Save doublemarked/7658a16d0f8f6420df8e to your computer and use it in GitHub Desktop.
Save doublemarked/7658a16d0f8f6420df8e to your computer and use it in GitHub Desktop.
Boot script for fragmented loading of Loopback models

Fragmenting Loopback Models

Hey! I've bundled this approach into a component: https://github.com/doublemarked/loopback-component-model-fragments

This boot script will load module components on app initialization. Stick this file in server/boot. Components are looked for in the directory common/models/model-name. The script will load recursively any script from that directory, passing it the Model handle as a parameter (just like model.js loads). Conveniently, since this is occuring during the boot phase, those model scripts will execute at a later phase than model.js, meaning PersistedModel is already initialized and all peer model handles are already usable. Note - it's necessary for you to still maintain a model.js file for Loopback to load the model at all.

AUTHOR: Heath Morrison | @govright.org | http://github.com/doublemarked

QUESTIONS? Write me or join us on Gitter: https://gitter.im/strongloop/loopback

// AUTHOR: Heath Morrison | <firstname>@govright.org | http://github.com/doublemarked
// QUESTIONS? Write me or join us on Gitter: https://gitter.im/strongloop/loopback
//
// This boot script will load module components on app initialization. Stick this file in server/boot.
// Components are looked for in the directory common/models/model-name. The script will load recursively any
// script from that directory, passing it the Model handle as a parameter (just like model.js loads).
// Conveniently, since this is occuring during the boot phase, those model scripts will execute at a later
// phase than model.js, meaning PersistedModel is already initialized and all peer model handles are already usable.
// Note - it's necessary for you to still maintain a model.js file for Loopback to load the model at all.
module.exports = function(app) {
Object.keys(app.models).forEach(function (key) {
loadComponents(app.models[key]);
});
};
function loadComponents(Model, options) {
options = options || {};
var componentsPath = options.path || Model.settings.components || 'common/models/' + slugify(Model.modelName);
try {
recursiveRequire(appRoot + '/' + componentsPath);
} catch (e) {
// anything other than 'file not found' should be a hard fail
if (e.code !== 'ENOENT') {
console.error('Failure loading component path:', appRoot + '/' + componentsPath);
process.exit(1);
}
}
function recursiveRequire(sourcePath) {
fs.readdirSync(sourcePath).forEach(function (f) {
var filePath = sourcePath + '/' + f;
if (fs.lstatSync(filePath).isDirectory()) {
recursiveRequire(filePath);
} else if (path.extname(f) === '.js') {
require(filePath)(Model);
}
});
}
}
// Works for 99% of cases. For others, set explicit path via options/config.
function slugify(name) {
name = name.replace(/^[A-Z]+/, function (s) { return s.toLowerCase(); });
return name.replace(/[A-Z]/g, function (s) { return '-' + s.toLowerCase(); });
}

Here's an example of how one of our models (Scope) has been broken into components:

common/models/scope
common/models/scope/hooks.js
common/models/scope/linker.js
common/models/scope/methods.js
common/models/scope/overrides.js
common/models/scope/remotes
common/models/scope/remotes/find-linked.js
common/models/scope/remotes/find-one-linked.js
common/models/scope/remotes/find-parent.js
common/models/scope/validations.js
common/models/scope.js
common/models/scope.json

@ZepAviator
Copy link

So, within the loadComponents function I just added the vars

var path = require('path');
var fs = require('fs');
var appRoot = path.resolve(__dirname, '..', '..' );

I'm not sure if this is the most efficient way in loopback or if I should set this stuff up more in a global space, but that seemed to be the trick.

@ZepAviator
Copy link

The sub directory models, if you call Model.remoteMethod() in them, it doesn't work. Only in the root model.js. But you can reference functions defined in the sub directories.

@drmikecrowe
Copy link

If desired, you can also split up your static methods into a

    methods/

directory as well

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment