插件
Fastify 可以通过插件进行扩展,这些插件可以是一组路由、一个服务器
装饰器,或其他功能。使用 register
API 来添加一个或多个插件。
默认情况下,register
创建一个新的作用域,这意味着对 Fastify 实例(通过 decorate
)的更改不会影响当前上下文的祖先,仅对其后代产生影响。此特性支持插件的封装和继承,并创建有向无环图 (DAG),从而避免跨依赖问题。
入门指南 快速开始 包含了使用此 API 的示例:
fastify.register(plugin, [options])
插件选项
fastify.register
的可选 options
参数支持一组预定义的选项,Fastify 本身会使用这些选项,除非该插件被 fastify-plugin 包装。无论插件是否被包装,在调用时都会将此选项对象传递给插件。当前 Fastify 特定支持的选项列表如下:
使用 fastify-plugin 时,这些选项将被忽略。
为了避免冲突,插件应考虑命名空间其选项。例如,一个名为 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()
}))
// fastify-foo 的 opts 参数将是 { hello: 'world' }
fastify.register(require('fastify-foo'), parent => parent.foo_bar)
传递给函数的 Fastify 实例是插件声明时外部 **Fastify 实例** 的最新状态,允许访问通过 [`decorate`](./Decorators.md) 注入的变量,根据 **注册顺序**。如果一个插件依赖于先前插件对 Fastify 实例所做的更改(例如利用现有的数据库连接),这将非常有用。
请记住,传递给函数的 Fastify 实例与传递给插件的实例相同,是外部 Fastify 实例的一个副本而不是引用。使用该实例的行为与其在插件函数中调用时的行为相同。例如,如果调用了 `decorate`,则装饰后的变量将在插件函数内可用,除非该插件被 [`fastify-plugin`](https://github.com/fastify/fastify-plugin) 包装。
路由前缀选项
如果传递了一个键为 prefix
的值为字符串的选项,Fastify 将使用该前缀来处理注册中的所有路由。更多详情请参阅 这里。
请注意,如果路由被包裹在
fastify-plugin
中,则此选项将不起作用(查看解决方法)。
错误处理
错误处理由 avvio 处理。
一般而言,应在下一个 after
或 ready
块中处理错误,否则它们将在 listen
回调中被捕获。
fastify.register(require('my-plugin'))
// `after` 将在之前的 `register` 完成后执行一次
fastify.after(err => console.log(err))
// `ready` 将在所有声明的注册完成后执行一次
fastify.ready(err => console.log(err))
// `listen` 是一个特殊的 ready,
// 因此它以相同的方式工作
fastify.listen({ port: 3000 }, (err, address) => {
if (err) console.log(err)
})
async/await
after
、ready
和 listen
支持 async/await,并且 fastify
本身也是一个 Thenable。
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()
}
请记住,register
总是会创建一个新的 Fastify 范围。如果不需要这样做,请参阅以下部分。
处理作用域
如果 register
只用于通过 decorate
扩展服务器功能,告诉 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