news 2026/9/11 8:39:36

Joplin 插件开发入门:使用 generator-joplin 脚手架从零搭建可发布插件

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Joplin 插件开发入门:使用 generator-joplin 脚手架从零搭建可发布插件

Joplin 插件开发入门:使用 generator-joplin 脚手架从零搭建可发布插件

【免费下载链接】joplinJoplin - the privacy-focused note taking app with sync capabilities for Windows, macOS, Linux, Android and iOS.项目地址: https://gitcode.com/GitHub_Trending/jo/joplin

本文是 Joplin 插件脚手架工具 generator-joplin 的完整使用指南,核心面向希望在 Joplin(Windows / macOS / Linux / Android / iOS 全平台笔记应用)上开发插件的开发者。阅读本文后,你将掌握用 Yeoman 生成插件骨架、理解/src/index.tsmanifest.json等关键文件结构、完成 Webpack 构建产出 JPL 安装包、同步版本号、发布到官方插件仓库,以及通过plugin.config.json编译内容脚本(content script)与 Webview 脚本的完整实战流程。文中所有结论均可在 packages/generator-joplin 目录的源码与模板、以及仓库内置的 note_list_renderer 示例插件 中得到验证。

生成器是什么

generator-joplin是一个基于 Yeoman 的 Joplin 插件项目脚手架(scaffold)工具,其官方描述为 "Scaffolds out a new Joplin plugin"。它在 Joplin 仓库中位于 packages/generator-joplin,核心实现是 generators/app/index.js 中继承自yeoman-generator的 Generator 类,依赖chalkyosayslugifyyeoman-generator等包(见 package.json)。

它解决的核心痛点包括:

  • 手工搭建成本高:插件需要同时维护 TypeScript 入口、Webpack 构建链、manifest 清单、API 类型声明等多套文件,手工初始化极易出错;
  • 版本同步繁琐:插件版本号同时存在于package.jsonmanifest.json,需要保持一致;
  • 发布规范隐蔽:官方插件仓库对包名、关键词、publish 目录有硬性要求,生成器会自动把这些规范配置好。

仓库中的 note_list_renderer 示例插件 就是由这类生成器产出的完整样例,其目录结构(src/api/plugin.config.jsonwebpack.config.jstsconfig.jsonpackage.json)与生成器模板一一对应,可作为本文所有讲解的落地参照。

安装与生成新插件项目

前置条件

使用前需已安装 Node.js 与 npm。生成器对 npm 的版本要求为>= 4.0.0(见 generator-joplin 的 package.json 中engines字段)。

安装 Yeoman 与生成器

npm install -g yo npm install -g generator-joplin

生成插件项目

yo --node-package-manager npm joplin

--node-package-manager npm明确指定使用 npm 作为包管理器,避免交互式询问。运行后生成器会依次向你询问以下信息(对应 generators/app/index.js 中的prompting()阶段):

提问项含义说明
pluginId插件唯一 ID必须全局唯一,如com.example.MyPlugin或一段 UUID
pluginName插件显示名称用户友好的字符串,将显示在 Joplin UI 中
pluginDescription插件描述将写入 manifest 的description字段
pluginAuthor作者将写入 manifest 的author字段
pluginRepositoryUrl仓库 URL将写入 manifest 的repository_url
pluginHomepageUrl主页 URL将写入 manifest 的homepage_url
packageNamenpm 包名默认根据插件名自动推导,可直接回车接受或修改

包名自动推导逻辑:在 generators/app/utils.js 的packageNameFromPluginName()中实现——先把*+~.()'"!:@[]等特殊字符替换为-,再用slugify转小写,修剪首尾多余的连字符,最后统一加上joplin-plugin-前缀,并限制在 214 个字符内。例如插件名 "Test List Plugin" 会得到默认包名joplin-plugin-test-list-plugin,这与 note_list_renderer 的 package.json 中的实际包名完全吻合。

注意:npm 存在一个长期未修复的 bug,会特殊对待.gitignorepackage.json,因此生成器模板目录中把它们命名为.gitignore_TEMPLATEpackage_TEMPLATE.json,在写入阶段再重命名还原(源码中已有注释说明,见 index.js)。

生成后的目录结构

生成器会产出以下关键文件(可在 note_list_renderer 示例 中看到实际效果):

your-plugin/ ├── src/ │ ├── index.ts # 插件源码入口 │ └── manifest.json # 插件清单 ├── api/ # 官方 Joplin Plugin API 类型声明(.d.ts 等) ├── script/ # 发布脚本(含 publish/ 子目录) ├── plugin.config.json # 构建配置(extraScripts 等) ├── webpack.config.js # 构建配置 ├── tsconfig.json ├── package.json ├── README.md └── .gitignore

其中最重要的两个文件是:

  • /src/index.ts:插件源码入口。默认模板内容(见 templates/src/index.ts)为:
import joplin from 'api'; joplin.plugins.register({ onStart: async function() { // eslint-disable-next-line no-console console.info('Hello world. Test plugin started!'); }, });

它从api导入joplin对象(Webpack 配置中为api设置了指向本目录api/的路径别名),并通过joplin.plugins.register()注册插件,onStart是插件启动入口。

  • /src/manifest.json:插件清单,包含名称、版本、作者等元信息。生成后的初始模板见 templates/src/manifest.json,各字段含义:
字段说明
manifest_version清单格式版本,当前为1
id全局唯一插件 ID(对应提问的 pluginId)
app_min_version支持该插件所需的最低 Joplin 版本(模板默认3.7
version插件版本号(初始1.0.0,与 package.json 同步)
name/description/author显示名称、描述、作者
homepage_url/repository_url主页与仓库地址
keywords/categories/screenshots关键词、分类、截图(用于插件仓库展示)
icons/promo_tile图标与推广图配置

构建插件:产出 dist 与 JPL 安装包

构建命令

npm run dist

该命令由三条 Webpack 构建串联而成(见 package_TEMPLATE.json 中的scripts.dist):

webpack --env joplin-plugin-config=buildMain && webpack --env joplin-plugin-config=buildExtraScripts && webpack --env joplin-plugin-config=createArchive

对应 webpack.config.js 中main()函数的三个构建阶段(注释明确说明 Webpack 配置并行运行会有问题,因此必须串行执行多次):

  1. buildMain:编译src/index.tsdist/index.js,同时用copy-webpack-pluginsrc/下其余非 TS/TSX 文件(CSS、图片、无需编译的 JS 等)原样复制到dist/
  2. buildExtraScripts:按plugin.config.json中的extraScripts逐个编译附加脚本(若为空则该阶段直接退出,见buildExtraScriptConfigs的空数组判断);
  3. createArchive:触发onBuildCompleted钩子,把dist/打包为publish/<pluginId>.jpl归档,并生成对应的<pluginId>.json插件信息文件。

构建完成后,产物为:

  • dist/:编译后的可分发代码目录;
  • 根目录(实际为publish/目录):.jpl归档文件(Joplin Plugin 安装包)与.json信息文件,可直接用于分发或在 Joplin 中安装。

打包细节(见 webpack.config.js 的createPluginArchivecreatePluginInfo):.jpl实际是用tarstrict+portable模式把dist/下所有文件打成压缩包;.json则是 manifest 的副本,并额外写入_publish_hashsha256:<jpl 文件的 SHA-256 摘要>)与_publish_commit(当前git分支与提交号,非 git 仓库时留空)两个字段。若dist/为空,打包会直接抛错 "Plugin archive was not created because the "dist" directory is empty"。

构建配置说明

模板项目默认使用TypeScript,但你可以改配置用纯 JavaScript(把入口改成.js并调整 ts-loader 规则即可)。构建链默认mode: 'production'target: 'node',TS 由ts-loader编译。值得注意的是,Webpack 5 默认不再为 Node 内置模块提供 polyfill,而插件运行在 Electron 的 Node 环境中,因此配置把所有builtinModulesfallback显式设为false,既避免警告也无需 polyfill(源码注释见 webpack.config.js)。

构建时还会对package.json做合法性校验(validatePackageJson):包名不以joplin-plugin-开头、keywords不含joplin-plugin、存在postinstall脚本(建议改用prepare)时都会打印黄色警告。

更新插件版本号

npm run updateVersion

该命令执行webpack --env joplin-plugin-config=updateVersion,核心实现在 webpack.config.js 的updateVersion()函数中:

  • 解析当前版本号,取最后一段(patch 位)加 1,例如1.0.3 → 1.0.4
  • 同时更新package.jsonmanifest.json两个文件的版本号,保证它们始终同步;
  • 若更新后两处版本号不一致(例如用户曾手动改过其中一个),会打印警告提示手动对齐。

更新插件框架

npm run update

该命令在模板 package.json 中的定义为:

npm install -g generator-joplin && yo joplin --node-package-manager npm --update --force

即重新安装最新的generator-joplin,并以--update --force模式运行生成器,把模板文件更新到最新版本。

更新模式的合并策略

更新不是无脑覆盖,而是有精细的合并逻辑(见 generators/app/index.js 与 utils.js):

  • src/README.md完全不动noUpdateFiles列表(src/index.tssrc/manifest.jsonREADME.md)在 update 模式下会被跳过;
  • package.json智能合并mergePackageKey()递归合并——目标已存在的键默认保留用户值;keywords确保包含joplin-plugindevDependencies一律采用框架新版本(否则依赖无法随框架升级);scripts中的distprepareupdate三个键强制采用框架版本(若不对,插件将无法正确构建);
  • .gitignore/.npmignore行级合并mergeIgnoreFile()把新旧文件按行拼接并去重,保留空行;
  • plugin.config.json保留现有内容:源码注释说明"暂时保留现有内容,未来可能再做合并";
  • webpack.config.js会被覆盖:这是更新时唯一容易出问题的文件,因此官方建议不要在它里面直接做大改动——可以新建一个独立 JS 文件,再在webpack.config.jsrequire引入,这样更新后只需恢复那一行引入语句即可。模板注释中也明确写着同样的建议(见 webpack.config.js)。

另外,进入 update 模式且未加--silent时,生成器会先弹出一个确认对话框,警告更新会覆盖配置文件、不会改动src/与 README,并提醒先把改动纳入版本控制以便 diff 检查;用户选择不继续则直接退出且不做任何更改。

使用 extraScripts 编译外部脚本

什么时候需要它

默认情况下 Webpack 只编译src/index.ts(以及它 import 的文件),其余文件会被直接复制到插件包中。但以下两类外部脚本必须经过编译(见 GENERATOR_DOC.md 原文档与本仓库模板):

  1. TypeScript 脚本.ts必须编译为.js才能在运行时加载;
  2. 依赖了 package.json 中第三方模块的脚本:无论 JS 还是 TS,都必须编译,使依赖被打包进 JPL 文件,否则运行时无法解析模块。

典型场景是内容脚本(content scripts)与Webview 脚本(webview scripts)。

配置方法

编辑plugin.config.json,把脚本路径加入extraScripts数组:

{ "extraScripts": [ "webviews/index.ts" ] }

规则与行为(结合 webpack.config.js 的resolveExtraScriptPath()与模板说明):

  • 路径相对于/src:例如文件在/src/webviews/index.ts,就写webviews/index.ts
  • 路径指向的文件必须真实存在,否则抛错Could not find extra script: ...
  • 编译产物始终使用.js扩展名webviews/index.ts会输出为webviews/index.js,你在插件代码中引用的就是编译后的这个路径;
  • 编译后的 JS 会覆盖上一阶段(buildMain)复制过去的同名.js文件——这正是设计意图:不需要编译的 JS 被直接复制,需要编译的则被替换为编译产物(源码注释见 webpack.config.js)。

另外,Webpack 配置把@codemirror/*@lezer/*等一系列常用编辑器库声明为 external(extraScriptExternals),这意味着内容脚本可以放心地require('@codemirror/view')等库而不必担心被打包或冲突(完整清单见 webpack.config.js)。

发布插件到官方插件仓库

发布流程

先通过npm publish把插件发布到 npmjs.com。之后会有一个自动脚本扫描 npm,把满足条件的插件收录进 Joplin 官方插件仓库。

必须满足的三个条件

插件要进入官方仓库,必须同时满足(见 GENERATOR_DOC.md):

  1. package.jsonnamejoplin-plugin-开头,例如joplin-plugin-toc
  2. package.jsonkeywords包含joplin-plugin
  3. publish/目录中存在.jpl.json两个文件——它们由npm run dist构建生成。

一般情况下,生成器会自动完成这些配置:包名默认带joplin-plugin-前缀(见上文packageNameFromPluginName逻辑)、keywords初始就包含joplin-plugin(见 package_TEMPLATE.json)、publish/目录由npm run dist自动产出。但如果插件没有出现在仓库中,请按上述三条逐一排查。

补充:仓库模板的package.json还提供了npm run submit脚本(tsc --project script/publish/tsconfig.json && node ./script/publish/dist/index.js),配合 script/publish 目录下的发布流程脚本(含authenticateverifyBuildverifyGitStatesubmitPayload等步骤)使用,用于向插件仓库提交插件信息。此外,webpack.config.js 的validatePackageJson()在构建时就会预先警告这三类不合规情况,是发布前自查的第一道关卡。

生成器的两个特殊运行模式

generators/app/index.js 定义了silentupdate两个命令行选项,理解它们有助于正确使用:

  • --update:进入"框架更新"模式,跳过交互式提问(pluginId等属性置空),按上文合并策略更新配置文件,跳过src/README.md
  • --silent:与--update配合时,跳过更新前的确认对话框,适合脚本化/无人值守更新(如模板中npm run update所执行的yo joplin ... --update --force就是如此)。

更进一步:在仓库中验证与学习

  • 查看生成器全部模板文件:packages/generator-joplin/generators/app/templates,其中 GENERATOR_DOC.md 即为本文原始依据;
  • 阅读生成器核心源码:generators/app/index.js(交互提问、文件写入与更新合并)与 generators/app/utils.js(包名推导、package.json / ignore 文件合并);
  • 研究构建链细节:templates/webpack.config.js 完整展示了 buildMain / buildExtraScripts / createArchive 三阶段与版本更新逻辑;
  • 参考真实产物:packages/app-cli/tests/support/plugins/note_list_renderer 是仓库内置的由生成器产出的示例插件(包含api/类型声明、src/plugin.config.jsonwebpack.config.jspackage.json),可对照其 manifest.json 与 package.json 理解清单字段与脚本的实际形态;
  • 了解插件 API 全貌:api 目录下的Joplin.d.tsJoplinViews*.d.tsJoplinContentScripts.d.ts等类型声明文件,是开发插件时最权威的 API 参考。

总结

generator-joplin把 Joplin 插件开发从"零散手工搭建"收敛为"一条命令起步":安装 Yeoman 与生成器后,交互式回答几个问题即可获得包含 TypeScript 入口、manifest、Webpack 构建链与官方 API 类型声明的完整工程;npm run dist一键产出dist/publish/下的 JPL 安装包;npm run updateVersion保证双版本号同步;npm run update在保留src/与 README 的前提下智能升级框架;extraScripts让内容脚本与 Webview 脚本也能被正确编译;而npm publish加上三条发布规范的自动预配置,让插件可以顺利进入 Joplin 官方插件仓库。掌握这套工具链,你就具备了从零开发、构建、升级到发布 Joplin 插件的完整能力。

【免费下载链接】joplinJoplin - the privacy-focused note taking app with sync capabilities for Windows, macOS, Linux, Android and iOS.项目地址: https://gitcode.com/GitHub_Trending/jo/joplin

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/11 8:37:44

AD9914 DDS配置全解析:从MCU到FPGA的移植实践

简介&#xff1a;基于亚德诺半导体 AD9914 直接数字频率合成器&#xff0c;这份 FPGA 驱动工程示例面向通信、测试测量与雷达系统开发人员&#xff0c;适合需要快速实现高精度频率和相位控制的场景。该芯片支持 3.5 GSPS 采样率与 12 位 DAC&#xff0c;驱动实现需兼顾高速接口…

作者头像 李华
网站建设 2026/9/11 8:36:24

Cal.diy 怎么配置 Twilio 发送短信验证码与通知

Cal.diy 怎么配置 Twilio 发送短信验证码与通知 【免费下载链接】cal.diy Scheduling infrastructure for absolutely everyone. 项目地址: https://gitcode.com/GitHub_Trending/ca/cal.diy 如果你部署了 Cal.diy&#xff08;Scheduling infrastructure for absolutely…

作者头像 李华
网站建设 2026/9/11 8:34:22

8G显存离线数字人:Duix.Avatar免费部署完整指南

8G显存离线数字人&#xff1a;Duix.Avatar免费部署完整指南 【免费下载链接】Duix-Avatar &#x1f680; Truly open-source AI avatar(digital human) toolkit for offline video generation and digital human cloning. 项目地址: https://gitcode.com/GitHub_Trending/he/…

作者头像 李华
网站建设 2026/9/11 8:34:11

树莓派Pico USB-CDC与select实现非阻塞虚拟串口通信控制舵机

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/11 8:34:00

嵌入式Linux下Modbus RTU传感器采集全攻略

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华