Pass `app` to fn exported by auto-required script
When a script in `models/` or `boot/` exports a function which is not a loopback.Model constructor, the bootstrapper immediatelly calls this exported function wit the current `app` object. This is providing a dependency injection mechanism for boot scripts, so that they no longer need to know where to find the `app` object. Note: the dependency injection is optional. Existing code getting `app` reference via `require('../app')` will continue to work.
This commit is contained in:
parent
9930934686
commit
3ba43e1197
21
index.js
21
index.js
|
@ -2,6 +2,7 @@ var assert = require('assert');
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var _ = require('underscore');
|
var _ = require('underscore');
|
||||||
|
var loopback = require('loopback');
|
||||||
var ConfigLoader = require('./lib/config-loader');
|
var ConfigLoader = require('./lib/config-loader');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -195,7 +196,7 @@ exports = module.exports = function bootLoopBackApp(app, options) {
|
||||||
|
|
||||||
// try to attach models to dataSources by type
|
// try to attach models to dataSources by type
|
||||||
try {
|
try {
|
||||||
require('loopback').autoAttach();
|
loopback.autoAttach();
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
if(e.name === 'AssertionError') {
|
if(e.name === 'AssertionError') {
|
||||||
console.warn(e);
|
console.warn(e);
|
||||||
|
@ -213,8 +214,8 @@ exports = module.exports = function bootLoopBackApp(app, options) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// require directories
|
// require directories
|
||||||
requireDir(path.join(modelsRootDir, 'models'));
|
requireDir(path.join(modelsRootDir, 'models'), app);
|
||||||
requireDir(path.join(appRootDir, 'boot'));
|
requireDir(path.join(appRootDir, 'boot'), app);
|
||||||
};
|
};
|
||||||
|
|
||||||
function assertIsValidConfig(name, config) {
|
function assertIsValidConfig(name, config) {
|
||||||
|
@ -232,7 +233,7 @@ function forEachKeyedObject(obj, fn) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function requireDir(dir) {
|
function requireDir(dir, app) {
|
||||||
assert(dir, 'cannot require directory contents without directory name');
|
assert(dir, 'cannot require directory contents without directory name');
|
||||||
|
|
||||||
var requires = {};
|
var requires = {};
|
||||||
|
@ -271,9 +272,12 @@ function requireDir(dir) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var basename = path.basename(filename, ext);
|
var exports = tryRequire(filepath);
|
||||||
|
if (isFunctionNotModelCtor(exports))
|
||||||
|
exports(app);
|
||||||
|
|
||||||
requires[basename] = tryRequire(filepath);
|
var basename = path.basename(filename, ext);
|
||||||
|
requires[basename] = exports;
|
||||||
});
|
});
|
||||||
|
|
||||||
return requires;
|
return requires;
|
||||||
|
@ -296,4 +300,9 @@ function tryReadDir() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isFunctionNotModelCtor(fn) {
|
||||||
|
return typeof fn === 'function' &&
|
||||||
|
!(fn.prototype instanceof loopback.Model);
|
||||||
|
}
|
||||||
|
|
||||||
exports.ConfigLoader = ConfigLoader;
|
exports.ConfigLoader = ConfigLoader;
|
||||||
|
|
|
@ -342,6 +342,43 @@ describe('bootLoopBackApp', function() {
|
||||||
expect(app.models).to.have.property('foo');
|
expect(app.models).to.have.property('foo');
|
||||||
expect(global.testData).to.have.property('foo', 'loaded');
|
expect(global.testData).to.have.property('foo', 'loaded');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('calls function exported by models/model.js', function() {
|
||||||
|
givenAppInSandbox();
|
||||||
|
writeAppFile('models/model.js',
|
||||||
|
'module.exports = function(app) { app.fnCalled = true; };');
|
||||||
|
|
||||||
|
var app = loopback();
|
||||||
|
delete app.fnCalled;
|
||||||
|
boot(app, appDir);
|
||||||
|
expect(app.fnCalled, 'exported fn was called').to.be.true();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('calls function exported by boot/init.js', function() {
|
||||||
|
givenAppInSandbox();
|
||||||
|
writeAppFile('boot/init.js',
|
||||||
|
'module.exports = function(app) { app.fnCalled = true; };');
|
||||||
|
|
||||||
|
var app = loopback();
|
||||||
|
delete app.fnCalled;
|
||||||
|
boot(app, appDir);
|
||||||
|
expect(app.fnCalled, 'exported fn was called').to.be.true();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not call Model ctor exported by models/model.json', function() {
|
||||||
|
givenAppInSandbox();
|
||||||
|
writeAppFile('models/model.js',
|
||||||
|
'var loopback = require("loopback");\n' +
|
||||||
|
'module.exports = loopback.Model.extend("foo");\n' +
|
||||||
|
'module.exports.prototype._initProperties = function() {\n' +
|
||||||
|
' global.fnCalled = true;\n' +
|
||||||
|
'};');
|
||||||
|
|
||||||
|
var app = loopback();
|
||||||
|
delete global.fnCalled;
|
||||||
|
boot(app, appDir);
|
||||||
|
expect(global.fnCalled, 'exported fn was called').to.be.undefined();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue