Skip to content

fastify/avvio

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

42 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

avvio   Build Status

Asynchronous bootstrapping made easy. Wait for all components/plugins to start, and then start your whole app.

avvio is fully reentrant and graph-based. You can load components/plugins within plugins, and be still sure that things will happen in the right order.

JavaScript Style Guide

Install

To install avvio, simply use npm:

npm install avvio --save

Example

The example below can be found here and ran using node example.js. It demonstrates how to use avvio to load functions / plugins in order.

'use strict'

const boot = require('avvio')()

boot
  .use(first, { hello: 'world' })
  .after((cb) => {
    console.log('after first and second')
    cb()
  })
  .use(third, (err) => {
    if (err) {
      console.log('something bad happened')
      console.log(err)
    }

    console.log('third plugin loaded')
  })
  .ready(function () {
    console.log('application booted!')
  })

function first (instance, opts, cb) {
  console.log('first loaded', opts)
  instance.use(second, cb)
}

function second (instance, opts, cb) {
  console.log('second loaded')
  process.nextTick(cb)
}

function third (instance, opts, cb) {
  console.log('third loaded')
  cb()
}

API


boot([instance], [started])

Start a boot sequence.

instance will be used as the first argument of all plugins loaded and use, after and ready  function will be added to that object, keeping the support for the chainable API:

const server = {}

require('avvio')(server)

server.use(function first (s, opts, cb) {
  // s is the same of server
  s.use(function second (s, opts, cb) {
    cb()
  }, cb)
}).after(function (cb) {
  // after first and second are finished
  cb()
})

Options:

  • expose: a key/value property to change how use, after and ready are exposed.

Events:

  • 'error'  if something bad happens
  • 'start'  when the application starts

The boot function can be used also as a constructor to inherits from.


app.use(func, [opts], [cb])

Loads a functions asynchronously. The function must have the signature:

function plugin (server, opts, done) {
  done()
}

done must be called only once.

Returns the instance on which use is called, to support a chainable API.

If you need to add more than a function and you don't need to use a different options object or callback, you can pass an array of functions to .use.

boot.use([first, second, third], opts, cb)

The functions will be loaded in the same order as they are inside the array.


app.after(func([done]), [cb])

Calls a functon after all the previously defined plugins are loaded, including all their dependencies. The 'start' event is not emitted yet.

boot.after(function (done) {
  done()
})

done must be called only once.

Returns the instance on which after is called, to support a chainable API.


app.ready(func([done]))

Calls a functon after all the plugins and after call are completed, but befer 'start' is emitted. ready callbacks are executed one at a time.

boot.ready(function (done) {
  done()
})

done must be called only once.

Returns the instance on which ready is called, to support a chainable API.


boot.express(app)

Same as:

const app = express()

boot(app, {
  expose: {
    use: 'load'
  }
})

app.override(server)

Allows to override the instance of the server for each loading plugin. It allows the creation of an inheritance chain for the server instances.

const boot = require('avvio')
const assert = require('assert')
const server = { count: 0 }
const app = boot(server)

console.log(app !== server, 'override must be set on the Avvio instance')

app.override = function (s) {
  // create a new instance with the
  // server as the prototype
  const res = Object.create(s)
  res.count = res.count + 1

  return res
}

app.use(function first (s1, opts, cb) {
  assert(s1 !== server)
  assert(server.isPrototypeOf(s1))
  assert(s1.count === 1)
  s1.use(second, cb)

  function second (s2, opts, cb) {
    assert(s2 !== s1)
    assert(s1.isPrototypeOf(s2))
    assert(s2.count === 2)
    cb()
  }
})

Skip override

If for some reason you have set an override and you want to skip it for a specific function, you must add functionName[Symbol.for('skip-override')] = true to your code.
Example:

const server = { my: 'server' }
const app = boot(server)

app.override = function (s) {
  return Object.create(s)
}

first[Symbol.for('skip-override')] = true
app.use(first)

function first (s, opts, cb) {
  // some code
  cb()
}

Acknowledgements

This project was kindly sponsored by nearForm.

License

Copyright Matteo Collina 2016, Licensed under MIT.