
Joplin 插件开发实战基于 content_script 模板插件的构建流程与框架更新指南【免费下载链接】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 仓库中的示例插件模板packages/app-cli/tests/support/plugins/content_script为蓝本完整讲解一个 Joplin 插件项目的核心文件构成、npm run dist背后的 Webpack 三段式构建机制编译主脚本 → 编译附加脚本 → 打包 JPL 归档以及使用yo joplin --update更新插件框架时如何保护自己的源码与自定义配置。读完后你可以基于该模板搭建可编译、可分发.jpl 归档的 Joplin 插件并理解打包产物中每个字段的来源。模板插件的定位一个可运行的最小 Joplin 插件骨架该 README 明确说明这是一个创建新 Joplin 插件的模板This is a template to create a new Joplin plugin。它位于 app-cli 包的测试支撑目录下同时承担着双重角色对插件开发者演示一个标准插件工程的最小文件组织方式对 Joplin 自身作为集成测试的样例插件插件 ID 为org.joplinapp.plugins.ContentScriptDemo见 manifest.json。同目录下还有大量同类模板插件如post_messages、codemirror6、dialog等它们共享同一套框架文件仅src/内容不同这本身就印证了框架文件与源码分离的设计。两个最核心的文件README 指出开发一个 Joplin 插件主要关注两个文件src/index.ts—— 插件源码的入口点src/manifest.json—— 插件清单manifest包含插件名称、版本等元信息。入口文件 src/index.ts以该模板为例src/index.ts 展示了插件的标准生命周期import joplin from api; import { ContentScriptType } from api/types; joplin.plugins.register({ onStart: async function() { // 注册命令 await joplin.commands.register({ name: testCommand, label: My Test Command, execute: async (...args) { alert(Got command testCommand with args: JSON.stringify(args)); }, }); // 注册内容脚本MarkdownIt 插件类型 await joplin.contentScripts.register( ContentScriptType.MarkdownItPlugin, justtesting, ./markdownItTestPlugin.js ); // 监听来自内容脚本的 postMessage 消息 await joplin.contentScripts.onMessage(justtesting, (message: any) { return message response; }); }, });几个值得注意的实现细节api是一个模块别名而非真实包。webpack.config.js 中通过resolve.alias将api指向工程内的api/目录其中是Joplin.d.ts等类型声明文件因此插件代码import joplin from api在编译时获得完整类型提示而运行时由 Joplin 应用注入实际实现。scriptPath必须相对主脚本。joplin.contentScripts.register()第三个参数./markdownItTestPlugin.js是相对于入口的路径这一点在 JoplinContentScripts.d.ts 的类型注释中有明确规定。内容脚本不是任意代码注入。根据该类型声明文件的注释注册内容脚本本身不做任何事——它只会在特定场景Markdown 渲染器、代码编辑器等应用模块中被按需加载因此它不能被视为在应用中执行任意代码的手段这是出于安全与性能的考虑。清单文件 src/manifest.json模板中的 manifest.json 展示了当前模板采用的全部字段{ id: org.joplinapp.plugins.ContentScriptDemo, manifest_version: 1, app_min_version: 1.4, name: Content Script Test, description: , version: 1.0.0, author: , homepage_url: }构建系统对该文件有硬性校验见下文readManifest分析。构建插件npm run dist 的三段式流水线README 说明插件使用 Webpack 构建编译产物位于/dist同时会在根目录生成一个可用于分发的 JPL 归档构建命令就是npm run dist项目默认配置为 TypeScript也可以改为纯 JavaScript。脚本定义一条命令串起三次 Webpack 运行查看 package.json 可以发现dist脚本的完整定义dist: webpack --joplin-plugin-config buildMain webpack --joplin-plugin-config buildExtraScripts webpack --joplin-plugin-config createArchive即同一次构建会依次以三个不同的配置名运行 Webpack。为什么一个命令要跑三次webpack.config.js 中有明确注释Webpack 的多配置是并行执行的而插件构建必须串行先编译再打包似乎唯一的办法就是多次运行 webpack每次使用不同配置。--joplin-plugin-config参数即用于选择本次运行要返回哪一组配置若未指定该参数Webpack 会直接报错退出。第一阶段 buildMain编译主脚本并复制资源pluginConfig配置的关键点入口为./src/index.ts输出到dist/index.js编译目标为target: node生产模式TypeScript 规则.ts/.tsx文件走ts-loader排除node_modules资源复制通过copy-webpack-plugin把src/下所有文件同步到dist/但忽略**/*.ts和**/*.tsx它们已被编译为 JS 并输出到 dist无需重复复制。对 content_script 模板而言这一步会把markdownItTestPlugin.css、markdownItTestPluginRuntime.js等纯资源文件原样拷入dist/同时把src/index.ts编译为dist/index.js。第二阶段 buildExtraScripts编译附加脚本框架支持将src/中的多个脚本分别编译为独立入口——这正是内容脚本content script能携带自身依赖的机制。需要编译哪些脚本由用户配置文件 plugin.config.json 声明{ extraScripts: [ markdownItTestPlugin.ts ] }resolveExtraScriptPath()会验证./src/脚本名存在并按文件名去掉扩展名的规则输出到dist/且输出采用libraryTarget: commonjs、libraryExport: default——这与 markdownItTestPlugin.ts 中export default function(context) {...}的写法精确对应Joplin 应用加载该 JS 时取到的正是这个默认导出的工厂函数。配置注释中还特别说明了设计意图不需要编译的 JS 文件在第一阶段被原样复制到 dist需要编译的则在此阶段被覆盖为编译产物两者兼得。该演示脚本本身返回{ plugin, assets }两个钩子plugin在 MarkdownIt 实例上覆写fence渲染规则当代码块语言为justtesting时输出自定义 HTML并携带joplin-editable/joplin-source类以支持富文本编辑器回写原始 Markdownassets声明随插件注入的markdownItTestPlugin.css与markdownItTestPluginRuntime.js而运行时的 markdownItTestPluginRuntime.js 通过webviewApi.postMessage()向插件主进程发消息——消息回传链路正是入口文件中joplin.contentScripts.onMessage(justtesting, ...)监听的部分。这套渲染钩子 页面运行时 postMessage 通信的完整闭环是理解 Joplin 内容脚本工作方式的最佳样例。第三阶段 createArchive生成 JPL 归档与发布信息createArchiveConfig以dist/index.js作为占位入口Webpack 无入口无法运行真正的打包工作由on-build-webpack插件在构建完成后执行onBuildCompleted()删除publish/index.js占位文件createPluginArchive()用tar把dist/下全部文件glob 遍历、去目录打包为publish/manifest.id.jpl参数portable: true保证归档可移植若 dist 为空则直接抛错createPluginInfo()生成publish/manifest.id.json即在 manifest 基础上追加两个字段_publish_hashsha256:JPL 归档的 SHA-256用于分发完整性校验_publish_commit当前 git 分支与提交号非 git 仓库时该字段为空并打印提示。同时readManifest()在构建启动前就会校验 manifestid缺失直接报错categories若存在则不允许重复且必须全部来自白名单[appearance, developer tools, productivity, themes, integrations, viewer, search, tags, editor, files, personal knowledge management]。validatePackageJson()还会给出三类发布相关警告包名未以joplin-plugin-开头、keywords缺少joplin-plugin、使用了postinstall脚本建议改用prepare以便在发布前执行构建——该模板的 package.json 正是以prepare: npm run dist体现这一建议。构建产物一览产物路径说明主入口dist/index.jssrc/index.ts编译结果附加脚本dist/脚本名.jsplugin.config.json中声明的 extraScripts 编译结果静态资源dist/内其他文件从src/原样复制CSS、图片、纯 JS 等可分发归档publish/id.jpldist 全部内容打包的 tar.gz 归档该模板目录中已提交了一份org.joplinapp.plugins.ContentScriptDemo.jpl发布信息publish/id.jsonmanifest SHA-256 哈希 git 提交信息更新插件框架yo joplin --update 及其保护策略README 的第二节专门讲框架更新要点值得逐条展开命令yo joplin --update模板 package.json 中对应的update脚本实际是npm install -g generator-joplin yo joplin --update即先确保全局安装了 Yeoman 生成器 generator-joplin 再执行更新该生成器的源码位于仓库的 packages/generator-joplin用户侧文档即插件根目录随模板携带的 GENERATOR_DOC.md。覆盖范围更新会覆盖src/目录之外的所有框架相关文件如package.json、.gitignore、webpack.config.js等但绝不触碰src/中的源码。因此修改过任何框架文件后务必把代码纳入版本控制以便 diff 检查并重新应用自己的改动。官方最佳实践——把自定义隔离到独立文件尽量不改框架文件如果确需修改例如改 Webpack 配置应新建一个独立的 JavaScript 文件然后在webpack.config.js中引入它。这样更新框架后只需要恢复引入该文件的那一行其余改动全部保留。这个建议与 webpack.config.js 文件头的注释完全一致不建议编辑此文件因为更新框架时它会被覆盖……若必须修改请考虑用外部 JS 文件 require 进来将改动降到最低框架更新机制与构建配置在同一处形成了闭环。小结模板给出的工程约定源码只放src/src/index.ts为入口、src/manifest.json描述元信息这是唯一不会被框架更新触碰的区域附加脚本内容脚本通过plugin.config.json的extraScripts声明以 CommonJS 默认导出形式交付给 Joplin 各应用模块按需加载一条npm run dist完成编译 → 附加脚本编译 → 打包 .jpl 发布信息产物publish/中的.jpl即可直接分发安装框架更新用yo joplin --update自定义改动通过外部 JS 文件隔离使重新应用成本最小化。以上约定均可以直接在 content_script 模板目录 内对照验证从入口注册逻辑、资源复制规则到归档哈希生成构建链条上的每一步都有对应的源码依据。【免费下载链接】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),仅供参考