Make boot asynchronous
This commit is contained in:
parent
3443c8ba1b
commit
b0df4207c4
|
@ -21,7 +21,7 @@ var Bootstrapper = require('./lib/bootstrapper').Bootstrapper;
|
|||
* @header boot(app)
|
||||
*/
|
||||
|
||||
exports = module.exports = function bootBrowserApp(app, options) {
|
||||
exports = module.exports = function bootBrowserApp(app, options, callback) {
|
||||
// Only using options.id to identify the browserified bundle to load for
|
||||
// this application. If no Id was provided, load the default bundle.
|
||||
var moduleName = 'loopback-boot#instructions';
|
||||
|
@ -39,6 +39,6 @@ exports = module.exports = function bootBrowserApp(app, options) {
|
|||
app: app,
|
||||
instructions: instructions,
|
||||
};
|
||||
bootstrapper.run(context);
|
||||
return bootstrapper.run(context, callback);
|
||||
};
|
||||
|
||||
|
|
30
index.js
30
index.js
|
@ -146,6 +146,11 @@ var utils = require('./lib/utils');
|
|||
*/
|
||||
|
||||
exports = module.exports = function bootLoopBackApp(app, options, callback) {
|
||||
if (typeof options === 'function' && callback === undefined) {
|
||||
callback = options;
|
||||
options = {};
|
||||
}
|
||||
options = options || {};
|
||||
// backwards compatibility with loopback's app.boot
|
||||
options.env = options.env || app.get('env');
|
||||
|
||||
|
@ -156,17 +161,14 @@ exports = module.exports = function bootLoopBackApp(app, options, callback) {
|
|||
app: app,
|
||||
};
|
||||
|
||||
bootstrapper.run(context, callback);
|
||||
return bootstrapper.run(context, callback);
|
||||
};
|
||||
|
||||
exports.compile = function(options) {
|
||||
exports.compile = function(options, done) {
|
||||
var bootstrapper = new Bootstrapper(options);
|
||||
bootstrapper.phases = ['load', 'compile'];
|
||||
var context = {};
|
||||
bootstrapper.run(context, function(err) {
|
||||
if (err) throw err;
|
||||
});
|
||||
return context.instructions;
|
||||
return bootstrapper.run(context, done);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -179,9 +181,13 @@ exports.compile = function(options) {
|
|||
*
|
||||
* @header boot.compileToBrowserify(options, bundler)
|
||||
*/
|
||||
exports.compileToBrowserify = function(options, bundler) {
|
||||
var instructions = exports.compile(options);
|
||||
addInstructionsToBrowserify({ instructions: instructions }, bundler);
|
||||
exports.compileToBrowserify = function(options, bundler, done) {
|
||||
return exports.compile(options, function(err, context) {
|
||||
if (err) return done(err);
|
||||
addInstructionsToBrowserify({ instructions: context.instructions },
|
||||
bundler);
|
||||
done();
|
||||
});
|
||||
};
|
||||
|
||||
/* -- undocumented low-level API -- */
|
||||
|
@ -202,9 +208,5 @@ exports.execute = function(app, instructions, done) {
|
|||
app: app,
|
||||
instructions: instructions,
|
||||
};
|
||||
bootstrapper.run(context, function(err) {
|
||||
if (err) throw err;
|
||||
if (done) done(err);
|
||||
});
|
||||
return context;
|
||||
return bootstrapper.run(context, done);
|
||||
};
|
||||
|
|
|
@ -144,42 +144,40 @@ Bootstrapper.prototype.run = function(context, done) {
|
|||
|
||||
var phases = context.phases || this.phases;
|
||||
var bootPlugins = this.getExtensions('/boot');
|
||||
async.eachSeries(phases, function(phase, done) {
|
||||
async.eachSeries(phases, function(phase, cb1) {
|
||||
debug('Phase %s', phase);
|
||||
async.eachSeries(bootPlugins, function(plugin, done) {
|
||||
async.eachSeries(bootPlugins, function(plugin, cb2) {
|
||||
var result;
|
||||
if (typeof plugin.handler[phase] === 'function') {
|
||||
debug('Invoking %s.%s', plugin.handler.name, phase);
|
||||
try {
|
||||
if (plugin.handler[phase].length === 2) {
|
||||
plugin.handler[phase](context, done);
|
||||
plugin.handler[phase](context, cb2);
|
||||
} else {
|
||||
result = plugin.handler[phase](context);
|
||||
if (typeof Promise !== 'undefined') {
|
||||
if (result && typeof result.then === 'function') {
|
||||
result.then(function(value) {
|
||||
done(null, value);
|
||||
}).catch(function(err) {
|
||||
debug(err);
|
||||
done(err);
|
||||
});
|
||||
} else {
|
||||
done(null, result);
|
||||
}
|
||||
Promise.resolve(result).then(function(value) {
|
||||
cb2(null, value);
|
||||
}).catch(function(err) {
|
||||
debug(err);
|
||||
cb2(err);
|
||||
});
|
||||
} else {
|
||||
done(null, result);
|
||||
cb2(null, result);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
debug(err);
|
||||
done(err);
|
||||
cb2(err);
|
||||
}
|
||||
} else {
|
||||
debug('Skipping %s.%s', plugin.handler.name, phase);
|
||||
return done();
|
||||
return cb2();
|
||||
}
|
||||
}, done);
|
||||
}, done);
|
||||
}, cb1);
|
||||
}, function(err) {
|
||||
return done(err, context);
|
||||
});
|
||||
return done.promise;
|
||||
};
|
||||
|
||||
|
|
|
@ -77,9 +77,14 @@ function runScripts(app, list, callback) {
|
|||
});
|
||||
} else {
|
||||
debug('Starting sync function %s', f.path);
|
||||
f.func(app);
|
||||
debug('Sync function finished %s', f.path);
|
||||
done();
|
||||
var error;
|
||||
try {
|
||||
f.func(app);
|
||||
debug('Sync function finished %s', f.path);
|
||||
} catch (err) {
|
||||
error = err;
|
||||
}
|
||||
done(error);
|
||||
}
|
||||
}, callback);
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
// License text available at https://opensource.org/licenses/MIT
|
||||
|
||||
var boot = require('../');
|
||||
var async = require('async');
|
||||
var exportBrowserifyToFile = require('./helpers/browserify').exportToSandbox;
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
|
@ -40,20 +41,21 @@ describe('browser support for multiple apps', function() {
|
|||
browserifyTestApps(apps, function(err, bundlePath) {
|
||||
if (err) return done(err);
|
||||
|
||||
var bundledApps = executeBundledApps(bundlePath, apps);
|
||||
var app1 = bundledApps.defaultApp;
|
||||
var app2 = bundledApps.browserApp2;
|
||||
var bundledApps = executeBundledApps(bundlePath, apps, function(err) {
|
||||
var app1 = bundledApps.defaultApp;
|
||||
var app2 = bundledApps.browserApp2;
|
||||
|
||||
expect(app1.settings).to.have.property('custom-key', 'custom-value');
|
||||
expect(Object.keys(app1.models)).to.include('Customer');
|
||||
expect(Object.keys(app1.models)).to.not.include('Robot');
|
||||
expect(app1.models.Customer.settings).to.have.property('_customized',
|
||||
'Customer');
|
||||
expect(app1.settings).to.have.property('custom-key', 'custom-value');
|
||||
expect(Object.keys(app1.models)).to.include('Customer');
|
||||
expect(Object.keys(app1.models)).to.not.include('Robot');
|
||||
expect(app1.models.Customer.settings).to.have.property('_customized',
|
||||
'Customer');
|
||||
|
||||
expect(Object.keys(app2.models)).to.include('Robot');
|
||||
expect(Object.keys(app2.models)).to.not.include('Customer');
|
||||
expect(Object.keys(app2.models)).to.include('Robot');
|
||||
expect(Object.keys(app2.models)).to.not.include('Customer');
|
||||
|
||||
done();
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -74,6 +76,7 @@ function browserifyTestApps(apps, next) {
|
|||
|
||||
addPlugins(b);
|
||||
|
||||
var bundles = [];
|
||||
for (var i in apps) {
|
||||
var appDir = apps[i].appDir;
|
||||
var appFile = apps[i].appFile;
|
||||
|
@ -90,28 +93,37 @@ function browserifyTestApps(apps, next) {
|
|||
appRootDir: appDir,
|
||||
};
|
||||
}
|
||||
boot.compileToBrowserify(opts, b);
|
||||
bundles.push(opts);
|
||||
}
|
||||
|
||||
exportBrowserifyToFile(b, 'browser-app-bundle.js', next);
|
||||
async.eachSeries(bundles, function(opts, done) {
|
||||
boot.compileToBrowserify(opts, b, done);
|
||||
}, function(err) {
|
||||
exportBrowserifyToFile(b, 'browser-app-bundle.js', next);
|
||||
});
|
||||
}
|
||||
|
||||
function executeBundledApps(bundlePath, apps) {
|
||||
function executeBundledApps(bundlePath, apps, done) {
|
||||
var code = fs.readFileSync(bundlePath);
|
||||
var context = createBrowserLikeContext();
|
||||
vm.runInContext(code, context, bundlePath);
|
||||
|
||||
var ids = [];
|
||||
var script = 'var apps = {};\n';
|
||||
for (var i in apps) {
|
||||
var moduleName = apps[i].moduleName;
|
||||
var id = apps[i].appId || 'defaultApp';
|
||||
ids.push(id);
|
||||
script += 'apps.' + id + ' = require("' + moduleName + '");\n';
|
||||
}
|
||||
script += 'apps;\n';
|
||||
|
||||
var appsInContext = vm.runInContext(script, context);
|
||||
|
||||
printContextLogs(context);
|
||||
async.each(ids, function(id, done) {
|
||||
appsInContext[id].start(done);
|
||||
}, function(err) {
|
||||
printContextLogs(context);
|
||||
done();
|
||||
});
|
||||
|
||||
return appsInContext;
|
||||
}
|
||||
|
|
|
@ -58,19 +58,18 @@ describe('browser support', function() {
|
|||
browserifyTestApp(appDir, function(err, bundlePath) {
|
||||
if (err) return done(err);
|
||||
|
||||
var app = executeBundledApp(bundlePath);
|
||||
var app = executeBundledApp(bundlePath, function(err) {
|
||||
// configured in fixtures/browser-app/boot/configure.js
|
||||
expect(app.settings).to.have.property('custom-key', 'custom-value');
|
||||
expect(Object.keys(app.models)).to.include('Customer');
|
||||
expect(app.models.Customer.settings)
|
||||
.to.have.property('_customized', 'Customer');
|
||||
|
||||
// configured in fixtures/browser-app/boot/configure.js
|
||||
expect(app.settings).to.have.property('custom-key', 'custom-value');
|
||||
expect(Object.keys(app.models)).to.include('Customer');
|
||||
expect(app.models.Customer.settings)
|
||||
.to.have.property('_customized', 'Customer');
|
||||
|
||||
// configured in fixtures/browser-app/component-config.json
|
||||
// and fixtures/browser-app/components/dummy-component.js
|
||||
expect(app.dummyComponentOptions).to.eql({ option: 'value' });
|
||||
|
||||
done();
|
||||
// configured in fixtures/browser-app/component-config.json
|
||||
// and fixtures/browser-app/components/dummy-component.js
|
||||
expect(app.dummyComponentOptions).to.eql({ option: 'value' });
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -83,14 +82,14 @@ describe('browser support', function() {
|
|||
browserifyTestApp(options, function(err, bundlePath) {
|
||||
if (err) return done(err);
|
||||
|
||||
var app = executeBundledApp(bundlePath);
|
||||
var app = executeBundledApp(bundlePath, function(err) {
|
||||
var modelBuilder = app.registry.modelBuilder;
|
||||
var registry = modelBuilder.mixins.mixins;
|
||||
expect(Object.keys(registry)).to.eql(['TimeStamps']);
|
||||
expect(app.models.Customer.timeStampsMixin).to.eql(true);
|
||||
|
||||
var modelBuilder = app.registry.modelBuilder;
|
||||
var registry = modelBuilder.mixins.mixins;
|
||||
expect(Object.keys(registry)).to.eql(['TimeStamps']);
|
||||
expect(app.models.Customer.timeStampsMixin).to.eql(true);
|
||||
|
||||
done();
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -103,14 +102,14 @@ describe('browser support', function() {
|
|||
browserifyTestApp(appDir, 'coffee', function(err, bundlePath) {
|
||||
if (err) return done(err);
|
||||
|
||||
var app = executeBundledApp(bundlePath);
|
||||
|
||||
// configured in fixtures/browser-app/boot/configure.coffee
|
||||
expect(app.settings).to.have.property('custom-key', 'custom-value');
|
||||
expect(Object.keys(app.models)).to.include('Customer');
|
||||
expect(app.models.Customer.settings)
|
||||
.to.have.property('_customized', 'Customer');
|
||||
done();
|
||||
var app = executeBundledApp(bundlePath, function(err) {
|
||||
// configured in fixtures/browser-app/boot/configure.coffee
|
||||
expect(app.settings).to.have.property('custom-key', 'custom-value');
|
||||
expect(Object.keys(app.models)).to.include('Customer');
|
||||
expect(app.models.Customer.settings)
|
||||
.to.have.property('_customized', 'Customer');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -127,18 +126,19 @@ function browserifyTestApp(options, strategy, next) {
|
|||
var appDir = typeof(options) === 'object' ? options.appRootDir : options;
|
||||
var b = compileStrategies[strategy](appDir);
|
||||
|
||||
boot.compileToBrowserify(options, b);
|
||||
|
||||
exportBrowserifyToFile(b, 'browser-app-bundle.js', next);
|
||||
boot.compileToBrowserify(options, b, function(err) {
|
||||
exportBrowserifyToFile(b, 'browser-app-bundle.js', next);
|
||||
});
|
||||
}
|
||||
|
||||
function executeBundledApp(bundlePath) {
|
||||
function executeBundledApp(bundlePath, done) {
|
||||
var code = fs.readFileSync(bundlePath);
|
||||
var context = createBrowserLikeContext();
|
||||
vm.runInContext(code, context, bundlePath);
|
||||
var app = vm.runInContext('require("browser-app")', context);
|
||||
|
||||
printContextLogs(context);
|
||||
|
||||
app.start(function(err) {
|
||||
printContextLogs(context);
|
||||
done(err);
|
||||
});
|
||||
return app;
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -7,8 +7,10 @@ var loopback = require('loopback');
|
|||
var boot = require('../../../');
|
||||
|
||||
var app = module.exports = loopback();
|
||||
app.start = function(done) {
|
||||
boot(app, {
|
||||
appId: 'browserApp2',
|
||||
appRootDir: __dirname,
|
||||
}, done);
|
||||
};
|
||||
|
||||
boot(app, {
|
||||
appId: 'browserApp2',
|
||||
appRootDir: __dirname,
|
||||
});
|
||||
|
|
|
@ -7,4 +7,6 @@ var loopback = require('loopback');
|
|||
var boot = require('../../../');
|
||||
|
||||
var app = module.exports = loopback();
|
||||
boot(app);
|
||||
app.start = function(done) {
|
||||
boot(app, __dirname, done);
|
||||
};
|
||||
|
|
|
@ -2,4 +2,5 @@ loopback = require 'loopback'
|
|||
boot = require '../../../'
|
||||
|
||||
module.exports = client = loopback()
|
||||
boot(client)
|
||||
client.start = (done) ->
|
||||
boot(client, __dirname, done)
|
||||
|
|
Loading…
Reference in New Issue