Skip to content

ACFUN-FOSS/ACLiveFrame-plugin-cli

Repository files navigation

ACLiveFrame 插件开发 CLI & Monorepo

本仓库是 ACLiveFrame 插件开发工具的 monorepo 项目。它提供了完整的插件开发 CLI 工具和模板,支持使用 pnpm workspace 管理多个插件,提供统一的构建系统、热重载开发环境,以及完整的工具箱 API 类型定义。

📚 目录


🏗 架构概览

ACLiveFrame 插件系统采用 双进程模型 (Dual-Process Model) 以确保稳定性和灵活性:

  1. 前端 (渲染进程 Renderer):

    • 基于 Vue 3 + Vite 构建。
    • 运行在安全的沙箱环境中 ( Wujie 微前端)。
    • 负责处理 独立窗口 (Window)、侧边栏面板 (UI) 和 直播画板 (Overlay) 的界面渲染。
    • 通过标准的 HTTP/WebSocket 或工具箱提供的 IPC 桥接器与后端通信。

    前端承载机制: 使用 Wujie 微前端框架通过 iframe 沙箱承载插件,确保插件间的隔离。每个形态对应不同的页面组件 (Window/UI/Overlay),通过统一的 usePluginFrame composable 处理插件加载和 API 注入。

  2. 后端 (主进程 Main Process):

    • 作为工具箱管理的 Node.js 子进程运行。
    • 入口点定义在 src/main/index.ts
    • 拥有访问 工具箱 API (系统、文件系统、AcFun API 等) 的完整权限。
    • 负责业务逻辑、数据持久化和繁重的计算任务。

Monorepo 结构

本项目采用 pnpm workspace 管理多个插件:

  • packages/ - 存放所有插件包,每个插件都是独立的npm包
  • template/ - 插件开发模板,用于快速创建新插件
  • types/ - 共享的TypeScript类型定义,提供完整的API类型支持
  • cli.js - 根目录的CLI工具,提供插件创建、构建、开发等功能

清单系统 (The Manifest System)

插件通过 manifest.json 文件定义。在此 CLI 工具中,该清单文件由 package.json 中的 pluginConfig 字段自动生成


🚀 快速开始

先决条件

  • Node.js (推荐 v18+)
  • pnpm (必须 v7.0+,推荐最新版)

安装

克隆本仓库并安装依赖:

git clone <repository-url>
cd plugin-cli
pnpm install

验证安装

# 检查 pnpm 版本
pnpm --version

# 检查 workspace 配置
pnpm -r ls

🔧 插件管理

创建新插件

# 基本创建(会交互式选择插件类型)
pnpm run create <pluginName>

# 带描述的创建
pnpm run create <pluginName> --description "插件描述"

创建过程中会:

  1. 验证插件名称(必须以英文字母开头,只能包含字母、数字、连字符、下划线)
  2. 选择需要的插件类型(window、ui、overlay、main)
  3. 自动复制模板并配置 package.json
  4. 注入 TypeScript 路径别名指向根目录 types/

查看现有插件

# 列出所有插件
ls packages/

# 查看插件状态和版本
pnpm -r ls

# 查看插件信息
pnpm info <pluginName>

现有插件示例

  • obs-assistant: OBS直播助手插件,提供自动启动OBS、同步推流配置等功能,支持UI面板形态。

💻 开发工作流

开发插件

# 在根目录启动指定插件的开发服务器
pnpm run dev <pluginName>

# 例如:开发名为 "obs-assistant" 的插件
pnpm run dev obs-assistant

开发模式会:

  • 启动 Vite 开发服务器(支持热重载)
  • 启动 TypeScript 监听器监控后端代码
  • 自动生成 manifest.json
  • 输出构建产物到插件目录的 release/ 文件夹

构建插件

# 在根目录构建指定插件
pnpm run build <pluginName>

# 构建产物会输出到插件目录的 release/ 文件夹
# 生成的文件名格式: <pluginName>@<version>.zip

完整工作流示例

# 1. 创建新插件(在根目录执行)
pnpm run create my-awesome-plugin

# 2. 进入插件目录
cd packages/my-awesome-plugin

# 3. 安装插件依赖(如果需要额外依赖)
pnpm install

# 4. 返回根目录,启动开发模式
cd ../../
pnpm run dev my-awesome-plugin

# 5. 在另一个终端构建发布版本
pnpm run build my-awesome-plugin

插件内可用命令

在插件目录 (packages/<pluginName>/) 中,你可以使用以下命令:

命令 说明
pnpm run dev 启动开发服务器,支持热重载
pnpm run build 编译前端和后端代码并打包
pnpm run build:main 仅编译后端 TypeScript 代码
pnpm run watch:main 监听后端代码变化并自动编译
pnpm run package 生成发布包 (zip 文件)
pnpm run clean 清理构建产物目录

注意: 推荐使用根目录的 pnpm run dev/build <pluginName> 命令进行开发和构建。


📂 项目结构

plugin-cli/
├── cli.js                       # 主 CLI 工具 (Node.js)
├── packages/                    # 插件包目录
│   └── obs-assistant/          # 示例插件: OBS直播助手
│       ├── src/
│       │   ├── app/            # Vue 3 前端应用
│       │   │   ├── main.ts     # 前端入口点
│       │   │   ├── shell/      # 应用外壳组件
│       │   │   └── views/      # 页面视图 (UI, Overlay, Window)
│       │   └── main/           # Node.js 后端逻辑
│       │       └── index.ts    # 后端入口点
│       ├── public/             # 静态资源 (图标等)
│       ├── release/            # 插件构建产物
│       ├── package.json        # 插件配置 (包含 pluginConfig)
│       ├── vite.config.ts      # Vite 配置
│       └── tsconfig*.json      # TypeScript 配置
├── template/                    # 插件开发模板
├── types/                       # 共享类型定义
│   ├── toolbox-api.d.ts        # 前端 API 类型
│   ├── toolbox-api-main.d.ts   # 后端 API 类型
│   ├── danmu.d.ts              # 弹幕相关类型
│   └── global.d.ts             # 全局类型定义
├── package.json                 # Monorepo 配置
├── pnpm-workspace.yaml         # Workspace 定义
└── README.md                    # 项目文档

⚙️ 配置指南 (pluginConfig)

package.jsonpluginConfig 字段下配置您的插件。

"pluginConfig": {
  "spa": true,                    // 是否为单页应用 (SPA),当为 true 时 html 字段无效
  "main": {                       // 后端入口配置
    "dir": ".",                   // 入口文件所在目录
    "file": "index.js",           // 入口文件名 (由 src/main/index.ts 编译而来)
    "libs": []                    // 依赖库 (可选)
  },
  "icon": "icon.svg",             // 插件图标路径 (相对于 public 目录)

  // 独立窗口配置
  "window": {
    "route": "/window",           // Vue 应用中的路由路径
    "width": 1024,                // 窗口宽度
    "height": 768,                // 窗口高度
    "minWidth": 400,              // 最小宽度
    "minHeight": 200,             // 最小高度
    "resizable": true,            // 是否可调整大小
    "html": "index.html"          // HTML 模板文件 (当 spa 为 true 时无效)
  },

  // OBS 直播画板 / 挂件配置
  "overlay": {
    "route": "/overlay",          // Vue 应用中的路由路径
    "html": "index.html"          // HTML 模板文件 (当 spa 为 true 时无效)
  },

  // 用户配置项 (显示在工具箱设置页面中)
  "config": {
    "config": {
      "type": "input",            // 配置类型: input, select, boolean, textarea, text, file, directory
      "label": "配置项",          // 显示标签
      "description": "这里可以输入插件的配置项,并在插件管理-查看详情-设置中统一管理,支持boolean、number、select、textarea、text、file、directory",
      "default": ""               // 默认值
    },
    "select_demo": {
      "type": "select",           // 下拉选择框
      "label": "选择示例",
      "description": "这是一个下拉选择框示例",
      "default": "option1",
      "options": [                // 选项列表
        {
          "label": "选项1",
          "value": "option1"
        },
        {
          "label": "选项2",
          "value": "option2"
        }
      ]
    }
  }
}

🎨 Window / UI / Overlay 形态说明

ACLiveFrame 支持三种不同的插件前端形态,每种形态适合不同的使用场景:

形态对比

形态 Window UI Overlay
用途 独立工具窗口 嵌入式侧边栏/面板 直播覆盖层/挂件
特点 完整独立页面,可调整大小 轻量嵌入,共享宿主上下文 高性能渲染,透明定位
适用场景 复杂工具、多步骤流程 设置面板、状态监控 实时信息展示、交互挂件
路由路径 /window /ui /overlay
生命周期 独立窗口生命周期 随宿主面板显示 随直播场景激活
性能考虑 内存独立,资源充足 受宿主约束,轻量化 高帧率,DOM 操作最小化
交互方式 窗口控制 API 面板内交互 覆盖层事件处理

配置方式

Window(独立窗口)

{
  "window": {
    "route": "/window",
    "width": 1024,
    "height": 768,
    "minWidth": 400,
    "minHeight": 200,
    "resizable": true
  }
}

UI(侧边栏面板)

{
  "ui": {
    "route": "/ui"
  }
}

Overlay(直播画板)

{
  "overlay": {
    "route": "/overlay"
  }
}

选择建议

  • 选择 Window:如果插件需要复杂的用户界面、多步骤操作,或需要较大的显示空间
  • 选择 UI:如果插件主要是设置界面、信息展示,或需要与宿主工具箱紧密集成
  • 选择 Overlay:如果插件需要在直播画面上显示实时信息、进行视觉增强,或需要高性能渲染

🎯 前端开发示例

Vue 路由配置

src/app/main.ts 中配置不同形态的路由:

import { createApp } from 'vue'
import { createRouter, createWebHistory } from 'vue-router'
import WindowView from './views/WindowView.vue'
import UiView from './views/UiView.vue'
import OverlayView from './views/OverlayView.vue'

const routes = [
  {
    path: '/window',
    component: WindowView
  },
  {
    path: '/ui',
    component: UiView
  },
  {
    path: '/overlay',
    component: OverlayView
  }
]

const router = createRouter({
  history: createWebHistory(),
  routes
})

const app = createApp(App)
app.use(router)
app.mount('#app')

组件间消息传递

发送消息到后端

<template>
  <div>
    <button @click="sendToBackend">发送消息</button>
  </div>
</template>

<script setup lang="ts">
// 假设在 Window 形态中
import type { ToolboxWindowApi } from '@types/toolbox-api'

// --- API Resolution ---
const getApi = (): ToolboxWindowApi => {
  if ((window as any).toolboxApi) return (window as any).toolboxApi

  console.warn('Toolbox API not found')
  return {} as any
}

const api = getApi()

const sendToBackend = async () => {
  if (api?.sendMain) {
    // 发送消息到后端
    await api.sendMain({
      action: 'test',
      method: 'logger.info',
      params: { msg: '来自前端的消息' }
    })
  }
}
</script>

监听后端消息

<template>
  <div>
    <p>收到的消息: {{ receivedMessage }}</p>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue'
import type { ToolboxWindowApi } from '@types/toolbox-api'

// --- API Resolution ---
const getApi = (): ToolboxWindowApi => {
  if ((window as any).toolboxApi) return (window as any).toolboxApi

  console.warn('Toolbox API not found')
  return {} as any
}

const api = getApi()
const receivedMessage = ref('')
let unsubscribe: (() => void) | undefined

onMounted(() => {
  // 监听后端发送的消息
  if (api?.onMainMessage) {
    unsubscribe = api.onMainMessage((payload: any) => {
      if (payload.type === 'update') {
        receivedMessage.value = payload.data
      }
    })
  }
})

onUnmounted(() => {
  if (unsubscribe) {
    unsubscribe()
  }
})
</script>

形态特定的开发模式

Window 形态开发

<!-- WindowView.vue -->
<template>
  <div class="window-container">
    <header>
      <h1>我的工具窗口</h1>
      <button @click="minimizeWindow">最小化</button>
    </header>
    <main>
      <!-- 窗口内容 -->
    </main>
  </div>
</template>

<script setup lang="ts">
import { onMounted } from 'vue'
import type { ToolboxWindowApi } from '@types/toolbox-api'

// --- API Resolution ---
const getApi = (): ToolboxWindowApi => {
  if ((window as any).toolboxApi) return (window as any).toolboxApi

  console.warn('Toolbox API not found in WindowView')
  return {} as any
}

const api = getApi()

const minimizeWindow = async () => {
  if (api?.window) {
    await api.window.minimize()
  }
}
</script>

UI 形态开发

<!-- UiView.vue -->
<template>
  <div class="ui-panel">
    <div class="panel-header">
      <h3>设置面板</h3>
    </div>
    <div class="panel-content">
      <!-- 轻量级设置界面 -->
      <form @submit.prevent="saveSettings">
        <input v-model="setting" type="text" placeholder="设置项">
        <button type="submit">保存</button>
      </form>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import type { ToolboxUiApi } from '@types/toolbox-api'

// --- API Resolution ---
const getApi = (): ToolboxUiApi => {
  if ((window as any).toolboxApi) return (window as any).toolboxApi

  console.warn('Toolbox API not found in UiView')
  return {} as any
}

const api = getApi()
const setting = ref('')

const saveSettings = async () => {
  if (api?.settings?.set) {
    await api.settings.set('userSetting', setting.value)
  }
  console.log('保存设置:', setting.value)
}
</script>

<style scoped>
.ui-panel {
  max-width: 300px; /* 受宿主面板尺寸限制 */
  padding: 16px;
}
</style>

Overlay 形态开发

<!-- OverlayView.vue -->
<template>
  <div class="overlay-container" :style="{ left: position.x + 'px', top: position.y + 'px' }">
    <div class="overlay-content">
      <!-- 实时信息展示 -->
      <div class="info-badge">{{ liveInfo.viewerCount }}</div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted } from 'vue'
import type { ToolboxOverlayApi } from '@types/toolbox-api'

// --- API Resolution ---
const getApi = (): ToolboxOverlayApi => {
  if ((window as any).toolboxApi) return (window as any).toolboxApi

  console.warn('Toolbox API not found in OverlayView')
  return {} as any
}

const api = getApi()
const position = ref({ x: 100, y: 100 })
const liveInfo = ref({ viewerCount: 0 })

onMounted(async () => {
  // 订阅直播数据更新
  if (api?.subscribeEvents) {
    api.subscribeEvents(['message'], (event) => {
      // 高性能更新循环
      const updateLoop = () => {
        // 处理直播数据更新
        liveInfo.value.viewerCount = Math.floor(Math.random() * 1000)
        requestAnimationFrame(updateLoop)
      }
      updateLoop()
    })
  }
})
</script>

<style scoped>
.overlay-container {
  position: absolute;
  pointer-events: none; /* 避免阻挡直播画面交互 */
  z-index: 1000;
}

.overlay-content {
  background: rgba(0, 0, 0, 0.8);
  color: white;
  padding: 8px 12px;
  border-radius: 4px;
  font-size: 14px;
  backdrop-filter: blur(4px);
}
</style>

开发与打包流程

热重载开发

# 在根目录启动开发服务器
pnpm run dev <pluginName>

# 例如:开发 obs-assistant 插件
pnpm run dev obs-assistant

# 访问不同形态:
# - Window: http://localhost:5173/window
# - UI: http://localhost:5173/ui
# - Overlay: http://localhost:5173/overlay

生产构建

# 在根目录构建插件
pnpm run build <pluginName>

# 或者在插件目录内:
# 构建前端资源
pnpm run build

# 构建后端代码
pnpm run build:main

# 打包为发布包
pnpm run package

🖥 后端开发

💡 深入了解: 有关后端工作原理、Worker 架构和何时需要后端的详细信息,请参考 插件开发指南 - 后端原理详解

后端逻辑位于 src/main/index.ts。您必须导出特定的生命周期函数来与工具箱进行交互。

入口点示例 (src/main/index.ts)

import type { ToolboxMainApi } from '@types/toolbox-api-main'

let apiRef: ToolboxMainApi | undefined
let startedAt: number | undefined

// 本地保存订阅的关闭函数,用于清理
const subscriptions: Map<string, () => void> = new Map()

export function afterLoaded(api: ToolboxMainApi) {
  apiRef = api
  startedAt = Date.now()
  api.logger.info('[插件] 已启动')

  // 监听来自前端的消息
  api.onUiMessage((payload: any) => {
    handleUiMessage(payload)
  })

  // 示例:监听配置变更
  api.settings.onChange((newConfig) => {
    api.logger.info('配置已更新:', newConfig)
  })
}

export function cleanup() {
  apiRef?.logger?.info('[插件] 正在清理...')

  // 清理所有订阅
  for (const closer of subscriptions.values()) {
    try { closer() } catch (e) {}
  }
  subscriptions.clear()

  apiRef = undefined
}

export function getStatus() {
  return {
    startedAt,
    running: !!apiRef
  }
}

export function onConfigUpdated(newConfig: unknown) {
  apiRef?.logger?.info(`[插件] 配置更新: ${JSON.stringify(newConfig)}`)
}

/**
 * 处理来自前端的消息
 */
async function handleUiMessage(payload: any) {
  if (!apiRef) return

  try {
    // 解析消息
    if (payload.action === 'test' && payload.method) {
      // 处理测试调用
      const result = await handleTestMethod(payload.method, payload.params)
      // 可以发送结果回前端
      apiRef.sendUI({ type: 'response', result })
    }
  } catch (error) {
    apiRef.logger.error('[插件] 处理消息失败:', error)
  }
}

/**
 * 处理测试方法调用
 */
async function handleTestMethod(method: string, params: any) {
  if (!apiRef) throw new Error('API not initialized')

  const methodParts = method.split('.')
  let target: any = apiRef

  // 遍历方法路径
  for (const part of methodParts) {
    if (target && typeof target === 'object' && part in target) {
      target = target[part]
    } else {
      throw new Error(`Method not found: ${method}`)
    }
  }

  if (typeof target !== 'function') {
    throw new Error(`${method} is not a function`)
  }

  // 调用方法
  if (Array.isArray(params)) {
    return await target(...params)
  } else if (typeof params === 'object' && params !== null) {
    // 根据方法签名决定参数传递方式
    return await target(params)
  } else {
    return await target()
  }
}

📖 API 参考

ToolboxMainApi 提供了后端访问宿主系统和 AcFun 服务的接口。完整的后端类型定义请参阅 types/toolbox-api-main.d.ts

ToolboxWindowApiToolboxUiApi 等前端 API 提供了前端组件访问工具箱服务的接口。完整的前端类型定义请参阅 types/toolbox-api.d.ts

核心模块

1. 订阅与事件流(单一 SSE 通道)

  • 所有插件侧 SSE 订阅均通过统一通道 GET /sse/plugins/:pluginId/overlay,由注入的 toolboxApi 封装。
  • 订阅/取消订阅由主进程通过 /api/plugins/:pluginId/subscribe 管理,无需插件手动拼接 kinds 或 query。
  • 示例:
    • 监听消息:api.subscribeEvents(['message'], (env) => ...)
    • 监听配置变更:api.settings.onChange(cb)(底层使用 config kind)
    • 监听只读 store:api.store.onChange(['account','ui'], cb)(底层使用 store kind + storeKeys)

2. acfun - AcFun 平台集成

访问用户信息、直播间信息、发送弹幕和礼物数据。

// 获取用户信息
const user = await api.acfun.user.getUserInfo('123456');

// 发送弹幕 (需要登录态)
await api.acfun.danmu.sendComment('liveId', '你好,世界');

// 获取直播间信息
const room = await api.acfun.danmu.getLiveRoomInfo('liverId');

2. fs - 文件系统

沙箱化的文件访问和持久化存储。

// 键值对存储 (基于 SQLite)
await api.fs.pluginStorage.write({ key: 'count', value: 1 });
const data = await api.fs.pluginStorage.read('count');

// 简单的文件 IO
await api.fs.writeFile('data.txt', 'content');
const content = await api.fs.readFile('data.txt');

3. window - 窗口控制

控制插件的独立窗口 (如果已配置)。

await api.window.setSize(1024, 768);
await api.window.setAlwaysOnTop(true);
await api.window.minimize();

4. lifecycle - 生命周期事件

监听应用程序事件。

api.lifecycle.on('beforeUnload', () => {
  // 在应用关闭前保存状态
});

5. logger - 日志记录

将日志输出到主工具箱的日志文件中。

api.logger.info('普通信息');
api.logger.error('发生错误');

6. http - 网络代理

通过主进程发起 HTTP 请求 (绕过 CORS 限制)。

const response = await api.http.get('https://api.example.com/data');

7. store - 共享状态

访问全局应用程序状态 (只读)。

const state = await api.store.get(['account']);
console.log(state.account.userInfo);

8. 弹幕事件订阅

订阅直播弹幕、礼物、点赞等实时事件。

// 订阅弹幕事件
api.subscribeDanmaku([], (event: any) => {
  switch (event.type) {
    case 'comment':
      // 处理评论: event.content, event.userInfo.nickname
      console.log(`${event.userInfo.nickname}: ${event.content}`);
      break;
    case 'gift':
      // 处理礼物: event.giftDetail.giftName, event.count, event.value
      console.log(`${event.userInfo.nickname} 送了 ${event.count}${event.giftDetail.giftName}`);
      break;
    case 'like':
      // 处理点赞
      console.log(`${event.userInfo.nickname} 点了赞`);
      break;
  }
});

// 按房间订阅特定事件
api.subscribeDanmaku([{
  roomId: '123456',
  eventTypes: ['comment', 'gift']
}], (event) => {
  // 只处理指定房间和事件类型的弹幕
  console.log('房间弹幕:', event);
});

🐛 插件调试

开发模式调试

1. 使用开发服务器

在插件开发过程中,可以使用工具箱的调试功能来连接外部开发服务器:

# 1. 在根目录启动开发服务器
pnpm run dev <pluginName>

# 例如:启动 obs-assistant 的开发服务器
pnpm run dev obs-assistant

# 2. 在工具箱中添加调试插件
# 打开插件管理页面 -> 添加插件 -> 添加调试插件
# 配置外部开发服务器地址和端口

2. 调试插件配置

在工具箱插件管理页面中:

  1. 点击 "添加插件""添加调试插件"
  2. 在弹出的调试工具对话框中配置:
    • 插件ID: 唯一标识符
    • 开发服务器地址: http://localhost:5173 (或其他端口)
    • 插件配置: manifest.json 中的配置项
  3. 点击 "测试加载" 验证连接
  4. 点击 "确认" 添加调试插件

3. 热重载支持

调试插件支持热重载,当你修改代码时:

  • 前端代码会自动重新编译和刷新
  • 后端代码修改后需要手动重新加载插件
  • 配置文件修改后需要重新添加调试插件

4. 调试信息查看

  • 控制台日志: 在工具箱开发者工具中查看插件日志
  • 网络请求: 监控插件的网络活动
  • 状态检查: 使用插件提供的状态检查功能
  • 错误追踪: 查看工具箱日志文件中的详细错误信息

调试插件识别

调试插件会在插件列表中显示特殊的 "调试插件" 标签,并且:

  • 图标会显示随机图标而不是固定图标
  • 支持实时重载和配置更新
  • 开发服务器断开时会显示连接错误状态

常用调试技巧

前端调试:

// 在插件代码中使用 console.log
console.log('插件初始化完成', { pluginId, version });

// 使用浏览器开发者工具
// F12 打开开发者工具,查看 Console 和 Network 标签

后端调试:

// 在后端代码中使用 logger
api.logger.info('插件收到消息', { message, timestamp: Date.now() });

// 检查插件状态
const status = api.getStatus();
console.log('插件状态:', status);

配置调试:

// 检查配置是否正确加载
api.settings.get().then(config => {
  console.log('当前配置:', config);
});

🔧 故障排除

常见问题

Q: 插件无法加载或运行?

  • 检查 package.json 中的 pluginConfig 配置是否正确
  • 确保 src/main/index.ts 导出了必需的生命周期函数 (afterLoaded, cleanup)
  • 查看工具箱的日志输出以获取详细错误信息

Q: 前端页面无法正常显示?

  • 确认路由配置正确 (在 pluginConfig 中设置正确的 route)
  • 检查 Vue 组件是否正确导入和注册
  • 确保构建过程成功完成 (pnpm build)

Q: API 调用失败?

  • 验证 API 方法名称和参数格式
  • 检查工具箱版本兼容性
  • 查看 src/types/toolbox-api.d.ts 获取正确的类型定义

Q: 热重载不工作?

  • 确保使用 pnpm dev 命令启动开发服务器
  • 检查控制台是否有 TypeScript 编译错误
  • 确认文件修改已保存

调试技巧

  • 使用 api.logger 记录调试信息,这些日志会输出到工具箱的主日志文件中
  • 在前端代码中使用 console.log,日志会显示在插件的开发者工具中
  • 利用 getStatus() 函数返回插件的运行状态

📝 开发提示

  • 类型安全: 充分利用 types/ 目录下的 TypeScript 类型定义,避免运行时错误
  • 错误处理: 在异步操作中添加适当的 try-catch 块,后端代码遵循"只在必要的地方用try-catch"的原则
  • 资源清理: 在 cleanup() 函数中释放所有订阅和定时器
  • 代码风格: 函数声明只允许使用箭头函数风格,保持代码简洁干练
  • 性能优化: 避免频繁的 API 调用,合理使用缓存,UI形态插件注意轻量化

🤝 贡献

欢迎提交 Issue 和 Pull Request 来改进这个插件模板!

请确保:

  • 代码符合现有的代码风格
  • 添加必要的类型定义
  • 更新相关文档
  • 测试功能在不同环境下正常工作

About

适用于ACLiveFrame的快速插件开发脚手架

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published