目 录CONTENT

文章目录

1.4.4.[Obsidian][插件][发布]插件指南

克林空间
2024-01-30 / 0 评论 / 0 点赞 / 41 阅读 / 0 字 / 正在检测是否收录...
温馨提示:
本文最后更新于2024-01-30,若内容或图片失效,请留言反馈。 部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

本页列出了插件作者在提交插件时收到的常见评审意见。

虽然此页面上的指南是建议,但根据其严重程度,我们可能仍会要求您解决违规问题。

插件开发者政策

Make sure that you've read our Developer policies as well as the Submission requirements for plugins.
请务必阅读我们的[[开发者政策]]以及[[插件的提交要求]]。

常规

避免使用全局应用实例

避免使用全局应用对象 app (或 window.app )。请改用插件实例提供的引用  this.app

全局应用对象用于调试目的,将来可能会被删除。

UI 文本

本部分列出了在用户界面中设置文本格式的准则,例如设置、命令和按钮。

下面的“设置”→“外观”中的示例演示了用户界面中文本的准则。

dqrdq

  1. 常规设置位于顶部,没有标题
  2. 章节标题的标题文本中没有“设置”
  3. 在 UI 中使用句子大小写

有关Obsidian编写和格式化文本的更多信息,请参阅我们的样式指南

仅当有多个部分时,才使用设置下的标题。

避免在设置选项卡中添加顶级标题,例如“常规”、“设置”或插件名称。

如果设置下有多个部分,并且其中一个包含常规设置,请将它们保留在顶部,而不添加标题。

例如,查看“设置”→“外观”下的设置。

避免在设置标题中使用“设置”

在设置选项卡中,您可以添加标题来组织设置。避免在这些标题中包含“设置”一词。由于设置选项卡下的所有内容都是设置,因此对每个标题重复它变得多余。

  • 首选“高级”而不是“高级设置”。
  • 首选“模板”而不是“模板设置”。

在UI中使用句子大小写

UI 元素中的任何文本都应使用句子大小写而不是标题大小写,其中只有句子中的第一个单词和专有名词应大写。

  • 首选 "Template folder location" 而不是 "Template Folder Location"。
  • 首选 "Create new note" 而不是 "Create New Note"。

安全

避免 innerHTML 和 outerHTML insertAdjacentHTML

从用户定义的输入构建 DOM 元素,使用 innerHTML 和 outerHTML insertAdjacentHTML 可能会带来安全风险。

下面的示例使用包含用户输入的字符串生成 DOM 元素 ${name} 。 name 可以包含其他 DOM 元素,例如 <script>alert()</script> ,并可允许潜在攻击者在用户计算机上执行任意代码。

function showName(name: string) {
  let containerElement = document.querySelector('.my-container');
  // DON'T DO THIS
  containerElement.innerHTML = `<div class="my-class"><b>Your name is: </b>${name}</div>`;
}

请改用 DOM API 或Obsidian帮助程序函数(如 createEl() ) createDiv() createSpan() 以编程方式生成 DOM 元素。有关更多信息,请参阅 [[HTML 元素]]。

资源管理

插件卸载时清理资源

插件创建的任何资源(例如事件侦听器)都必须在插件卸载时销毁或释放。

如果可能,请使用 registerEvent() 或 addCommand() 等方法在插件卸载时自动清理资源。

export default class MyPlugin extends Plugin {
  onload() {
    this.registerEvent(this.app.vault.on("create", this.onCreate));
  }

  onCreate: (file: TAbstractFile) => {
    // ...
  }
}

[!NOTE]

您无需清理在插件卸载时删除的资源。例如,如果在 DOM 元素上注册 mouseenter 侦听器,当该元素超出范围时,将对事件侦听器进行垃圾回收。

不要在onunload分离 leaves

当用户更新您的插件时,任何打开的叶子都将在其原始位置重新初始化,无论用户将它们移动到何处。

命令

避免为命令设置默认热键

设置默认热键可能会导致插件之间发生冲突,并可能覆盖用户已配置的热键。

选择所有操作系统上都可用的默认热键很困难。

对命令使用适当的回调类型

在插件中添加命令时,请使用适当的回调类型。

  • 如果命令无条件运行,则使用 callback 。
  • 如果命令仅在特定条件下运行,则使用 checkCallback 。

如果该命令需要打开且处于活动状态的 Markdown 编辑器,请使用 editorCallback 或相应的 editorCheckCallback .

工作区

避免直接访问 workspace.activeLeaf

如果要访问活动视图,请改用 getActiveViewOfType() :

const view = this.app.workspace.getActiveViewOfType(MarkdownView);

// getActiveViewOfType will return null if the active view is null, or if it's not a MarkdownView.
if (view) {
  // ...
}

如果要访问活动笔记中的编辑器,请改用 activeEditor :

const editor = this.app.workspace.activeEditor;

避免管理对自定义视图的引用

管理对自定义视图的引用可能会导致内存泄漏或意外后果。

不要:

this.registerViewType(MY_VIEW_TYPE, () => this.view = new MyCustomView());

请改为执行此操作:

this.registerViewType(MY_VIEW_TYPE, () => new MyCustomView());

要从插件访问视图,请使用 Workspace.getActiveLeavesOfType() :

for (let leaf of app.workspace.getActiveLeavesOfType(MY_VIEW_TYPE)) {
  let view = leaf.view;
  if (view instanceof MyCustomView) {
    // ...
  }
}

首选编辑器 API,而不是 Vault.modify

如果要编辑活动注释,请使用 Editor 接口,而不是 Vault.modify()

编辑器会维护有关活动笔记的信息,例如光标位置、选择和折叠内容。当您使用 Vault.modify() 编辑注释时,所有这些信息都会丢失,这会导致用户体验不佳。

在对笔记的某些部分进行小的更改时,编辑器也更有效率。

仅当您在后台编辑文件时,才使用 Vault.modify()。

首选 Vault API 而不是适配器 API

Obsidian公开了两个用于文件操作的 API:Vault API ( app.vault ) 和适配器 API ( app.vault.adapter )。

虽然许多开发人员通常更熟悉适配器 API 中的文件操作,但与适配器相比,Vault API 有两个主要优势。

  • 性能:Vault API 具有一个缓存层,当Obsidian文件已知时,该缓存层可以加快文件读取速度。
  • 安全性:Vault API 按顺序执行文件操作,以避免出现任何争用条件,例如在读取同时写入的文件时。

避免遍历所有文件,建议按路径查找文件

遍历文件是低效的,特别是对于大型库。请改用 getAbstractFileByPath() 。

不建议:

vault.getAllFiles().find(file => file.path === filePath)

请改为执行此操作:

const filePath = 'folder/file.md';

const file = app.vault.getAbstractFileByPath(filePath);

// Check if it exists and is of the correct type
if (file instanceof TFile) {
  // file is automatically casted to TFile within this scope.
}

使用 normalizePath() 清理用户定义的路径

每当您访问库中文件或文件夹的用户定义路径时,或者当您在插件代码中构造自己的路径时,请使用  normalizePath() 。

通过normalizePath() 获取路径并清理它,以确保文件系统和跨平台使用的安全。此功能:

  • 清理正斜杠和反斜杠的使用,例如将 1 个或多个 \ 或 / 替换为单个 / 。
  • 删除前导和后导斜杠。
  • 将任何不间断空格 替换为 \u00A0 常规空格。
  • 通过 String.prototype.normalize 执行路径。
import { normalizePath } from "obsidian";
const pathToPlugin = normalizePath(app.vault.configDir + "//plugins/my-plugin");
// pathToPlugin contains ".obsidian/plugins/my-plugin" not .obsidian//plugins/my-plugin

编辑器

更改或重新配置编辑器扩展

如果要在使用 registerEditorExtension(), 注册后更改或重新配置[[编辑器扩展]],请使用 updateOptions() 更新所有编辑器。

class MyPlugin extends Plugin {
  private editorExtension: Extension[] = [];

  onload() {
    //...

    this.registerEditorExtension(this.editorExtension);
  }

  updateEditorExtension() {
    // Empty the array while keeping the same reference
    // (Don't create a new array here)
    this.editorExtension.length = 0;

    // Create new editor extension
    let myNewExtension = this.createEditorExtension();
    // Add it to the array
    this.editorExtension.push(myNewExtension);

    // Flush the changes to all editors
    this.app.workspace.updateOptions();
  }
}

TypeScript

使用 const 和 let 优于 var

有关更多信息,请参阅在现代 JavaScript 中 var 被认为过时的 4 个原因

首选 async/await 而不是 Promise

最新版本的 JavaScript 和 TypeScript 支持 async and await 关键字异步运行代码,这使代码比用 Promise 更具可读性。

不建议:

function test(): Promise<string | null> {
  return requestUrl('https://example.com')
    .then(res => res.text
    .catch(e => {
      console.log(e);
      return null;
    });
}

请改为执行此操作:

async function AsyncTest(): Promise<string | null> {
  try {
    let res = await requestUrl('https://example.com');
    let text = await r.text;
    return text;
  }
  catch (e) {
    console.log(e);
    return null;
  }
}

考虑使用文件夹组织代码库

如果您的插件使用多个 .ts 文件,请考虑将它们组织到文件夹中,以便于查看和维护。

重命名占位符类名

示例插件包含常见类的占位符名称,例如 MyPlugin 、 MyPluginSettings 和 SampleSettingTab 。重命名这些名称以反映插件的名称。

0

评论区