开发步骤
- 从 obsidian-sample-plugin克隆一个仓库
- 修改其中的 manifest.json 文件,其中 plugin id 是最重要的。
- 修改主文件 main.ts,使用
npm install
安装依赖库 - 使用命令
npm run dev
编译出 main.js - 在 Obsidian 的 vault 目录 .obsidian/plugins/ 创建一个插件名称的文件夹,拷贝 manifest.json 和 main.js 到该目录,有的插件可能还有 style.css 等文件。
- 在 settings 页面加载插件
在开发过程中,可以通过 Ctrl-Shift-i
来打开调试页面。
开发插件
hot-reload: 热重载
首先,需要在插件目录中添加 .hotreload
文件,然后,下载插件并开启。
注意❗
- 如果没有
hot-reload
,需要重新打开插件,代码才能生效。- 插件id为输出文件夹的名称。
- obsidian-plugin-cli: 将开发生产的代码拷贝到插件目录,可以不再插件目录下开发。
- obsidian42-bratpub: Obsidian Beta 测试。
- obsidian-textfileview-plugin-sample: Obsidian TextFileView plugin
- obsidian-note-publish
常用命令
如何开启开发者模式 /控制台
- Win:
Ctrl + Shitf + i
. - Mac:
cmd+ option + i
.
发布插件
使用 GitHub Actions 发布您的插件
name: Release Obsidian plugin
on:
push:
tags:
- "*"
env:
PLUGIN_NAME: your-plugin-id # Change this to match the id of your plugin.
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Use Node.js
uses: actions/setup-node@v1
with:
node-version: "14.x"
- name: Build
id: build
run: |
npm install
npm run build
mkdir ${{ env.PLUGIN_NAME }}
cp main.js manifest.json styles.css ${{ env.PLUGIN_NAME }}
zip -r ${{ env.PLUGIN_NAME }}.zip ${{ env.PLUGIN_NAME }}
ls
echo "::set-output name=tag_name::$(git tag --sort version:refname | tail -n 1)"
- name: Create Release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
VERSION: ${{ github.ref }}
with:
tag_name: ${{ github.ref }}
release_name: ${{ github.ref }}
draft: false
prerelease: false
- name: Upload zip file
id: upload-zip
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./${{ env.PLUGIN_NAME }}.zip
asset_name: ${{ env.PLUGIN_NAME }}-${{ steps.build.outputs.tag_name }}.zip
asset_content_type: application/zip
- name: Upload main.js
id: upload-main
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./main.js
asset_name: main.js
asset_content_type: text/javascript
- name: Upload manifest.json
id: upload-manifest
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./manifest.json
asset_name: manifest.json
asset_content_type: application/json
- name: Upload styles.css
id: upload-css
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./styles.css
asset_name: styles.css
asset_content_type: text/css
提交插件
将插件添加到配置文件中,提交pull request 进行审核。
{
"id": "recent-files-obsidian",
"name": "Recent Files",
"author": "Tony Grosinger",
"description": "Display a list of recently opened files",
"repo": "tgrosinger/recent-files-obsidian",
"branch": "main"
}
UI 界面
Views (创建视图)
import { ItemView, WorkspaceLeaf } from 'obsidian';
export const VIEW_TYPE_EXAMPLE = 'example-view';
export class ExampleView extends ItemView {
constructor(leaf: WorkspaceLeaf) {
super(leaf);
}
getViewType() {
return VIEW_TYPE_EXAMPLE;
}
getDisplayText() {
return 'Example view';
}
async onOpen() {
const container = this.containerEl.children[1];
container.empty();
container.createEl('h4', { text: 'Example view' });
}
async onClose() {
// Nothing to clean up.
}
}
DOM API (创建元素)
- createEl()
- createDiv()
- createSpan()
const book = containerEl.createEl('div', { cls: 'book' });
book.createEl('div', { text: 'How to Take Smart Notes', cls: 'book__title' });
book.createEl('small', { text: 'Sönke Ahrens', cls: 'book__author' });
.book {
border: 1px solid var(--background-modifier-border);
padding: 10px;
}
.book__title {
font-weight: 600;
}
.book__author {
color: var(--text-muted);
}
根据条件设置样式:
element.toggleClass('danger', status === 'error');
下面是系统中的CSS 变量:
使用 React 组件
安装React并配置
- Add React to your plugin dependencies:
npm install react react-dom
- Add type definitions for React:
npm install --save-dev @types/react @types/react-dom
- In
tsconfig.json
, enable JSX support on thecompilerOptions
object:
{
"compilerOptions": {
"jsx": "react-jsx"
}
}
```
### 创建组件
创建一个叫 `ReactView.tsx` 的组件:
```tsx
export const ReactView = () => {
return <h4>Hello, React!</h4>;
};
使用React组件
下面将 ReactView
组件挂载到 this.containerEl.children[1]
元素上:
import { StrictMode } from 'react';
import { ItemView, WorkspaceLeaf } from 'obsidian';
import { Root, createRoot } from 'react-dom/client';
import { ReactView } from './ReactView';
const VIEW_TYPE_EXAMPLE = 'example-view';
class ExampleView extends ItemView {
root: Root | null = null;
constructor(leaf: WorkspaceLeaf) {
super(leaf);
}
getViewType() {
return VIEW_TYPE_EXAMPLE;
}
getDisplayText() {
return 'Example view';
}
async onOpen() {
this.root = createRoot(this.containerEl.children[1]);
this.root.render(
<StrictMode>
<ReactView />,
</StrictMode>,
);
}
async onClose() {
this.root?.unmount();
}
}
创建全局状态
- Use
createContext()
to create a new app context.
import { createContext } from 'react';
import { App } from 'obsidian';
export const AppContext = createContext<App | undefined>(undefined);
- Wrap the
ReactView
with a context provider and pass the app as the value.
this.root = createRoot(this.containerEl.children[1]);
this.root.render(
<AppContext.Provider value={this.app}>
<ReactView />
</AppContext.Provider>
);
- Create a custom hook to make it easier to use the context in your components.
import { useContext } from 'react';
import { AppContext } from './context';
export const useApp = (): App | undefined => {
return useContext(AppContext);
};
- Use the hook in any React component within
ReactView
to access the app.
import { useApp } from './hooks';
export const ReactView = () => {
const { vault } = useApp();
return <h4>{vault.getName()}</h4>;
};