Add support for async boot scripts
This commit is contained in:
parent
e974033395
commit
94cb4d6342
|
@ -12,6 +12,7 @@
|
|||
"newcap": true,
|
||||
"nonew": true,
|
||||
"sub": true,
|
||||
"unused": "vars",
|
||||
"globals": {
|
||||
"describe": true,
|
||||
"it": true,
|
||||
|
|
4
index.js
4
index.js
|
@ -75,12 +75,12 @@ var addInstructionsToBrowserify = require('./lib/bundler');
|
|||
* @header boot(app, [options])
|
||||
*/
|
||||
|
||||
exports = module.exports = function bootLoopBackApp(app, options) {
|
||||
exports = module.exports = function bootLoopBackApp(app, options, callback) {
|
||||
// backwards compatibility with loopback's app.boot
|
||||
options.env = options.env || app.get('env');
|
||||
|
||||
var instructions = compile(options);
|
||||
execute(app, instructions);
|
||||
execute(app, instructions, callback);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -2,6 +2,7 @@ var assert = require('assert');
|
|||
var _ = require('underscore');
|
||||
var semver = require('semver');
|
||||
var debug = require('debug')('loopback:boot:executor');
|
||||
var async = require('async');
|
||||
|
||||
/**
|
||||
* Execute bootstrap instructions gathered by `boot.compile`.
|
||||
|
@ -12,7 +13,7 @@ var debug = require('debug')('loopback:boot:executor');
|
|||
* @header boot.execute(instructions)
|
||||
*/
|
||||
|
||||
module.exports = function execute(app, instructions) {
|
||||
module.exports = function execute(app, instructions, callback) {
|
||||
patchAppLoopback(app);
|
||||
assertLoopBackVersion(app);
|
||||
|
||||
|
@ -24,9 +25,16 @@ module.exports = function execute(app, instructions) {
|
|||
setupDataSources(app, instructions);
|
||||
setupModels(app, instructions);
|
||||
|
||||
runBootScripts(app, instructions);
|
||||
|
||||
enableAnonymousSwagger(app, instructions);
|
||||
// Run the boot scripts in series synchronously or asynchronously
|
||||
// Please note async supports both styles
|
||||
async.series([
|
||||
function(done) {
|
||||
runBootScripts(app, instructions, done);
|
||||
},
|
||||
function(done) {
|
||||
enableAnonymousSwagger(app, instructions);
|
||||
done();
|
||||
}], callback);
|
||||
};
|
||||
|
||||
function patchAppLoopback(app) {
|
||||
|
@ -176,13 +184,36 @@ function forEachKeyedObject(obj, fn) {
|
|||
});
|
||||
}
|
||||
|
||||
function runScripts(app, list) {
|
||||
if (!list || !list.length) return;
|
||||
function runScripts(app, list, callback) {
|
||||
list = list || [];
|
||||
var functions = [];
|
||||
list.forEach(function(filepath) {
|
||||
debug('Requiring script %s', filepath);
|
||||
var exports = tryRequire(filepath);
|
||||
if (typeof exports === 'function')
|
||||
exports(app);
|
||||
if (typeof exports === 'function') {
|
||||
debug('Exported function detected %s', filepath);
|
||||
functions.push({
|
||||
path: filepath,
|
||||
func: exports
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
async.eachSeries(functions, function(f, done) {
|
||||
debug('Running script %s', f.path);
|
||||
if (f.func.length >= 2) {
|
||||
debug('Starting async function %s', f.path);
|
||||
f.func(app, function(err) {
|
||||
debug('Async function finished %s', f.path);
|
||||
done(err);
|
||||
});
|
||||
} else {
|
||||
debug('Starting sync function %s', f.path);
|
||||
f.func(app);
|
||||
debug('Sync function finished %s', f.path);
|
||||
done();
|
||||
}
|
||||
}, callback);
|
||||
}
|
||||
|
||||
function tryRequire(modulePath) {
|
||||
|
@ -198,8 +229,8 @@ function tryRequire(modulePath) {
|
|||
}
|
||||
}
|
||||
|
||||
function runBootScripts(app, instructions) {
|
||||
runScripts(app, instructions.files.boot);
|
||||
function runBootScripts(app, instructions, callback) {
|
||||
runScripts(app, instructions.files.boot, callback);
|
||||
}
|
||||
|
||||
function enableAnonymousSwagger(app, instructions) {
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
"url": "https://github.com/strongloop/loopback-boot/blob/master/LICENSE"
|
||||
},
|
||||
"dependencies": {
|
||||
"async": "~0.9.0",
|
||||
"commondir": "0.0.1",
|
||||
"debug": "^1.0.4",
|
||||
"lodash.clonedeep": "^2.4.1",
|
||||
|
|
|
@ -3,6 +3,7 @@ var path = require('path');
|
|||
var loopback = require('loopback');
|
||||
var assert = require('assert');
|
||||
var expect = require('must');
|
||||
var fs = require('fs-extra');
|
||||
var sandbox = require('./helpers/sandbox');
|
||||
var appdir = require('./helpers/appdir');
|
||||
|
||||
|
@ -161,13 +162,62 @@ describe('executor', function() {
|
|||
|
||||
describe('with boot and models files', function() {
|
||||
beforeEach(function() {
|
||||
process.bootFlags = process.bootFlags || [];
|
||||
boot.execute(app, simpleAppInstructions());
|
||||
});
|
||||
|
||||
it('should run `boot/*` files', function() {
|
||||
assert(process.loadedFooJS);
|
||||
delete process.loadedFooJS;
|
||||
afterEach(function() {
|
||||
delete process.bootFlags;
|
||||
});
|
||||
|
||||
it('should run `boot/*` files', function(done) {
|
||||
// scripts are loaded by the order of file names
|
||||
expect(process.bootFlags).to.eql([
|
||||
'barLoaded',
|
||||
'barSyncLoaded',
|
||||
'fooLoaded',
|
||||
'barStarted'
|
||||
]);
|
||||
|
||||
// bar finished happens in the next tick
|
||||
// barSync executed after bar finished
|
||||
setTimeout(function() {
|
||||
expect(process.bootFlags).to.eql([
|
||||
'barLoaded',
|
||||
'barSyncLoaded',
|
||||
'fooLoaded',
|
||||
'barStarted',
|
||||
'barFinished',
|
||||
'barSyncExecuted'
|
||||
]);
|
||||
done();
|
||||
}, 10);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with boot with callback', function() {
|
||||
beforeEach(function() {
|
||||
process.bootFlags = process.bootFlags || [];
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
delete process.bootFlags;
|
||||
});
|
||||
|
||||
it('should run `boot/*` files asynchronously', function(done) {
|
||||
boot.execute(app, simpleAppInstructions(), function() {
|
||||
expect(process.bootFlags).to.eql([
|
||||
'barLoaded',
|
||||
'barSyncLoaded',
|
||||
'fooLoaded',
|
||||
'barStarted',
|
||||
'barFinished',
|
||||
'barSyncExecuted'
|
||||
]);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('with PaaS and npm env variables', function() {
|
||||
|
@ -299,5 +349,7 @@ function someInstructions(values) {
|
|||
}
|
||||
|
||||
function simpleAppInstructions() {
|
||||
return boot.compile(SIMPLE_APP);
|
||||
// Copy it so that require will happend again
|
||||
fs.copySync(SIMPLE_APP, appdir.PATH);
|
||||
return boot.compile(appdir.PATH);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
process.bootFlags.push('barLoaded');
|
||||
module.exports = function(app, callback) {
|
||||
process.bootFlags.push('barStarted');
|
||||
process.nextTick(function() {
|
||||
process.bootFlags.push('barFinished');
|
||||
callback();
|
||||
});
|
||||
};
|
|
@ -0,0 +1,5 @@
|
|||
process.bootFlags.push('barSyncLoaded');
|
||||
module.exports = function(app) {
|
||||
process.bootFlags.push('barSyncExecuted');
|
||||
};
|
||||
|
|
@ -1 +1 @@
|
|||
process.loadedFooJS = true;
|
||||
process.bootFlags.push('fooLoaded');
|
Loading…
Reference in New Issue