diff --git a/README.md b/README.md index e82c448..51060df 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,7 @@ async function third (instance, opts) { * instance.use() * instance.after() * instance.ready() + * instance.start() * instance.override() * instance.onClose() * instance.close() @@ -81,7 +82,7 @@ async function third (instance, opts) { ------------------------------------------------------- -### avvio([instance], [started]) +### avvio([instance], [options], [started]) Starts the avvio sequence. As the name suggest, `instance` is the object representing your application. @@ -107,6 +108,9 @@ server.use(function first (s, opts, cb) { Options: * `expose`: a key/value property to change how `use`, `after` and `ready` are exposed. +* `autostart`: do not start loading plugins automatically, but wait for + a call to [`.start()`](#start)  or [`.ready()`](#ready). + Events: @@ -261,6 +265,16 @@ app.ready(function (err, context, done) { Returns the instance on which `ready` is called, to support a chainable API. +If `autostart: false` is passed as an option, calling `.ready()`  will +also start the boot sequence. + +------------------------------------------------------- + + +### app.start() + +Start the boot sequence, if it was not started yet. + ------------------------------------------------------- diff --git a/boot.js b/boot.js index 4a3dee1..c0bd4cb 100644 --- a/boot.js +++ b/boot.js @@ -88,6 +88,10 @@ function Boot (server, opts, done) { return instance } + if (opts.autostart !== false) { + opts.autostart = true + } + server = server || this this._server = server @@ -98,6 +102,7 @@ function Boot (server, opts, done) { this.once('start', done) } + this.started = false this.booted = false this._readyQ = fastq(this, callWithCbOrNextTick, 1) @@ -114,34 +119,34 @@ function Boot (server, opts, done) { } this._thereIsCloseCb = false - // we init, because we need to emit "start" if no use is called - this._init() + this._doStart = null + const main = new Plugin(this, (s, opts, done) => { + this._doStart = done + if (opts.autostart) { + this.start() + } + }, opts, noop) + + Plugin.loadPlugin.call(this, main, (err) => { + debug('root plugin ready') + if (err) { + this._error = err + if (this._readyQ.length() === 0) { + throw err + } + } else { + this._readyQ.resume() + } + }) } inherits(Boot, EE) -Boot.prototype._init = function () { - if (this.booted) { - throw new Error('root plugin has already booted') - } +Boot.prototype.start = function () { + this.started = true - if (this._current.length === 0) { - const main = new Plugin(this, function root (s, opts, done) { - // we need to wait any call to use() to happen - process.nextTick(done) - }, {}, noop) - Plugin.loadPlugin.call(this, main, (err) => { - debug('root plugin ready') - if (err) { - this._error = err - if (this._readyQ.length() === 0) { - throw err - } - } else { - this._readyQ.resume() - } - }) - } + // we need to wait any call to use() to happen + process.nextTick(this._doStart) } // allows to override the instance of a server, given a plugin @@ -176,8 +181,9 @@ Boot.prototype._addPlugin = function (plugin, opts, callback) { opts = opts || {} callback = callback || null - // we reinit, if use is called after emitting start once - this._init() + if (this.booted) { + throw new Error('root plugin has already booted') + } // we always add plugins to load at the current element const current = this._current[0] @@ -230,6 +236,7 @@ Boot.prototype.close = function (func) { Boot.prototype.ready = function (func) { this._readyQ.push(func) + this.start() return this } diff --git a/test/basic.test.js b/test/basic.test.js index ddd197b..3004626 100644 --- a/test/basic.test.js +++ b/test/basic.test.js @@ -205,3 +205,53 @@ test('promise long resolve', (t) => { t.notOk(err) }) }) + +test('do not autostart', (t) => { + const app = boot(null, { + autostart: false + }) + app.on('start', () => { + t.fail() + }) + t.end() +}) + +test('start with ready', (t) => { + t.plan(2) + + const app = boot(null, { + autostart: false + }) + + app.on('start', () => { + t.pass() + }) + + app.ready(function (err) { + t.error(err) + }) +}) + +test('load a plugin after start()', (t) => { + t.plan(1) + + var startCalled = false + const app = boot(null, { + autostart: false + }) + + app.use((s, opts, done) => { + t.ok(startCalled) + done() + }) + + // we use a timer because + // it is more reliable than + // nextTick and setImmediate + // this almost always will come + // after those are completed + setTimeout(() => { + app.start() + startCalled = true + }, 2) +})