3、插件项目结构:package.json配置、入口文件、manifest清单、资源文件组织

好,咱们直接进入正题。一个CVAT插件项目,说白了就是一堆文件按照特定规则摆在一起。我刚开始接触时也觉得挺乱的,但摸清楚套路后,你会发现其实就那么几样东西。

我个人习惯把插件项目比作一个「工具箱」。package.json是箱子的标签,入口文件是开箱的把手,manifest清单是工具清单,资源文件就是里面的扳手螺丝刀。缺一个,这箱子就用不顺手。

3.1 package.json:插件的身份证

每个插件项目根目录下都得有一个 package.json。这玩意儿不光给npm看,CVAT的插件加载器也会读它。我见过不少新手直接复制别人的配置,结果字段名写错了,插件死活加载不上。

核心字段就这几个:

字段 说明 示例值
name 插件唯一标识,建议用 cvat- 前缀 cvat-plugin-auto-annotate
version 语义化版本号 1.0.0
main 入口文件路径 dist/index.js
cvat CVAT专属配置块 见下方代码

这里有个坑——cvat 字段是CVAT自己定义的,不是npm标准字段。我曾经在升级插件时忘了加这个字段,结果CVAT后台根本识别不到我的插件,排查了半天才发现。

{
  "name": "cvat-plugin-auto-annotate",
  "version": "1.0.0",
  "description": "自动标注辅助插件",
  "main": "dist/index.js",
  "cvat": {
    "name": "自动标注工具",
    "type": "annotation",
    "version": "2.0",
    "description": "基于预训练模型的自动标注插件"
  },
  "dependencies": {
    "axios": "^0.21.0"
  }
}
我的小技巧: cvat.type 字段我一般填 annotationinteraction。填错了虽然不会报错,但插件会出现在错误的菜单分类里,用户找起来很费劲。

3.2 入口文件:插件的启动开关

入口文件就是 package.jsonmain 字段指向的那个文件。CVAT加载插件时,会先执行这个文件。说白了,这就是插件的「main函数」。

入口文件必须导出一个函数或一个对象。我习惯导出一个函数,因为这样可以在函数内部做初始化逻辑。你想想看,如果导出一个对象,那所有逻辑都得在模块作用域里执行,调试起来很不方便。

// dist/index.js
import CVATPlugin from './core/plugin';

export default function(context) {
  // context 是CVAT提供的上下文对象
  const plugin = new CVATPlugin(context);
  plugin.init();
  return plugin;
}

嗯,这里要注意:context 对象里包含了CVAT的核心API,比如 context.jobs(任务列表)、context.shapes(标注形状)等。我刚开始写插件时,总想着自己维护状态,后来发现直接用 context 里的东西就够了,省事不少。

3.3 manifest清单:告诉CVAT你的插件长啥样

manifest清单文件通常叫 cvat-plugin.json 或直接写在 package.jsoncvat 字段里。我个人更推荐单独写一个文件,因为这样结构更清晰,尤其是当插件功能复杂时。

manifest里最重要的几个东西:

  • 插件名称:显示在CVAT界面上的名字
  • 图标:插件按钮的图标,支持SVG或字体图标
  • 权限声明:插件需要访问哪些CVAT资源
  • UI插槽:插件要挂载到CVAT的哪个位置
{
  "name": "自动标注工具",
  "icon": "icon-auto-annotate.svg",
  "permissions": ["read:job", "write:shape"],
  "slots": {
    "sidebar": "sidebar.html",
    "toolbar": "toolbar-button"
  }
}
避坑指南: 我曾经在 permissions 里只写了 read:job,结果插件想往任务里写数据时直接报403。记住,权限声明是白名单机制,没写的权限默认都没有。

3.4 资源文件组织:别把文件堆成一团

资源文件包括HTML模板、CSS样式、图片图标、语言包等。我见过最乱的项目,所有文件都扔在根目录下,找起来跟大海捞针似的。

我建议按功能模块来组织目录:

my-cvat-plugin/
├── package.json
├── cvat-plugin.json
├── src/
│   ├── index.js          # 入口文件
│   ├── core/             # 核心逻辑
│   │   ├── plugin.js
│   │   └── utils.js
│   ├── ui/               # UI相关
│   │   ├── sidebar.html
│   │   └── styles.css
│   └── assets/           # 静态资源
│       ├── icons/
│       └── locales/
├── dist/                 # 构建输出
└── README.md

为什么这么分?因为CVAT加载资源时,会根据 slots 配置去找对应的文件。比如 sidebar.html 放在 ui/ 目录下,manifest里写 "sidebar": "ui/sidebar.html",这样路径清晰,别人接手你的代码也容易看懂。

3.5 知识体系总览

说了这么多,咱们用一张图把整个结构串起来。我画了个SVG图,你看一眼就明白了:

CVAT插件项目 package.json 插件身份证 + CVAT配置 入口文件 启动开关,导出函数 manifest清单 权限 + UI插槽声明 资源文件 HTML/CSS/图标/语言包 核心原则:各司其职,路径清晰,权限明确 四者缺一不可,否则CVAT无法正确加载插件

这张图把四个核心组件的关系画得很清楚。你写插件时,就按这个结构来组织代码,基本不会出大问题。

3.6 实战中的一些碎碎念

最后聊几个我踩过的坑:

  • 路径问题:manifest里的路径是相对于插件根目录的,不是相对于入口文件。我一开始写成了 ../ui/sidebar.html,结果CVAT报404。
  • 构建产物:如果你用Webpack或Rollup打包,记得把 dist/ 目录提交到git。我见过有人只提交了 src/,结果别人拉下来跑不了。
  • 版本兼容:CVAT版本升级后,cvat.version 字段要跟着改。我吃过一次亏,插件在CVAT 2.0上跑得好好的,升级到2.1后直接崩了,就是因为API变了但版本号没更新。

一句话总结: package.json管身份,入口文件管启动,manifest管权限和位置,资源文件管长相。把这四样理清楚,你的插件项目就稳了。


专注资料整理