开发入门
概述
Obsidian 支持通过插件和主题进行扩展开发。本章节将介绍开发环境的搭建和基础知识。
开发环境准备
必需工具
- Node.js:v16 或更高版本
- npm 或 pnpm:包管理器
- 代码编辑器:推荐 VS Code
- Git:版本控制
安装 Node.js
bash
# macOS/Linux (使用 nvm)
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
nvm install 18
nvm use 18
# Windows (使用 winget)
winget install OpenJS.NodeJS.LTS
# 验证安装
node --version
npm --version推荐的 VS Code 插件
| 插件名称 | 用途 |
|---|---|
| ESLint | 代码检查 |
| Prettier | 代码格式化 |
| TypeScript and JavaScript | 语言支持 |
| GitLens | Git 增强 |
创建插件项目
使用模板
推荐使用官方模板快速创建项目:
bash
# 克隆模板
git clone https://github.com/obsidianmd/obsidian-sample-plugin my-plugin
cd my-plugin
# 安装依赖
npm install
# 或使用 degit
npx degit obsidianmd/obsidian-sample-plugin my-plugin项目结构
text
my-plugin/
├── main.ts # 插件入口文件
├── manifest.json # 插件清单
├── styles.css # 插件样式(可选)
├── tsconfig.json # TypeScript 配置
├── esbuild.config.mjs # 构建配置
├── package.json # 项目配置
└── .github/ # GitHub Actions 配置manifest.json
json
{
"id": "my-plugin",
"name": "My Plugin",
"version": "1.0.0",
"minAppVersion": "1.0.0",
"description": "A sample Obsidian plugin",
"author": "Your Name",
"authorUrl": "https://github.com/yourusername",
"isDesktopOnly": false
}main.ts 基本结构
typescript
import { App, Plugin, PluginSettingTab, Setting } from 'obsidian';
// 定义设置接口
interface MyPluginSettings {
mySetting: string;
}
// 默认设置
const DEFAULT_SETTINGS: MyPluginSettings = {
mySetting: 'default value'
};
// 插件主类
export default class MyPlugin extends Plugin {
settings: MyPluginSettings;
async onload() {
await this.loadSettings();
// 注册命令
this.addCommand({
id: 'hello-command',
name: 'Say Hello',
callback: () => {
console.log('Hello from my plugin!');
}
});
// 添加设置面板
this.addSettingTab(new MySettingTab(this.app, this));
}
onunload() {
console.log('Plugin unloaded');
}
async loadSettings() {
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
}
async saveSettings() {
await this.saveData(this.settings);
}
}
// 设置面板
class MySettingTab extends PluginSettingTab {
plugin: MyPlugin;
constructor(app: App, plugin: MyPlugin) {
super(app, plugin);
this.plugin = plugin;
}
display(): void {
const { containerEl } = this;
containerEl.empty();
new Setting(containerEl)
.setName('Setting name')
.setDesc('Setting description')
.addText(text => text
.setValue(this.plugin.settings.mySetting)
.onChange(async (value) => {
this.plugin.settings.mySetting = value;
await this.plugin.saveSettings();
}));
}
}开发流程
本地开发
编译插件
bashnpm run dev链接到 Obsidian
bash# macOS/Linux ln -s /path/to/my-plugin /path/to/vault/.obsidian/plugins/my-plugin # Windows (PowerShell) New-Item -ItemType SymbolicLink -Path "C:\path\to\vault\.obsidian\plugins\my-plugin" -Target "C:\path\to\my-plugin"在 Obsidian 中启用插件
- 打开设置 → 第三方插件
- 刷新插件列表
- 找到并启用你的插件
热重载
修改代码后,需要重新加载插件:
- 方法一:禁用再启用插件
- 方法二:使用「Hot Reload」插件自动重载
- 方法三:
Ctrl/Cmd + R重新加载 Obsidian
调试
打开开发者工具:
- macOS:
Cmd + Option + I - Windows/Linux:
Ctrl + Shift + I
typescript
// 使用 console.log 调试
console.log('Debug info', someVariable);
// 使用 console.error 记录错误
console.error('Something went wrong', error);发布插件
准备发布
- 更新
manifest.json中的版本号 - 构建生产版本bash
npm run build - 确保包含必要文件
main.jsmanifest.jsonstyles.css(如有)
发布到社区
- 在 GitHub 创建仓库
- 推送代码
- 创建 Release,上传构建文件
- Fork
obsidian-releases仓库 - 编辑
community-plugins.json,添加你的插件信息 - 提交 Pull Request
GitHub Release 配置
可以使用 GitHub Actions 自动构建:
yaml
# .github/workflows/release.yml
name: Release
on:
push:
tags:
- '*'
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 18
- run: npm ci
- run: npm run build
- uses: softprops/action-gh-release@v1
with:
files: |
main.js
manifest.json
styles.cssTypeScript 配置
json
// tsconfig.json
{
"compilerOptions": {
"baseUrl": ".",
"inlineSourceMap": true,
"inlineSources": true,
"module": "ESNext",
"target": "ES6",
"allowJs": true,
"noImplicitAny": true,
"moduleResolution": "node",
"importHelpers": true,
"isolatedModules": true,
"strictNullChecks": true,
"lib": ["DOM", "ES5", "ES6", "ES7"]
},
"include": ["**/*.ts"]
}下一步
Obsidian API 核心 API 速览
理解 Obsidian 插件开发的关键 API,帮助你快速上手。
常用 API 分类
| 分类 | 核心类/方法 | 用途 |
|---|---|---|
| 插件生命周期 | onload() / onunload() | 插件加载和卸载时执行 |
| 命令注册 | this.addCommand() | 注册命令面板命令 |
| 事件监听 | this.registerEvent() | 监听 Vault 事件 |
| 设置管理 | this.loadData() / this.saveData() | 读写插件配置 |
| 视图 | this.addView() | 注册自定义视图 |
| Ribbon | this.addRibbonIcon() | 添加侧边栏图标 |
| 状态栏 | this.addStatusBarItem() | 添加状态栏元素 |
文件操作 API
typescript
// 读取文件
const content = await this.app.vault.read(file);
// 写入文件
await this.app.vault.modify(file, newContent);
// 创建文件
const newFile = await this.app.vault.create(path, content);
// 删除文件
await this.app.vault.delete(file);
// 获取文件
const file = this.app.vault.getAbstractFileByPath('path/to/note.md');
// 列出文件夹中的文件
const files = this.app.vault.getFiles();
const markdownFiles = this.app.vault.getMarkdownFiles();编辑器操作 API
typescript
// 获取当前活动编辑器
const activeFile = this.app.workspace.getActiveFile();
const editor = this.app.workspace.activeEditor?.editor;
// 读取选中内容
const selection = editor?.getSelection();
// 替换选中内容
editor?.replaceSelection('替换文本');
// 在光标位置插入内容
editor?.replaceRange('插入内容', editor.getCursor());
// 获取当前行内容
const line = editor?.getLine(editor.getCursor().line);事件系统
typescript
// 监听文件创建
this.registerEvent(
this.app.vault.on('create', (file) => {
console.log('文件创建:', file.path);
})
);
// 监听文件修改
this.registerEvent(
this.app.vault.on('modify', (file) => {
console.log('文件修改:', file.path);
})
);
// 监听活动文件变化
this.registerEvent(
this.app.workspace.on('active-leaf-change', (leaf) => {
console.log('活动视图变化');
})
);
// 监听布局变化
this.registerEvent(
this.app.workspace.on('layout-change', () => {
console.log('布局变化');
})
);模态框(Modal)
typescript
// 自定义模态框
class MyModal extends Modal {
constructor(app: App) {
super(app);
}
onOpen() {
const { contentEl } = this;
contentEl.createEl('h2', { text: '我的模态框' });
new Setting(contentEl)
.setName('输入')
.addText(text => text.onChange(value => {
// 处理输入
}));
new ButtonComponent(contentEl)
.setButtonText('确定')
.onClick(() => {
this.close();
});
}
onClose() {
const { contentEl } = this;
contentEl.empty();
}
}
// 使用
new MyModal(this.app).open();通知(Notice)
typescript
// 简单通知
new Notice('操作成功!');
// 带超时的通知(5秒)
new Notice('处理中,请稍候...', 5000);
// 错误通知
new Notice('❌ 操作失败,请重试');常见开发模式
模式一:命令型插件
注册命令,用户通过命令面板触发:
typescript
this.addCommand({
id: 'format-note',
name: '格式化当前笔记',
editorCallback: (editor, view) => {
const content = editor.getValue();
const formatted = formatMarkdown(content);
editor.setValue(formatted);
}
});模式二:视图型插件
创建自定义视图,显示特殊内容:
typescript
// 注册视图
this.registerView('my-view', (leaf) => new MyView(leaf));
// 添加命令打开视图
this.addCommand({
id: 'open-my-view',
name: '打开自定义视图',
callback: () => {
this.app.workspace.detachLeavesOfType('my-view');
const leaf = this.app.workspace.getRightLeaf(false);
leaf?.setViewState({ type: 'my-view' });
this.app.workspace.revealLeaf(leaf!);
}
});模式三:自动处理型插件
监听事件,自动执行操作:
typescript
// 自动为新笔记添加 frontmatter
this.registerEvent(
this.app.vault.on('create', async (file) => {
if (!(file instanceof TFile) || file.extension !== 'md') return;
const content = await this.app.vault.read(file);
if (content.startsWith('---')) return; // 已有 frontmatter
const frontmatter = `---
created: ${new Date().toISOString()}
tags: []
---
`;
await this.app.vault.modify(file, frontmatter + content);
})
);开发工具与技巧
推荐开发工具
| 工具 | 用途 | 安装方式 |
|---|---|---|
| Hot Reload | 修改代码后自动重载插件 | 社区插件 |
| Obsidian API Types | TypeScript 类型提示 | npm install obsidian |
| esbuild | 快速打包 | 已在模板中配置 |
调试技巧
typescript
// 1. 使用 console 输出
console.log('变量值:', variable);
console.table(arrayData); // 表格形式输出数组
// 2. 使用 Notice 快速反馈
new Notice(`结果: ${result}`);
// 3. 使用 debugger 断点
debugger; // 代码执行到这里会暂停
// 4. 监控性能
console.time('操作耗时');
// ... 执行代码
console.timeEnd('操作耗时');开发常见错误
| 错误 | 原因 | 解决方案 |
|---|---|---|
Cannot read property of undefined | API 对象未正确获取 | 添加空值检查 |
| 插件加载后无效果 | onload() 中未注册功能 | 检查 onload() 实现 |
| 修改代码后无变化 | 未重载插件 | 使用 Hot Reload 或 Ctrl+R |
| 类型错误 | API 类型定义未安装 | npm install obsidian |
| 样式不生效 | CSS 文件未正确引入 | 检查 styles.css 位置 |
进阶开发指引
掌握了基础知识后,可以深入学习以下方向:
插件发布流程
- 代码质量:确保代码清晰、有注释
- README 编写:说明插件功能和使用方法
- 版本管理:遵循语义化版本号
- 提交审核:Fork
obsidian-releases仓库提交 PR