拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Joplin 插件模板工程全解:从目录结构、`npm run dist` 构建到 Imaging 图像处理 API 实战

Joplin 插件模板工程全解从目录结构、npm run dist构建到 Imaging 图像处理 API 实战【免费下载链接】joplinJoplin - the privacy-focused note taking app with sync capabilities for Windows, macOS, Linux, Android and iOS.项目地址: https://gitcode.com/GitHub_Trending/jo/joplinJoplin 官方在仓库中内置了多个插件示例工程其中packages/app-cli/tests/support/plugins/imaging目录既是一份标准的 Joplin 插件模板模板 README 见 imaging/README.md又是一个演示「图像处理插件 APIImaging」的完整可运行示例。本文将以这份模板文档为主线结合该目录下真实的src/index.ts示例代码、类型定义与packages/lib中的底层实现讲解 Joplin 插件的工程结构、构建打包流程、框架更新方法并深入剖析joplin.imaging图像处理 API 的完整调用链与内存管理模型。读完本文你将能够独立搭建一个 Joplin 插件工程并掌握「从笔记资源/URL/PDF 生成图片、缩放、裁剪、转存为资源并插入笔记」的完整实战方案。插件工程的两大核心文件Joplin 插件模板的骨架非常简单官方 README 明确指出你首先需要关注的两个文件是src/index.ts插件源码的入口文件见 imaging/src/index.tssrc/manifest.json插件清单记录了插件的名称、版本等元信息见 imaging/src/manifest.json。以 imaging 示例为例其 manifest 内容如下{ id: org.joplinapp.plugins.ImagingDemo, manifest_version: 1, app_min_version: 1.4, name: Imaging demo, description: Demonstrate how to use the imaging API, version: 1.0.0, author: Laurent Cozic, homepage_url: https://joplinapp.org }各字段含义字段说明id插件唯一标识采用反向域名风格如org.joplinapp.plugins.ImagingDemo构建 JPL 归档时也会以id命名文件manifest_version清单格式版本当前模板为1app_min_version插件要求的最低 Joplin 版本imagine 示例为1.4即低于 1.4 的 Joplin 不会加载该插件name/description插件展示名称与描述version插件版本号author/homepage_url作者与主页信息而src/index.ts是插件逻辑的唯一入口。Joplin 通过joplin.plugins.register({ onStart })注册插件生命周期回调见 index.tsjoplin.plugins.register({ onStart: async function() { await registerMakeThumbnailCommand(); await registerInlinePdfCommand(); await registerMakeThumbnailFromUrlCommand(); }, });onStart在插件启动时被调用所有命令注册、视图创建等初始化工作都在这里完成。imaging 示例正是在这里注册了三个命令并为每个命令在编辑器工具栏创建了按钮。构建插件一条命令产出可分发产物模板 README 说明了构建方式插件使用 Webpack 构建编译产物输出到/dist目录同时在工程根目录生成一个 JPL 归档文件用于分发。运行方式为npm run distpackage.json中dist脚本的实际定义见 imaging/package.json是scripts: { dist: webpack --joplin-plugin-config buildMain webpack --joplin-plugin-config buildExtraScripts webpack --joplin-plugin-config createArchive, prepare: npm run dist, update: npm install -g generator-joplin yo joplin --update }可以看到npm run dist会按顺序执行三个 Webpack 构建步骤对应 webpack.config.js 中的三套配置buildMain编译src/index.ts及其导入的模块输出到/dist同时把src/下其余资源CSS、脚本等非.ts文件复制进/dist该步骤还会清空并重建dist/与publish/目录buildExtraScripts根据plugin.config.json中的extraScripts数组编译插件需要额外打包的脚本如 content scripts 或 webview scripts。本示例的 plugin.config.json 中该数组为空因此这一步为空操作createArchive基于/dist内容打包生成 JPL 插件归档。关于 JPL 归档的实际落盘位置仓库代码与模板 README 的表述略有差异webpack.config.js中的createPluginArchive函数会将/dist目录下的全部文件用 tar 打包输出到publish/目录下的publish/manifest.id.jpl并同时生成一个同名.json文件其中写入_publish_hashJPL 文件的 sha256 值与_publish_commit当前 git 分支与提交号见 webpack.config.js。构建完成后publish/目录即为可直接分发/安装的产物。构建配置的技术要点从 webpack.config.js 可以提炼出模板工程的技术约定入口./src/index.tsapi通过 Webpack alias 指向工程根目录下的api/目录其中包含 Joplin 提供的全套类型声明文件如 JoplinImaging.d.ts语言ts-loader编译 TypeScripttarget: node、mode: productionTypeScript 配置见 tsconfig.json模块格式commonjs、目标es2015、输出到./dist/。模板默认使用 TypeScript但官方注明完全可以修改配置改用纯 JavaScript 编写插件。源码级剖析imaging 示例与joplin.imaging图像处理 API模板 README 本身是通用脚手架说明而该目录的独特价值在于src/index.ts是一个完整的 Imaging API 演示。下面结合 JoplinImaging.d.ts 与 lib 包中的真实实现 packages/lib/services/plugins/api/JoplinImaging.ts剖析其三大功能与底层原理。句柄Handle模型一切图像操作的核心Imaging API 的设计是「创建 → 处理 → 释放」三段式先用createFrom*系列函数把图像载入内存并拿到一个句柄handle再用resize/crop等函数处理图像最后必须调用free()释放。底层实现维护了一个images_数组把「句柄字符串」映射到真实的图像对象private createImageHandle(): Handle { return [Date.now(), Math.random()].join(:); } private cacheImage(data: NativeImageLike) { const handle this.createImageHandle(); this.images_.push({ handle, data }); return handle; }在 Electron 桌面端这个底层图像对象是 Electron 的NativeImageLike支持toPNG()、toJPEG()、resize()、crop()、getSize()。packages/lib/services/plugins/BasePlatformImplementation.ts中通过imaging属性将平台实现注入插件 API因此该 API 是桌面端专用类型声明中标注span classplatform-desktopdesktop/span。功能一为当前笔记生成缩略图makeThumbnail示例注册的makeThumbnail命令见 index.ts演示了最典型的「资源 → 图像 → 缩放 → 转回资源」流程const noteIds await joplin.workspace.selectedNoteIds(); if (noteIds.length ! 1) return; const noteId noteIds[0]; const result await joplin.data.get([notes, noteId, resources]); if (result.items.length 0) return; const resource result.items[0]; const imageHandle await joplin.imaging.createFromResource(resource.id); const resizedImageHandle await joplin.imaging.resize(imageHandle, { width: 100 }); const newResource await joplin.imaging.toJpgResource(resizedImageHandle, { title: Thumbnail }); await joplin.commands.execute(insertText, \n![](:/ newResource.id )); await joplin.imaging.free(imageHandle); await joplin.imaging.free(resizedImageHandle);关键调用链说明joplin.workspace.selectedNoteIds()获取当前选中的笔记 ID要求恰好选中 1 条joplin.data.get([notes, noteId, resources])取回该笔记关联的资源列表取第一个资源joplin.imaging.createFromResource(resource.id)把资源加载为图像。底层实现JoplinImaging.ts的getResourcePath会先通过Resource.load()加载资源实体、用Resource.fullPath()解析文件路径并校验文件存在再交给createFromPathjoplin.imaging.resize(imageHandle, { width: 100 })缩放到 100px 宽。ResizeOptions支持width、height与qualitygood | better | best三个可选参数见 JoplinImaging.d.tstoJpgResource将图像转成 JPEG 并创建为新的 Joplin 资源{ title: Thumbnail }作为资源属性传入joplin.commands.execute(insertText, ...)把 Markdown 图片语法![](:/资源ID)插入到当前笔记光标处:/前缀是 Joplin 内部资源链接的标准写法最后用free()释放两个句柄。重要free()是必须的。JoplinImaging.ts中注释明确说明「图像数据不会被 Joplin 自动删除请务必在完成后对句柄调用free()」。free()支持单个句柄或句柄数组内部从images_数组中移除对应条目。若不释放图像数据会一直驻留内存直到插件卸载。功能二从 URL 加载图像makeThumbnailFromUrlmakeThumbnailFromUrl命令见 index.ts演示了createFromPath的一个特殊能力传入 URL 而非本地路径。const imageHandle await joplin.imaging.createFromPath(url); const resizedImageHandle await joplin.imaging.resize(imageHandle, { width: 100 }); const newResource await joplin.imaging.toJpgResource(resizedImageHandle, { title: Thumbnail }); await joplin.commands.execute(insertText, \n![](:/ newResource.id )); await joplin.imaging.free(imageHandle); await joplin.imaging.free(resizedImageHandle);类型定义中对此有明确说明见 JoplinImaging.d.tscreateFromPath同时支持图片与 PDF 文件如果提供的是 URL 而非本地路径文件会先被下载再转换为图像。示例中遍历两个 URL一张 PNG 图片和一个 PDF 文件分别生成缩略图资源插入笔记展示了 URL 来源的完整处理流程。功能三把选中的 PDF 内联为页面图片inlinePdfs第三个命令inlinePdfs见 index.ts是功能最完整的演示覆盖了 PDF 处理const selection: string await joplin.commands.execute(selectedText); // Matches content of the form // text here // Where ([a-z0-9]{32}) matches the resource ID. const resourceLinkRegex /\[.*\]\(:\/([a-z0-9]{32})\)/; const resourceLinkMatch selection.match(resourceLinkRegex); if (!resourceLinkMatch) return; const resourceId resourceLinkMatch[1]; const resource await joplin.data.get([resources, resourceId], { fields: [mime] }); const isPdf resource.mime application/pdf; if (!isPdf) return; await joplin.commands.execute(replaceSelection, ); await joplin.commands.execute(insertText, selection); const pdfInfo await joplin.imaging.getPdfInfoFromResource(resourceId); const images await joplin.imaging.createFromPdfResource( resourceId, { minPage: 1, maxPage: 10, scaleFactor: 0.5 }, ); let pageNumber 0; for (const image of images) { pageNumber; const pageResource await joplin.imaging.toJpgResource( image, { title: Page ${pageNumber} of ${pdfInfo.pageCount} } ); await joplin.commands.execute(insertText, \n- ${pageResource.title}); } await joplin.imaging.free(images);流程拆解解析选中文本用正则/\[.*\]\(:\/([a-z0-9]{32})\)/从选中的 Markdown 中提取文本形式的资源链接([a-z0-9]{32})精确匹配 32 位小写字母数字组成的资源 ID校验类型通过joplin.data.get([resources, resourceId], { fields: [mime] })读取资源的mime字段只有application/pdf才继续PDF 信息查询getPdfInfoFromResource返回{ pageCount }用于生成页码标题PDF 转图片createFromPdfResource(resourceId, { minPage: 1, maxPage: 10, scaleFactor: 0.5 })将 PDF 前 10 页转换为图像数组。CreateFromPdfOptions的参数语义见 JoplinImaging.d.tsminPage起始页码默认1maxPage结束页码默认最后一页若大于 PDF 实际页数则全部页面都会被转换scaleFactor缩放因子示例用0.5控制生成图片的体积逐页转资源并插入每页调用toJpgResource生成标题为「Page N of M」的资源以 Markdown 列表项- 标题形式依次插入批量释放free(images)一次释放整个句柄数组。完整的 Imaging API 能力清单除示例用到的接口外JoplinImaging还提供见 JoplinImaging.d.ts方法说明createFromPath(path)从本地路径或 URL 创建图像支持图片与 PDFcreateFromResource(resourceId)从 Joplin 资源创建图像createFromPdfPath(path)/createFromPdfResource(resourceId)将 PDF 各页转换为图像句柄数组getPdfInfoFromPath/getPdfInfoFromResource获取 PDF 页数信息getSize(handle)获取图像宽高resize(handle, { width, height, quality })缩放图像crop(handle, rectangle)按矩形裁剪图像toPngFile/toJpgFile导出为本地文件JPEG 的quality取值范围 0–100默认 80toPngResource/toJpgResource导出为 Joplin 资源内部先写临时文件再导入free(handles)释放句柄避免内存泄漏toJpgResource/toPngResource的底层实现值得注意见 JoplinImaging.ts它先把图像编码写入Setting.value(tempDir)下的临时文件再调用shim.createResourceFromPath()以resizeLargeImages: never选项导入为资源最后删除临时文件。createFromBuffer与toDataUrl/toBase64在实现中被注释禁用原因是它们需要在插件与主进程间传输完整图像数据会拖慢甚至冻结应用官方建议优先使用createFromPath/createFromResource与toXxxFile/toXxxResource系列方法。工具栏按钮注册示例还演示了 UI 集成每个命令都通过joplin.views.toolbarButtons.create(id, commandName, location)注册一个工具栏按钮。ToolbarButtonLocation枚举定义在 api/types.tsNoteToolbar noteToolbar应用右上角的笔记工具栏作用于整个笔记含元数据桌面端可用EditorToolbar editorToolbar文本编辑器正上方的工具栏仅作用于笔记正文。三个示例按钮均注册在EditorToolbar例如toolbarButtons.create(makeThumbnailButton, makeThumbnail, ToolbarButtonLocation.EditorToolbar)。更新插件框架yo joplin --update的边界与最佳实践模板 README 强调插件框架需要随官方更新命令为yo joplin --update对应package.json中的npm run update它先全局安装generator-joplin再执行上述命令。更新行为的两个关键边界必须清楚只会覆盖src/目录之外的所有框架相关文件如package.json、.gitignore、webpack.config.js等你的源码src/不会被触碰因此如果你修改过框架文件务必先让代码处于版本控制之下更新后才能通过 diff 查看变更并重新应用自己的修改。与之配套的官方建议是尽量不要改动框架文件或尽量把改动降到最小如果确实要改 Webpack 配置新建一个独立的 JavaScript 文件再在webpack.config.js中 include 它。这样框架更新后你只需恢复 include 那一行即可而不用重做整个配置文件——这也是 webpack.config.js 头部注释反复强调的约定。补充说明该目录配套的生成器文档 GENERATOR_DOC.md 描述了更新框架的更多细节——它提到npm run update会尝试合并package.json和.gitignore的变更而非直接覆盖并且会保留src/与 README.md 不动真正可能被整体覆盖、最容易出问题的是webpack.config.js这正是「独立文件 include」方案的由来。若想自行生成新插件工程可全局安装generator-joplin对应 packages/generator-joplin 包后运行yo joplin。从构建到发布JPL 归档的发布条件若要把插件发布到 Joplin 插件仓库GENERATOR_DOC 给出了三个必要条件package.json中name以joplin-plugin-开头如joplin-plugin-tocpackage.json的keywords包含joplin-pluginpublish/目录下存在.jpl与.json两个文件由npm run dist自动生成。webpack.config.js中的validatePackageJson()会在构建时对前两条给出黄色警告。正常流程是运行npm publish发布到 npm之后由官方脚本自动将满足上述条件的插件收录进 Joplin 插件仓库。yo joplin生成器会默认设置好这些字段并生成publish/目录一般无需手工干预。小结与文件导航本文以 imaging/README.md 为骨架完整覆盖了 Joplin 插件的工程结构src/index.tssrc/manifest.json、构建流程npm run dist的三段式 Webpack 构建、JPL 归档生成、框架更新规范yo joplin --update的覆盖边界与「独立文件 include」策略并以同目录的 imaging 示例为纵深的实战教材从源码级剖析了joplin.imaging的句柄内存模型、三类典型应用笔记缩略图、URL 图像、PDF 内联与完整 API 清单。如需继续深入建议按以下路径阅读仓库源码示例插件入口与全部命令imaging/src/index.ts插件清单示例imaging/src/manifest.jsonImaging API 类型定义api/JoplinImaging.d.tsImaging API 底层实现packages/lib/services/plugins/api/JoplinImaging.ts工具栏位置枚举api/types.ts构建脚本与 Webpack 配置imaging/package.json、imaging/webpack.config.js插件生成器文档imaging/GENERATOR_DOC.md 与生成器源码 packages/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创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门