Super Productivity 插件开发指南:从零构建、打包、发布到 i18n 国际化
2026/9/13 22:03:20 网站建设 项目流程

Super Productivity 插件开发指南:从零构建、打包、发布到 i18n 国际化

【免费下载链接】super-productivitySuper Productivity is an advanced todo list app with integrated Timeboxing and time tracking capabilities. It also comes with integrations for Jira, GitLab, GitHub and Open Project.项目地址: https://gitcode.com/GitHub_Trending/su/super-productivity

本指南以packages/plugin-dev/README.md为主体,结合仓库内plugin-api类型定义、vite-plugin构建工具、示例插件与源码实现,系统讲解如何在 Super Productivity(高级待办清单 + 时间追踪应用)中开发插件:从脚手架搭建、PluginAPI能力矩阵、生命周期 Hooks,到plugin.zip打包、大小限制、GitHub Actions 发布,以及基于i18n/目录的完整国际化方案。读完你将能够独立创建一个可安装、可分发、支持多语言的 Super Productivity 插件。

目录

  • 插件开发环境与工作区
  • 快速上手:三种起步方式
  • 插件项目结构与构建产物
  • PluginAPI:插件能力全景
  • 生命周期 Hooks:订阅应用事件
  • 清单文件 manifest.json 详解
  • 构建与打包:从源码到 plugin.zip
  • 发布插件:GitHub Release 与 npm
  • 本地测试与调试
  • TypeScript 开发与类型安全
  • 插件国际化(i18n)完整指南
  • 最佳实践与疑难排查
  • 仓库内示例插件一览

插件开发环境与工作区

Super Productivity 的插件开发工作区位于仓库的packages/plugin-dev/目录,其package.json@super-productivity/plugin-api作为本地依赖,并通过 npm workspaces 把example-pluginsimple-typescript-pluginprocrastination-buster等示例纳入统一管理。

前置条件

  • Node.js 18 或更高版本
  • npm 或 yarn
  • TypeScript 基础(推荐,非必需)

工作区统一命令(在packages/plugin-dev/下执行):

# 构建所有插件 npm run build # 为所有插件安装依赖 npm run install:all # 清理构建产物(删除所有插件的 dist 目录) npm run clean:dist # 列出当前可用的插件目录 npm run list

list命令在 package.json 中的实现为ls -d */ | grep -v node_modules | grep -v scripts,可以快速查看仓库中已有哪些插件可作为参考。开发期常用的模式是在某个具体插件目录内单独执行npm installnpm run build,而不是每次都全量构建。

快速上手:三种起步方式

QUICK_START.md 为开发者提供了三种渐进式起步方案,按复杂度递增:

方案一:纯 JavaScript(最简单)

cd minimal-plugin # 编辑 plugin.js # 打成 zip 后上传即可
  • 优点:无构建步骤,改完即生效,反馈最快;
  • 缺点:没有 TypeScript 类型检查和打包能力。

方案二:简易 TypeScript(推荐入门)

cd simple-typescript-plugin npm install npm run build # 构建产物 plugin.zip 位于 dist/
  • 优点:具备 TypeScript 类型支持,构建流程简单;
  • 缺点:仅适合单文件插件。

方案三:完整 TypeScript + Webpack/Vite(进阶)

cd example-plugin npm install npm run build npm run package
  • 优点:支持多源文件、完整构建工具链;
  • 缺点:工程配置更复杂。

如何选择

  • 只是想快速验证 API → 使用minimal-plugin
  • 需要类型安全 → 使用simple-typescript-plugin
  • 构建复杂插件 → 使用example-plugin或仓库内更现代的 boilerplate-solid-js(SolidJS + Vite,自带 i18n 支持)。

也可以手动搭建:复制示例插件并重命名,修改manifest.json元数据与package.json名称描述,然后npm installnpm run dev开发、npm run build构建。

插件项目结构与构建产物

一个典型的插件项目结构如下:

my-plugin/ ├── package.json # NPM 包配置 ├── tsconfig.json # TypeScript 配置 ├── webpack.config.js # 构建配置(Webpack 方案) ├── manifest.json # 插件清单(元数据) ├── src/ │ └── index.ts # 插件主代码 ├── assets/ │ ├── index.html # 可选 UI(iframe 插件) │ └── icon.svg # 插件图标 ├── scripts/ │ └── package.js # 生成 plugin.zip 的脚本 └── dist/ # 构建输出 ├── plugin.js # 编译后的插件代码(纯 iframe 插件可省略) ├── manifest.json # 复制过来的清单 └── plugin.zip # 打包产物

如果使用仓库提供的 Vite 插件方案(见packages/vite-plugin/),构建输出在dist/,其中manifest.jsonsrc/manifest.json复制,icon.svgsrc/assets/icon.svg复制,i18n/*.json从插件根目录的i18n/复制,index.html中的 JS/CSS 会被内联为单文件,并可配置copyTo选项把产物自动拷贝到 Super Productivity 的src/assets/下实现热更新开发(见 vite-plugin 源码)。

PluginAPI:插件能力全景

插件运行时接收一个全局PluginAPI对象(类型定义见 packages/plugin-api/src/types.ts)。按能力维度可划分为以下几类:

配置读取

  • cfg:当前应用配置,包括theme'light' | 'dark')、appVersionplatform'web' | 'desktop' | 'android' | 'ios')、isDevlang语言信息。

UI 集成

  • registerMenuEntry():在应用菜单中添加条目;
  • registerHeaderButton():在顶部标题栏添加按钮;
  • registerSidePanelButton():在侧边面板添加按钮;
  • registerWorkContextHeaderButton():注册仅当活跃工作上下文(项目/标签/Today)匹配时才显示的标题按钮,回调会收到上下文快照;
  • registerShortcut():注册键盘快捷键;
  • unregisterShortcut(id):按 id 注销已注册的快捷键(用户在键盘设置中的绑定会被保留,重新注册同名 id 即可恢复);
  • showIndexHtmlAsView():在应用视图中展示插件 UI;
  • showInWorkContext():将插件index.html嵌入工作视图主体(替代任务列表,仅在项目或 Today 上下文生效);
  • closeWorkContextView():恢复为正常任务列表视图;
  • openDialog():打开自定义对话框。

数据访问

  • getTasks():获取全部任务;
  • getArchivedTasks():获取已归档任务;
  • getCurrentContextTasks():获取当前项目/标签下的任务;
  • getSelectedTask()/getFocusedTask():读取详情面板中选中的任务 / 当前获得焦点的任务行;
  • getAppState():获取包含任务、项目、标签、笔记、重复任务配置、简单计数器与全局配置的只读应用快照(PluginAppState);
  • updateTask(taskId, updates):更新任务;
  • addTask(taskData):创建任务,返回新任务 id;
  • deleteTask(taskId):删除任务;
  • batchUpdateForProject():在单个项目中批量执行创建/更新/删除/重排操作(支持临时 id 引用,见 BatchUpdateRequest);
  • getAllProjects()/addProject()/updateProject()/deleteProject():项目读写,其中删除项目会级联删除其包含的任务(与 UI 行为一致,且拒绝删除收件箱);
  • getAllTags()/addTag()/updateTag():标签读写;
  • reorderTasks():重排任务顺序;
  • selectTask(taskId):打开指定任务的详情面板。

用户交互

  • showSnack():显示 snack 条通知,type支持SUCCESS | ERROR | WARNING | INFO
  • notify():显示系统级通知(NotifyCfg);
  • openDialog():打开自定义对话框,HTML 内容会被宿主白名单清洗(脚本、事件处理器属性与危险 URL 均会被移除,见 DialogCfg 注释)。

数据持久化

  • persistDataSynced(dataStr, key?):保存插件数据,可选key参数可将同步数据拆分为多个独立解析的条目;
  • loadSyncedData(key?):加载已保存的数据;
  • getConfig():读取插件配置;
  • setSecret(key, value)/getSecret(key)/deleteSecret(key):本地专用的密钥存储(绝不进入同步、导出或备份,适合存放密码、API Token 等敏感信息)。

网络与系统能力

  • request(url, options):通过宿主受保护的 HTTP 桥发出请求,需要同时在permissions中声明"http"能力、在allowedHosts中声明目标主机(缺一即被拒绝,fail-closed);
  • downloadFile(filename, data):触发文件下载;
  • startOAuthFlow(config)/getOAuthToken()/clearOAuthToken():OAuth 流程与令牌管理;
  • executeNodeScript(request):Electron 桌面端执行 Node 脚本(需主进程用户授权,仅内置插件可授予);
  • dispatchAction(action):派发受限的 NgRx action;
  • isWindowFocused()/onWindowFocusChange(handler):窗口焦点状态;
  • 简单计数器:setCounter/getCounter/incrementCounter/decrementCounter/deleteCounter/getAllCounters
  • log:分级日志对象(critical/err/error/warn/normal/info/verbose/debug)。

生命周期与通信

  • onReady(fn):应用确认所有声明能力就绪后回调(把启动初始化代码放在这里,而不是plugin.js顶层);
  • onUnload(fn):插件被禁用/重载/卸载时回调,用于清理定时器与事件监听器(iframe 插件中为 no-op,因为 iframe 卸载时会随之销毁);
  • onMessage(handler):跨进程消息通信(插件 iframe 与宿主之间,见 PluginIframeMessageType)。

生命周期 Hooks:订阅应用事件

通过registerHook(hook, handler)订阅应用生命周期事件,完整枚举见 PluginHooks:

Hook触发时机载荷要点
taskCreated任务被创建taskId+task
taskComplete任务被标记完成taskId+task
taskUpdate任务被修改taskId+task+changes
taskDelete任务被删除taskId
currentTaskChange活跃任务切换current+previous(可为 null)
finishDay一天结束date
languageChange应用语言切换code/newLanguage
persistedDataChanged本插件持久化数据变化(含远端同步送达与批量导入)无载荷,需重新loadSyncedData()
action自定义 action 分发action+payload
anyTaskUpdate任意任务任意更新action+taskId?+task?+changes?
projectListUpdate项目列表变化action+projectId?+project?+changes?
workContextChange活跃工作上下文切换上下文快照(ActiveWorkContext

registerHook是泛型方法,处理器会收到与 hook 一一对应的强类型载荷(映射见 HookPayloadMap)。例如:

// 注册任务完成处理器 PluginAPI.registerHook('taskComplete', async (task) => { console.log('Task completed:', task); PluginAPI.showSnack({ msg: `Great job completing: ${task.title}`, type: 'SUCCESS', }); }); // 注册键盘快捷键 PluginAPI.registerShortcut({ id: 'my-action', label: 'My Plugin Action', onExec: async () => { const tasks = await PluginAPI.getTasks(); console.log(`You have ${tasks.length} tasks`); }, });

关于workContextChange有一个值得注意的细节:载荷中的taskIds发出时刻的快照而非实时视图,任务增删移动后会过期;需要当前顺序时应随时调用getActiveWorkContext()getTasks()重新读取(见 ActiveWorkContext 的注释说明)。

清单文件 manifest.json 详解

manifest.json是插件的元数据核心,完整字段定义见 PluginManifest:

{ "name": "My Awesome Plugin", "id": "my-awesome-plugin", "manifestVersion": 1, "version": "1.0.0", "minSupVersion": "13.0.0", "description": "An awesome plugin for Super Productivity", "hooks": ["taskComplete", "taskUpdate"], "permissions": ["showSnack", "getTasks", "addTask", "showIndexHtmlAsView"], "allowedHosts": ["api.example.com"], "iFrame": true, "uiKit": true, "sidePanel": false, "icon": "icon.svg", "i18n": { "languages": ["en", "de", "fr"] } }

关键字段说明:

  • id:全局唯一插件标识;
  • manifestVersion:清单格式版本号;
  • minSupVersion:兼容的最低 Super Productivity 版本;
  • hooks:插件声明使用的事件列表;
  • permissions:权限声明(最小权限原则)。常用权限见 plugin-api README:showSnacknotifyshowIndexHtmlAsViewopenDialoggetTasksgetArchivedTasksgetCurrentContextTasksgetSelectedTaskgetFocusedTaskaddTaskgetAllProjectsaddProjectdeleteProjectgetAllTagsaddTagpersistDataSyncedgetAppState等;
  • allowedHosts:允许PluginAPI.request访问的精确主机名列表(host-only、精确匹配、无通配符、忽略端口)。列表为空或省略时request被禁用(fail-closed);同时还必须在permissions中声明"http"能力(见 types.ts 注释)。安装时该列表会展示给用户以便审查插件的出网范围;
  • iFrametrue表示该插件通过index.html提供 UI;
  • uiKit:是否注入 UI Kit CSS reset,默认true
  • sidePaneltrue时插件加载到右侧面板而非路由;
  • icon:SVG 图标路径(相对插件根目录);
  • jsonSchemaCfg:插件配置的 JSON Schema 文件路径;
  • i18n.languages:插件支持的语言代码数组(详见下文国际化章节)。

构建与打包:从源码到 plugin.zip

打包命令

npm run build npm run package

产物为dist/plugin.zip,可直接分发。

文件大小限制

以下限制来自 plugin.const.ts,是宿主端实际执行的校验值(注意:与文档中列出的上限相比,当前源码中的 ZIP 与代码限制更为严格):

文件源码实际限制(当前仓库)
插件 ZIPMAX_PLUGIN_ZIP_SIZE = 10MB
插件代码(plugin.js)MAX_PLUGIN_CODE_SIZE = 5MB
清单(manifest.json)MAX_PLUGIN_MANIFEST_SIZE = 100KB
全部翻译文件合计MAX_PLUGIN_TRANSLATIONS_TOTAL_SIZE = 5MB

开发时请以源码常量 plugin.const.ts 为准,并预留余量。

必选与可选文件

plugin.zip必须包含:

  • manifest.json— 插件元数据;
  • plugin.js— 插件主代码;除非是iFrame: true且带index.html的纯 iframe 插件。

可选文件:

  • index.html— iframe 插件的 UI;
  • icon.svg— 插件图标;
  • i18n/*.json— 多语言翻译文件。

发布插件:GitHub Release 与 npm

GitHub Release(推荐方式)

  1. 为插件创建 GitHub 仓库;
  2. 使用 GitHub Actions 在发布时自动构建,参考 workflow:
name: Build Plugin on: release: types: [created] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: node-version: 18 - run: npm ci - run: npm run build - run: npm run package - uses: softprops/action-gh-release@v1 with: files: dist/plugin.zip
  1. 用户即可从 Releases 下载.zip文件安装。

NPM 包

也可以将插件源码发布到 npm:

  1. package.json中配置 npm scope;
  2. npm run build构建;
  3. npm publish发布。

用户可自行构建,或由你在包中包含构建产物。

本地测试与调试

开发模式测试

# 构建插件 npm run build # 复制到 Super Productivity 的资源目录 npm run install-local # 该命令将构建产物复制到 ../../../src/assets/my-plugin/ # 在开发模式下启动 Super Productivity cd ../../.. && npm start

此外,若使用@super-productivity/vite-plugin,可在 vite 配置中设置copyTo指向 Super Productivity 的src/assets/,构建时自动拷贝实现热更新(见 vite-plugin 源码 的copyTo选项)。

生产构建测试

  1. npm run package打包;
  2. 打开 Super Productivity;
  3. 进入Settings → Plugins
  4. 点击Upload Plugin
  5. 选择你的plugin.zip

调试技巧

  • 打开浏览器 DevTools 查看控制台日志;
  • 插件在主窗口上下文中运行,console.log()直接可见;
  • 插件错误会在 Console 中输出,可利用宿主提供的PluginAPI.log分级日志(debug/info/warn/error等)。

TypeScript 开发与类型安全

收益

  1. 类型安全:完整的 IntelliSense 与编译期检查;
  2. API 发现:所有PluginAPI方法自动补全;
  3. 重构安全:TypeScript 保证重构不破坏接口;
  4. 内联文档:IDE 中直接查看类型注释(例如getAppState()的快照语义、request()的 fail-closed 行为都有详细 JSDoc)。

安装类型包

npm install @super-productivity/plugin-api

带类型的示例

import type { TaskData, ProjectData } from '@super-productivity/plugin-api'; // 类型安全的任务处理 async function processTask(task: TaskData): Promise<void> { if (task.projectId) { const projects = await PluginAPI.getAllProjects(); const project = projects.find((p) => p.id === task.projectId); if (project) { console.log(`Task "${task.title}" belongs to project "${project.title}"`); } } } // 类型安全的 hook 注册 PluginAPI.registerHook('taskUpdate', (data: unknown) => { const task = data as TaskData; processTask(task); });

类型包还导出了PluginHooks枚举、PluginManifestPluginBaseCfgSnackCfgDialogCfgTask/Project/Tag等数据与 UI 类型(plugin-api README)。注意TaskDataProjectDataTagData已被标记为@deprecated,新代码建议直接使用TaskProjectTag

插件国际化(i18n)完整指南

完整规范见 PLUGIN_I18N.md,这里汇总核心要点。

目录结构与清单声明

my-plugin/ ├── manifest.json # 声明支持的语言 ├── plugin.js └── i18n/ # 翻译文件 ├── en.json # 必选 — 英文 ├── de.json # 可选 — 德语 └── fr.json # 可选 — 法语
{ "id": "my-plugin", "name": "My Plugin", "version": "1.0.0", "i18n": { "languages": ["en", "de", "fr"] } }

规则要点

  • languages必填,且必须至少包含"en"(英文是兜底语言);
  • 使用标准小写语言代码(endefresjazh等);
  • 语言代码必须与 Super Productivity 自身的代码匹配且全小写pt-br有效,pt-BR无效会被忽略;
  • 翻译文件必须是UTF-8编码的 JSON,旧式 8 位编码(Latin-1/CP1252)的文件会被直接拒绝;
  • 已声明但缺少对应i18n/<lang>.json的语言会被跳过并在控制台输出警告;不支持的代码统一输出Unsupported language codes: …警告;
  • 上传的插件 ZIP 中所有翻译文件合计不得超过 5MB(源码常量MAX_PLUGIN_TRANSLATIONS_TOTAL_SIZE,见 plugin.const.ts)。

翻译文件格式

使用层级化 JSON 组织:

{ "MESSAGES": { "WELCOME": "Welcome to the plugin!", "ERROR": "An error occurred: {{error}}" }, "BUTTONS": { "SAVE": "Save", "CANCEL": "Cancel" } }

最佳实践:键名统一大写;相关翻译分组;层级保持在 2~3 层以内;使用描述性键名(BUTTONS.SAVE_TASK优于BTN1)。

API 方法

translate(key, params?)

按当前语言翻译键,支持{{param}}参数插值。兜底顺序:当前应用语言 → 英文 → 找不到则返回键本身。

api.translate('MESSAGES.WELCOME'); // → "Welcome to the plugin!" (en) api.translate('MESSAGES.ERROR', { error: 'Network timeout' }); // → "An error occurred: Network timeout" api.translate('BUTTONS.SAVE'); // → "Speichern" (de) / "Save" (en 兜底) api.translate('BUTTONS.DELETE'); // → "BUTTONS.DELETE"(都找不到则返回键)
formatDate(date, format)

按当前语言环境格式化日期,输入支持Date对象、ISO 8601 字符串、毫秒时间戳。预定义格式:'short''medium''long''time''datetime'

api.formatDate(new Date(), 'short'); // → "1/16/26" (en-US) / "16.1.26" (de) api.formatDate('2026-01-16T14:30:00Z', 'datetime'); // → "1/16/26, 2:30 PM" (en)
getCurrentLanguage()

返回当前应用语言代码(如"en""de""fr"),可据此做条件逻辑(如 CJK 字体处理)。

语言切换 Hook

api.registerHook('languageChange', ({ newLanguage }) => { console.log(`Language changed to: ${newLanguage}`); // 插件翻译会自动重载,此处只需处理额外 UI 更新 updatePluginUI(); });

注意:语言切换时插件翻译会自动重新加载,只有需要额外 UI 更新的场景才需注册此 hook。

支持的语言代码

Super Productivity 官方支持的语言(完整表格):endeesfritptpt-brruzhzh-twjakoarfatrplnlnbsvficsskhrukidroro-md。插件只需声明自己实际翻译了的语言,其余用户自动回退到英文。

复数与参数插值

翻译键中不含复数逻辑,推荐用参数动态选择键:

{ "TASK_COUNT_SINGULAR": "{{count}} task remaining", "TASK_COUNT_PLURAL": "{{count}} tasks remaining" }
const key = count === 1 ? 'TASK_COUNT_SINGULAR' : 'TASK_COUNT_PLURAL'; const msg = api.translate(key, { count });

参数插值失败的两类常见错误:缺少花括号语法($name不生效,需{{name}});参数名不匹配(传{ user: 'John' }无法替换{{name}})。

性能与缓存语义

  • 翻译文件在插件激活时加载一次;
  • 翻译结果在内存中缓存,频繁调用translate()无性能影响;
  • 语言切换复用已加载的翻译;
  • 因此不要在插件里自行缓存翻译结果,每次都调用api.translate()即可。

最佳实践与疑难排查

最佳实践

  1. 错误处理:异步操作始终用 try-catch 包裹;
  2. 性能:不要在主线线程执行重型计算;
  3. 状态管理:插件状态使用persistDataSynced()(敏感信息改用setSecret(),避免进入同步/导出/备份);
  4. 用户体验:用 snack 消息提供清晰反馈;
  5. 权限:只申请实际需要的权限;
  6. 版本兼容:正确设置minSupVersion
  7. 国际化:始终附带en.json,为插件添加 i18n 支持以触达更多用户;
  8. 启动/卸载:初始化代码放进onReady(),清理代码放进onUnload()
  9. 网络访问:使用request()时必须同时声明"http"权限与allowedHosts白名单。

疑难排查

插件未加载

  • 检查浏览器控制台错误;
  • 确认manifest.json是合法 JSON;
  • 确认必填字段齐全(idmanifestVersionversionminSupVersion等);
  • 检查文件大小是否超过 plugin.const.ts 中的限制。

TypeScript 报错

  • 运行npm run typecheck查看全部错误;
  • 确认安装了@super-productivity/plugin-api
  • 检查tsconfig.json配置。

构建问题

  • 删除dist/后重新构建;
  • 检查 webpack/vite 配置;
  • 确认所有依赖已安装。

翻译显示为键名而非译文

  • 检查i18n/目录存在于插件 ZIP 根目录(与manifest.json同级);
  • 验证 JSON 文件有效且为 UTF-8;
  • 确认键名大小写完全一致(区分大小写);
  • 查看浏览器控制台中的警告日志。

仓库内示例插件一览

packages/plugin-dev/下提供了丰富的示例插件(npm run list可查看完整列表):

  • minimal-plugin— 最简单的插件(约 10 行代码);
  • simple-typescript-plugin— 带 TypeScript 的最小工程;
  • example-plugin— 功能完整的 Webpack 示例(覆盖全部 API、iframe UI、状态持久化、Hook 处理、构建配置);
  • boilerplate-solid-js— 现代 SolidJS 样板:SolidJS 响应式 UI、Vite 快速构建、i18n 支持(示例翻译)、插件与 iframe 通信,其 manifest.json 与 plugin.ts 是上手参考的绝佳模板;
  • procrastination-buster— 真实业务场景的 SolidJS 插件;
  • 此外还有brain-dumpdoc-modesync-mdtodoist-importvoice-reminderyesterday-tasks-plugin,以及github-issue-providergitlab/gitea/azure-devops/clickup/linear/trello-issue-providercaldav-calendar-providergoogle-calendar-provider等 Issue/日历集成示例,可分别作为标准插件与issueProvider类型插件的参考实现。

建议的开发路线:先用minimal-plugin理解 API,需要类型安全时迁移到 TypeScript,构建复杂插件时再引入 Webpack 或 Vite;全程参考 plugin-api 类型定义 中的 JSDoc 注释,它是插件 API 最权威的行为契约。

【免费下载链接】super-productivitySuper Productivity is an advanced todo list app with integrated Timeboxing and time tracking capabilities. It also comes with integrations for Jira, GitLab, GitHub and Open Project.项目地址: https://gitcode.com/GitHub_Trending/su/super-productivity

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询