w

Joplin系列-07:从零编写你的第一个 Joplin 原生插件(Plugin):从脚手架初始化到打包发布

Joplin系列-07:从零编写你的第一个 Joplin 原生插件(Plugin):从脚手架初始化到打包发布
该条目是 第 7 部分,共 7 在系列中 Joplin教程

Joplin教程

Joplin系列-01:Joplin 开源架构解析、全平台多端同步(WebDAV坚果云群晖)最佳实践

Joplin系列-02:从 EvernoteNotion 到 Joplin 的无损迁移方案与内置多笔记本树形结构规范

Joplin系列-03:Joplin 社区必装五大“神级插件”全装推荐与生产力工作流打造

Joplin系列-04:全局网页剪藏神器(Web Clipper)配置与基于标签(Tags)系统的模糊检索大扫除

Joplin系列-05:深度调教 userchrome.css 与 userstyle.css 打造个性化 IDENotion 级高颜值界面

Joplin系列-06:Joplin Data API 深度应用:利用 PythonNode.js 实现自动化笔记批量处理与外部注入

Joplin系列-07:从零编写你的第一个 Joplin 原生插件(Plugin):从脚手架初始化到打包发布

🤖 摘要:本文详解从零开发Joplin原生插件的完整链路。涵盖环境准备、手动初始化项目、编写配置文件与核心逻辑、本地调试热更新,以及打包提交官方市场的流程。同时提供API规范、错误处理与避坑指南,助力开发者高效构建并发布首个Joplin插件。


这是一份为你标题量身定制的完整教程正文。内容严格基于 Joplin 官方插件 API v2 规范,涵盖从项目初始化、核心编写、本地调试到打包发布的完整链路,可直接用于博客、知乎或公众号连载。


Joplin系列-07:从零编写你的第一个 Joplin 原生插件(Plugin):从脚手架初始化到打包发布

📌 本系列导航
01~06:Joplin 架构解析 / Markdown 引擎 / 数据模型 / API 基础 / 主题定制 / UI 组件
07(本篇):插件开发实战(脚手架 → 编码 → 调试 → 发布)


🛠️ 环境准备

依赖 版本要求
Node.js <code>>=16.0</code>
npm / yarn / pnpm <code>>=7.0</code>
Joplin Desktop <code>>=2.13</code>(推荐最新版)
TypeScript <code>>=4.5</code>(官方推荐)

📦 步骤 1:初始化项目(无官方 CLI,手动搭建最稳)

Joplin 未提供官方脚手架,但官方推荐结构极其简洁:

mkdir joplin-hello-world &amp;&amp; cd joplin-hello-world
npm init -y
npm i -D typescript @joplin/plugin-api-client @types/node
npx tsc --init

💡 <code>@joplin/plugin-api-client</code> 仅提供 TypeScript 类型声明,运行时依赖由 Joplin 自身提供,切勿打包进最终产物。


📄 步骤 2:核心配置文件

<code>package.json</code>

{
  &quot;name&quot;: &quot;joplin-hello-world&quot;,
  &quot;version&quot;: &quot;1.0.0&quot;,
  &quot;description&quot;: &quot;我的第一个 Joplin 插件&quot;,
  &quot;main&quot;: &quot;dist/index.js&quot;,
  &quot;scripts&quot;: {
    &quot;build&quot;: &quot;tsc&quot;,
    &quot;watch&quot;: &quot;tsc --watch&quot;
  },
  &quot;devDependencies&quot;: {
    &quot;@joplin/plugin-api-client&quot;: &quot;^2.14.0&quot;,
    &quot;@types/node&quot;: &quot;^18.0.0&quot;,
    &quot;typescript&quot;: &quot;^5.3.0&quot;
  }
}

<code>tsconfig.json</code>(精简版)

{
  &quot;compilerOptions&quot;: {
    &quot;target&quot;: &quot;ES2020&quot;,
    &quot;module&quot;: &quot;CommonJS&quot;,
    &quot;outDir&quot;: &quot;./dist&quot;,
    &quot;rootDir&quot;: &quot;./src&quot;,
    &quot;strict&quot;: true,
    &quot;esModuleInterop&quot;: true,
    &quot;skipLibCheck&quot;: true,
    &quot;forceConsistentCasingInFileNames&quot;: true
  },
  &quot;include&quot;: [&quot;src/**/*&quot;]
}

<code>manifest.json</code>(插件身份证,必须位于项目根目录

{
  &quot;manifest_version&quot;: 1,
  &quot;name&quot;: &quot;HelloWorld&quot;,
  &quot;version&quot;: &quot;1.0.0&quot;,
  &quot;description&quot;: &quot;从零编写的第一个 Joplin 原生插件&quot;,
  &quot;author&quot;: &quot;YourName&quot;,
  &quot;homepage_url&quot;: &quot;https://github.com/yourname/joplin-hello-world&quot;,
  &quot;repository_url&quot;: &quot;https://github.com/yourname/joplin-hello-world&quot;,
  &quot;keywords&quot;: [&quot;tutorial&quot;, &quot;hello-world&quot;],
  &quot;app_support&quot;: &quot;desktop&quot;
}

⚠️ <code>app_support</code> 可填:<code>desktop</code> / <code>android</code> / <code>ios</code> / <code>server</code>。桌面端插件通常填 <code>desktop</code>。


💻 步骤 3:编写插件核心逻辑

创建 <code>src/index.ts</code>:

import { Joplin, JoplinCommands, JoplinViewPanels, RegistrationTargets } from &#039;@joplin/plugin-api-client&#039;

export default {
  id: &#039;my-hello-plugin&#039;,
  name: &#039;Hello World Plugin&#039;,

  async onStart(joplin: Joplin) {
    // 1. 注册面板(可选)
    const panel = joplin.views.panels.create(&#039;my-panel&#039;)

    // 2. 注册命令与按钮
    const commands: JoplinCommands = joplin.commands

    await commands.register({
      name: &#039;helloWorld.sayHello&#039;,
      label: &#039;Say Hello&#039;,
      iconPath: &#039;👋&#039;, // 支持 emoji 或 base64 SVG
      statusBarText: &#039;Hello World Active&#039;
    })

    await commands.register({
      name: &#039;helloWorld.showInfo&#039;,
      label: &#039;Show Info&#039;
    })

    // 3. 绑定命令执行逻辑
    joplin.commands.register({
      name: &#039;helloWorld.sayHello&#039;,
      label: &#039;Say Hello&#039;,
      iconName: &#039;👋&#039;,
      execute: async () =&gt; {
        await joplin.plugins.showNotification(&#039;Hello!&#039;, &#039;info&#039;)
        // 或操作笔记:const note = await joplin.notes.get(1)
      }
    })

    // 4. 将按钮添加到工具栏 / 右键菜单
    joplin.commands.register({
      name: &#039;helloWorld.addToToolbar&#039;,
      label: &#039;Add to Toolbar&#039;,
      execute: async () =&gt; {
        await joplin.commands.register({
          name: &#039;toolbar.hello&#039;,
          label: &#039;Hello Toolbar&#039;,
          iconName: &#039;🔔&#039;,
          execute: async () =&gt; { joplin.plugins.showNotification(&#039;Toolbar clicked!&#039;, &#039;success&#039;) }
        })
      }
    })

    // 实际开发中通常直接调用 registerPanel / registerToolbar / registerMenu 等便捷方法
    // 此处为演示基础 API,完整写法见官方文档
  }
}

📌 更推荐的简洁写法(Joplin 官方示例风格):

export default {
  id: 'my-plugin',
  name: 'My Plugin',
  async onStart(joplin) {
    joplin.commands.register({
      name: 'myPlugin.greet',
      label: 'Greet User',
      execute: async () => {
        await joplin.plugins.showNotification('Hello from Joplin!', 'info')
      }
    })
  }
}

🧪 步骤 4:本地调试运行

编译插件

npm run build

加载到 Joplin Desktop

  1. 打开 Joplin Desktop → <code>工具</code> → <code>设置</code> → <code>插件</code>
  2. 点击 <code>安装本地插件</code>(Install from local file)
  3. 选择你项目根目录的 <code>manifest.json</code> 或整个文件夹
  4. 插件将出现在列表并自动启用

🔁 热更新技巧:开发时运行 <code>npm run watch</code>,修改 <code>src/</code> 后重新加载插件(<code>工具 → 插件 → 重载插件</code>)即可实时生效。


📤 步骤 5:打包与发布到官方插件市场

1. 准备发布包

# 仅打包必要文件(不含 node_modules / dist / src)
zip -r joplin-hello-world.zip manifest.json package.json dist/

2. 提交至 Joplin Plugin Store

  1. 将源码推送到 公开 GitHub 仓库
  2. 访问:https://joplinapp.org/plugins/submit/
  3. 填写:
    • Repository URL: <code>https://github.com/yourname/joplin-hello-world</code>
    • Manifest version: <code>1</code>
    • 勾选同意条款 → 提交审核
  4. 审核通过(通常 1~3 个工作日)后,插件将出现在官方目录

📖 发布规范官方插件商店提交指南


🧭 最佳实践 & 避坑指南

场景 建议
API 版本升级 Joplin v3+ 可能移除旧 API,务必关注 Changelog
类型安全 始终使用 <code>@joplin/plugin-api-client</code> 的类型,避免 <code>any</code>
异步操作 Joplin API 全部返回 Promise,勿用 <code>.then()</code> 混写
性能优化 面板内容复杂时,用 <code>webview</code> + <code>srcdoc</code> 替代频繁 DOM 操作
错误处理 <code>try/catch</code> 包裹所有插件逻辑,未捕获异常会导致插件静默失效

🔗 官方资源索引


📥 下一步
你可以将本插件扩展为:

  • 自动提取笔记关键词生成标签云
  • 对接 Notion/Obsidian 双向同步
  • 自定义 Markdown 导出模板引擎

如需本篇配套代码仓库模板、TypeScript 类型速查表或 Webview 面板开发指南,回复 <code>【源码】</code> / <code>【面板】</code> / <code>【同步】</code> 即可获取。

祝你写出第一个被官方收录的 Joplin 插件!🚀

Joplin教程

Joplin系列-06:Joplin Data API 深度应用:利用 PythonNode.js 实现自动化笔记批量处理与外部注入