# 创建第一个插件

万事开头难？别担心！开发飞块插件比你想象的更轻松。

在这一节中，我们将手把手带你完成一个“打个招呼”的插件动作：当你在界面中输入名字（如 `飞块`）并按下按钮时，插件便会返回温馨的问候语 `你好，飞块`。

通过这个极简示例，你将掌握插件从**项目搭建**、**清单声明**、**逻辑实现**到**桌面端联调**的完整开发闭环。

---

## 1. 准备项目文件

在开始写代码前，你可以选择使用官方 CLI 工具生成项目，也可以手动创建文件快速体验：

- **方式 A（推荐）：使用官方 CLI 快速生成**  
  按照[使用插件开发工具包](./toolkit.md)完成安装后，执行一行命令即可生成标准的 TypeScript 动作工程：
  ```sh
  flyon init hello --template action --id=example.hello
  cd hello
  flyon build
  ```
- **方式 B：手动创建极简 JavaScript 项目**  
  为了更直观地理解插件构成，这里我们以一个免编译、可直接运行的 JavaScript 结构为例。新建一个名为 `hello` 的空目录，并在其中创建以下 3 个核心文件（或者直接[下载完整示例](/docs-assets/examples/hello.zip)）：

```text
hello/
├── manifest.json   # 插件清单：声明插件信息与提供的功能
├── index.js        # 后台逻辑：实现具体功能的 JavaScript 代码
└── package.json    # 工程配置：指定模块规范与依赖
```

首先编辑 `package.json`，声明当前项目使用 CommonJS 规范，以便 `index.js` 能通过 `require()` 顺畅加载飞块 SDK：



```json
{
  "name": "@example/hello",
  "private": true,
  "version": "1.0.0",
  "type": "commonjs",
  "main": "index.js"
}
```



---

## 2. 编写清单声明（manifest.json）

把以下内容保存为 `manifest.json`。清单是飞块认识你插件的“身份证”，这里我们在 `actions` 数组中声明了一个唯一的动作，ID 定为 `hello`：



```json
{
  "apiVersion": 1,
  "id": "example.hello",
  "name": "Hello 飞块",
  "version": "1.0.0",
  "description": "Hello 飞块教学示例",
  "hostPlatforms": [
    "windows",
    "macos",
    "linux"
  ],
  "main": "index.js",
  "permissions": [],
  "contributes": {
    "actions": [
      {
        "id": "hello",
        "title": "打个招呼",
        "argsSchema": {
          "type": "object",
          "properties": {
            "name": {
              "type": "string",
              "title": "名字",
              "maxLength": 80,
              "default": "飞块",
              "titleKey": "actions.hello.argsSchema.properties.name.title"
            }
          },
          "required": [
            "name"
          ],
          "additionalProperties": false
        },
        "outputSchema": {
          "type": "object",
          "properties": {
            "message": {
              "type": "string"
            }
          },
          "required": [
            "message"
          ],
          "additionalProperties": false
        },
        "titleKey": "actions.hello.title"
      }
    ]
  },
  "icon": "assets/icon.png",
  "i18n": {
    "defaultLocale": "zh-CN",
    "resources": {
      "zh-CN": "locales/zh-CN.json",
      "en-US": "locales/en-US.json"
    }
  },
  "nameKey": "plugin.name",
  "descriptionKey": "plugin.description"
}
```



**关键字段解读：**
- **`argsSchema`（输入参数）**：定义了动作接收的参数规范。这里声明了一个文本类型的字段 `name`。飞块编辑器会根据此定义自动为用户渲染出美观的输入文本框。
- **`outputSchema`（输出结果）**：定义了动作执行完毕后返回的数据结构。这里声明将返回一个包含 `message` 字符串的对象，以便后续的工作流步骤读取。

> 💡 **提示**：`example.hello` 是用于本地学习调试的示例 ID。当你准备正式发布插件时，请务必将其换成你在开发者平台拥有的命名空间，具体命名规范请参阅[发布插件](../publishing/marketplace.md)。

---

## 3. 实现业务逻辑（index.js）

接下来，把以下业务代码保存为 `index.js`：



```js
const { t: tr } = require(process.env.FLYONDECK_SDK_PATH || "@flyondeck/plugin-sdk");
"use strict";
const { definePlugin } = require(process.env.FLYONDECK_SDK_PATH);
definePlugin({
  actions: {
    hello({ name }) {
      return { message: tr("messages.index.hello", [name]) };
    },
  },
});
```



**逻辑解析：**
- **`definePlugin()`**：飞块插件的标准入口函数，负责将你的处理函数安全注册到飞块运行时中。
- **`actions.hello`**：该键名需与清单中的动作 ID 严格对应。
- **函数入参**：第一个参数即为用户在界面或流程中填入的参数对象（例如 `{ name: "飞块" }`）。
- **函数返回值**：返回的对象将作为当前步骤的结果，供后续动作无缝衔接。

> ⚠️ **关于运行环境**：SDK 的加载路径由飞块在启动插件时通过环境变量 `FLYONDECK_SDK_PATH` 自动注入，因此插件入口代码需要由飞块宿主启动，不能直接在终端使用普通 `node index.js` 执行。

---

## 4. 将插件加载进飞块

现在，让你的代码在飞块桌面端跑起来！

1. **开启开发者模式**：打开飞块桌面客户端，进入“设置 → 通用”，勾选开启“开发者模式”。
2. **加载本地工程**：在左侧或顶部导航进入“拓展管理”，点击“加载开发文件夹”，选择刚刚创建的 `hello` 文件夹。
3. **绑定按键动作**：
   - 插件成功启动后，点击任意一个空白按键进入设置面板；
   - 在动作列表中找到并添加刚刚编写的“打个招呼”；
   - 在参数输入框中填入一个名字（例如 `飞块`）并保存。

此时按下该按键，飞块就会在后台静默执行你的 `hello` 函数。

---

## 5. 验证执行与查看结果

由于实体按键在单次执行动作时默认不会把文本结果直接覆盖在按键图标上，想要观察返回结果，推荐通过**动作工作流（Flow）**来验证：

1. 创建或编辑一个流程，第一步添加“打个招呼”动作并输入参数；
2. 第二步添加系统内置的“输出”动作；
3. 在“输出”动作的内容中选择**步骤结果**，选择前一步的“打个招呼”，并指定字段路径为 `message`；
4. 点击“运行流程”。

在调试输出日志中，你将看到清晰打印出的：
```text
你好，飞块
```

🎉 看到这一行，恭喜你！这意味着你的清单配置、参数表单、后台处理逻辑和数据回传机制已全线贯通！

---

## 接下来探索更多

每当你修改了 `index.js` 的代码后，只需在飞块的“拓展管理”中点击一下“重新启动”，改动就会立即生效。

接下来，你可以根据实际需求深入阅读：
- **拓展动作能力**：阅读[开发动作](./actions.md)，了解如何配置更丰富的参数校验、错误处理与文件选择器；
- **分发给朋友或社区**：准备分享给其他人时，阅读[打包与安装](../publishing/package.md)，将插件打包为标准的 `.flyext` 文件。
