# 插件编写与注册

URL: https://caijiao.org/fastify/plugins/write-register
Source: docs/fastify/plugins/write-register.md
Description: 讲解如何编写自定义 Fastify 插件，并在主应用中注册使用，包括同步与异步插件的实现方式。

Fastify 插件机制允许你将功能模块化，实现代码复用、作用域隔离与配置注入。插件可以封装路由、装饰器、中间件、钩子等逻辑。

## 编写基本插件

Fastify 插件本质是一个函数，接收两个参数：`fastify` 实例与 `options` 配置对象。

```js
// hello-plugin.js
async function helloPlugin(fastify, options) {
  fastify.get('/hello', async () => {
    return { msg: `Hello ${options.name}` };
  });
}

module.exports = helloPlugin;
```

## 注册插件

在主程序中使用 `register()` 方法注册插件，并传入配置项：

```js
const fastify = require('fastify')();

fastify.register(require('./hello-plugin'), { name: 'Fastify' });

fastify.listen({ port: 3000 });
```

访问 `/hello` 会返回：

```json
{ "msg": "Hello Fastify" }
```

## 使用 fastify-plugin 显式声明插件

为确保插件可以被其他插件访问，推荐使用 [`fastify-plugin`](https://github.com/fastify/fastify-plugin)：

```bash
npm install fastify-plugin
```

```js
// hello-plugin.js
const fp = require('fastify-plugin');

async function helloPlugin(fastify, options) {
  fastify.decorate('sayHi', () => `Hi, ${options.name}`);
}

module.exports = fp(helloPlugin);
```

注册后即可在其他地方访问 `fastify.sayHi()`。

## 同步插件

虽然推荐使用 `async` 函数，Fastify 也支持同步插件写法：

```js
function syncPlugin(fastify, options, done) {
  fastify.decorate('x', 123);
  done();
}

module.exports = syncPlugin;
```

注册时使用 `.register(syncPlugin)` 即可。

## 插件内部注册子插件

插件可以嵌套注册其他插件，实现模块组合：

```js
async function parentPlugin(fastify) {
  fastify.register(async function child(fastify) {
    fastify.get('/child', async () => 'from child');
  });
}

module.exports = parentPlugin;
```

## 设置作用域与隔离

默认插件是作用域隔离的，除非使用 `fastify-plugin` 显式暴露。

示例：

```js
// a-plugin.js
fastify.decorate('aaa', '123'); // 默认只在当前插件中可见
```

其他插件访问不到 `aaa`，除非通过 fastify-plugin 注册为全局插件。

## 插件文件结构建议

为保持项目整洁，可将插件放置于独立目录：

```bash
src/
├── plugins/
│   ├── db.js
│   └── auth.js
```

注册：

```js
fastify.register(require('./plugins/db'));
fastify.register(require('./plugins/auth'));
```

每个插件都应专注于单一职责，便于管理与测试。
