插件
插件
Fastify 允许用户使用插件扩展其功能。插件可以是一组路由、服务器装饰器或任何其他内容。用于使用一个或多个插件的 API 是 register
。
默认情况下,register
会创建一个新的作用域,这意味着如果您对 Fastify 实例(通过 decorate
)进行了一些更改,此更改将不会反映到当前上下文的祖先,而只会反映到其后代。此功能使我们能够实现插件的封装和继承,通过这种方式,我们创建了一个有向无环图 (DAG),并且不会出现由交叉依赖关系导致的问题。
您可能已经在入门指南中看到了使用此 API 的便捷性。
fastify.register(plugin, [options])
插件选项
fastify.register
的可选 options
参数支持 Fastify 本身将使用的一组预定义选项,除非插件已使用fastify-plugin包装。无论插件是否已被包装,此选项对象也会在调用时传递给插件。当前支持的 Fastify 特定选项列表为
注意:与 fastify-plugin 一起使用时,这些选项将被忽略。
将来 Fastify 可能直接支持其他选项。因此,为了避免冲突,插件应该考虑对其选项进行命名空间化。例如,插件 foo
可以像这样注册
fastify.register(require('fastify-foo'), {
prefix: '/foo',
foo: {
fooOption1: 'value',
fooOption2: 'value'
}
})
如果冲突不是问题,插件可以简单地按原样接受选项对象。
fastify.register(require('fastify-foo'), {
prefix: '/foo',
fooOption1: 'value',
fooOption2: 'value'
})
options
参数也可以是一个Function
,它将在注册插件时被评估,同时通过第一个位置参数访问 Fastify 实例。
const fp = require('fastify-plugin')
fastify.register(fp((fastify, opts, done) => {
fastify.decorate('foo_bar', { hello: 'world' })
done()
}))
// The opts argument of fastify-foo will be { hello: 'world' }
fastify.register(require('fastify-foo'), parent => parent.foo_bar)
传递给函数的 Fastify 实例是插件声明的外部 Fastify 实例的最新状态,允许根据注册顺序访问由先前插件通过decorate
注入的变量。这在插件依赖于先前插件对 Fastify 实例所做的更改时非常有用,例如利用现有的数据库连接对其进行包装。
请记住,传递给函数的 Fastify 实例与传递给插件的实例相同,是外部 Fastify 实例的副本,而不是引用。实例的任何用法都将与在插件函数中调用时表现相同,例如,如果调用了decorate
,则装饰的变量将在插件函数中可用,除非它已使用fastify-plugin
包装。
路由前缀选项
如果您使用键prefix
和string
值传递选项,Fastify 将使用它作为 register 内所有路由的前缀,有关更多信息,请查看此处。
请注意,如果您使用fastify-plugin
包装路由,此选项将不起作用(有一个解决方法可用)。
错误处理
错误处理由avvio完成。
作为一般规则,强烈建议您在下一个after
或ready
块中处理错误,否则您将在listen
回调中获取它们。
fastify.register(require('my-plugin'))
// `after` will be executed once
// the previous declared `register` has finished
fastify.after(err => console.log(err))
// `ready` will be executed once all the registers declared
// have finished their execution
fastify.ready(err => console.log(err))
// `listen` is a special ready,
// so it behaves in the same way
fastify.listen({ port: 3000 }, (err, address) => {
if (err) console.log(err)
})
async/await
after
、ready
和listen
以及fastify
作为Thenable都支持async/await。
await fastify.register(require('my-plugin'))
await fastify.after()
await fastify.ready()
await fastify.listen({ port: 3000 })
注意:在注册插件时使用await
会加载插件及其底层依赖项树,从而“完成”封装过程。插件及其依赖项加载后,对插件的任何修改都不会反映在父实例中。
ESM 支持
从Node.js v13.3.0
及更高版本开始支持ESM!
// main.mjs
import Fastify from 'fastify'
const fastify = Fastify()
fastify.register(import('./plugin.mjs'))
fastify.listen({ port: 3000 }, console.log)
// plugin.mjs
async function plugin (fastify, opts) {
fastify.get('/', async (req, reply) => {
return { hello: 'world' }
})
}
export default plugin
创建插件
创建插件非常简单,您只需要创建一个函数,该函数接受三个参数:fastify
实例、options
对象和done
回调。
示例
module.exports = function (fastify, opts, done) {
fastify.decorate('utility', function () {})
fastify.get('/', handler)
done()
}
您还可以在另一个register
内部使用register
。
module.exports = function (fastify, opts, done) {
fastify.decorate('utility', function () {})
fastify.get('/', handler)
fastify.register(require('./other-plugin'))
done()
}
有时,您需要知道服务器何时即将关闭,例如,因为您必须关闭与数据库的连接。要了解何时会发生这种情况,您可以使用'onClose'
钩子。
不要忘记register
将始终创建一个新的 Fastify 作用域,如果您不需要这样做,请阅读下一节。
处理作用域
如果您仅使用register
通过decorate
扩展服务器的功能,则您有责任告诉 Fastify 不要创建新的作用域。否则,用户将无法在父作用域中访问您的更改。
您可以通过两种方式告诉 Fastify 避免创建新的上下文。
- 使用
fastify-plugin
模块。 - 使用
'skip-override'
隐藏属性。
我们建议使用fastify-plugin
模块,因为它可以为您解决此问题,并且您可以将 Fastify 的版本范围作为插件支持的参数传递。
const fp = require('fastify-plugin')
module.exports = fp(function (fastify, opts, done) {
fastify.decorate('utility', function () {})
done()
}, '0.x')
查看fastify-plugin
文档以了解有关如何使用此模块的更多信息。
如果您不使用fastify-plugin
模块,则可以使用'skip-override'
隐藏属性,但我们不建议这样做。如果将来 Fastify API 发生更改,则您需要负责更新模块,而如果您使用fastify-plugin
,则可以确保向后兼容性。
function yourPlugin (fastify, opts, done) {
fastify.decorate('utility', function () {})
done()
}
yourPlugin[Symbol.for('skip-override')] = true
module.exports = yourPlugin