Based on siyuan/plugin-sample v0.5.0, with selected updates from newer releases.
- Using vite for packaging
- Use symbolic linking instead of putting the project into the plugins directory program development
- Provides a github action template to automatically generate package.zip and upload to new release
-
Use the Use this template button to make a copy of this repo as a template. Note that the repository name should match the plugin name, and the default branch must be
main. -
Clone your repository to the local development folder.
- Note: Unlike
plugin-sample, this example does not recommend directly downloading the code to{workspace}/data/plugins/.
- Note: Unlike
-
Install Node.js 24 or later and pnpm 11.4, then run
pnpm iin the development folder to install the required dependencies. -
Run the
pnpm run make-linkcommand to create a symbolic link (Windows developers, please refer to the "make-link on Windows" section below). -
Execute
pnpm run devfor real-time compilation. In development mode, LiveReload opens a local WebSocket port, and the client embedded in the plugin bundle connects to it from inside SiYuan. Keep this port stable and associated with the current plugin, especially when developing multiple plugins at the same time.If
portis omitted, LiveReload derives a stable default port from the plugin name. If that port is already in use or conflicts with another plugin, set a dedicated development port manually and keep using the same value invite.config.ts. The default debounce is 5 seconds, and the default delay between disabling and re-enabling the plugin is 500 ms. To override these settings, pass options touseLiveReloadinvite.config.ts:useLiveReload({ outputDir, port: 31416, debounceMs: 300, reloadGapMs: 500, message: "Reloading my plugin" })
LiveReload also verifies the plugin identity before reloading to prevent one plugin from responding to another plugin's server.
-
Open the marketplace in SiYuan and enable the plugin in the download tab.
The make-link command creates a symbolic link that binds your dev directory to the SiYuan plugin directory. You can configure the target SiYuan workspace and create the symbolic link in three ways:
-
Select Workspace
- Open SiYuan, ensure the SiYuan kernel is running.
- Run
pnpm run make-link, the script will automatically detect all SiYuan workspaces, please manually enter the number to select the workspace.>>> pnpm run make-link > plugin-sample-vite@0.0.3 make-link H:\SrcCode\开源项目\plugin-sample-vite > node --no-warnings ./scripts/make_dev_link.js "targetDir" is empty, try to get SiYuan directory automatically.... Got 2 SiYuan workspaces [0] H:\Media\SiYuan [1] H:\临时文件夹\SiYuanDevSpace Please select a workspace[0-1]: 0 Got target directory: H:\Media\SiYuan/data/plugins Done! Created symlink H:\Media\SiYuan/data/plugins/plugin-sample-vite
-
Manually Configure Target Directory
- Open the
./scripts/make_dev_link.jsfile, changetargetDirto the SiYuan plugin directory<siyuan workspace>/data/plugins. - Run the
pnpm run make-linkcommand. If you see a message similar to the one below, it indicates successful creation:
- Open the
-
Set Environment Variable to Create Symbolic Link
- Set the system environment variable
SIYUAN_PLUGIN_DIRto the pathworkspace/data/plugins.
- Set the system environment variable
Due to SiYuan upgrading to Go 1.23, the old version of junction links cannot be recognized normally on Windows, so it has been changed to create dir symbolic links.
However, creating directory symbolic links on Windows using NodeJs may require administrator privileges. You have the following options:
- Run
pnpm run make-linkin a command line with administrator privileges. - Configure Windows settings, enable developer mode in [System Settings - Update & Security - Developer Mode] then run
pnpm run make-link. - Run
pnpm run make-link-win, this command will use a PowerShell script to request administrator privileges, requiring the system to enable PowerShell script execution permissions.
In terms of internationalization, our main consideration is to support multiple languages. Specifically, we need to complete the following tasks:
- Meta information about the plugin itself, such as plugin display name, description and readme
displayName,descriptionandreadmefields in plugin.json, and the corresponding README*.md file
- Text used in the plugin, such as button text and tooltips
- public/i18n/*.json language configuration files
- Use
this.i18n.keyto get the text in the code
- YAML Support
- This template specifically supports I18n based on YAML syntax, see
public/i18n/zh-CN.yaml - During compilation, the defined YAML files will be automatically translated into JSON files and placed in the dist or dev directory.
- This template specifically supports I18n based on YAML syntax, see
It is recommended that the plugin supports at least English and Simplified Chinese, so that more people can use it more
conveniently. Unsupported languages do not need to be declared in the displayName, description and readme fields in plugin.json.
{
"name": "plugin-sample-vite",
"author": "frostime",
"url": "https://github.com/frostime/plugin-sample-vite",
"version": "0.5.0",
"minAppVersion": "3.8.0",
"disabledInPublish": true,
"backends": ["windows", "linux", "darwin"],
"frontends": ["desktop"],
"displayName": {
"default": "Plugin sample with vite",
"zh-CN": "插件样例 vite 版"
},
"description": {
"default": "SiYuan plugin sample with vite",
"zh-CN": "使用 vite 开发的思源插件样例"
},
"readme": {
"default": "README.md",
"zh-CN": "README.zh-CN.md"
},
"icon": "icon.png",
"preview": "preview.png",
"funding": {
"openCollective": "",
"patreon": "",
"github": "",
"custom": [
"https://ld246.com/sponsor"
]
},
"keywords": [
"plugin", "sample", "插件样例"
]
}name: Plugin name, must be the same as the repo name, and must be unique globally (no duplicate plugin names in the marketplace)author: Plugin author nameurl: Plugin repo URLversion: Plugin version number, it is recommended to follow the semver specificationminAppVersion: Minimum version number of SiYuan required to use this plugindisabledInPublish: Set totruewhen this template should not be published to the marketplacebackends: Backend environment required by the plugin, optional values arewindows,linux,darwin,docker,android,ios,harmonyandallwindows: Windows desktoplinux: Linux desktopdarwin: macOS desktopdocker: Dockerandroid: Android APPios: iOS APPharmony: HarmonyOS APPall: All environments
frontends: Frontend environment required by the plugin, optional values aredesktop,desktop-window,mobile,browser-desktop,browser-mobileandalldesktop: Desktopdesktop-window: Desktop window converted from tabmobile: Mobile APPbrowser-desktop: Desktop browserbrowser-mobile: Mobile browserall: All environments
- When
allappears inbackendsorfrontends, it must not be mixed with concrete platform values: write["all"]alone, or an explicit platform list. The marketplace automated check rejects mixed lists (the official sample template repos are exempted for demonstration purposes). displayName: Plugin name (plain text), displayed in the marketplace list, supports multiple languagesdefault: Default language, must existzh-CN,enand other languages: optional, must be BCP 47 tags (e.g.zh-CN,zh-TW,en,ja,pt-BR)
description: Plugin description (plain text), displayed in the marketplace list, supports multiple languagesdefault: Default language, must existzh-CN,enand other languages: optional, must be BCP 47 tags
readme: readme file name, mainly used to display in the marketplace details page, supports multiple languagesdefault: Default language, must existzh-CN,enand other languages: optional, must be BCP 47 tags- Relative images are loaded from
package.zipwhen present; otherwise the online marketplace falls back to the matching GitHub Release. Include them inpackage.zipfor offline use
icon: Optional marketplace icon filename at the package root. Supports PNG, JPEG, WebP, and AVIF up to 64 KiB; the recommended size is 160*160preview: Optional marketplace preview filename at the package root. Supports PNG, JPEG, WebP, and AVIF up to 512 KiB; the recommended size is 1024*768- SVG is unsupported. To omit an image, remove its field and the legacy
icon.pngorpreview.png; an empty field value is invalid
- SVG is unsupported. To omit an image, remove its field and the legacy
funding: Plugin sponsorship informationopenCollective: Open Collective namepatreon: Patreon namegithub: GitHub login namecustom: Custom sponsorship link listlinks: Labeled custom sponsorship links, for example{"label": "Sponsor", "url": "https://example.com"}
keywords: Search keyword list, used for marketplace search function
No matter which method is used to compile and package, we finally need to generate a package.zip, which contains at least the following files:
- i18n/*
- Image files declared by
iconandpreview(optional) - index.css
- index.js
- plugin.json
- README*.md
- asset/* (README images required offline)
pnpm run buildto generate package.zip- Create a new GitHub release using your new version number as the "Tag version". See here for an example: https://github.com/siyuan-note/plugin-sample/releases
- Upload the file package.zip as binary attachments
- Publish the release
For the first release, fork the Community Bazaar, add one owner/repo line to plugins.txt in its root, and open a PR against main. Use one repository per line without commas or empty lines, and add only one new package per PR. See Submitting a bazaar package for the full process and review rules.
After the PR is merged, the bazaar updates its index automatically. For subsequent updates, increase version in the package manifest and publish a regular GitHub Release containing package.zip; no additional listing PR is needed. See Updating a bazaar package for update timing and troubleshooting, and check deployment status in the Stage workflow.
The included workflow checks, packages, and publishes a GitHub release automatically:
-
In
Settings>Actions>General, select Read and write permissions under Workflow permissions. -
Update the versions in
package.jsonandplugin.json, then push a matching tag:git tag v0.5.0 git push origin v0.5.0
The workflow verifies that the tag version matches both JSON files before checking, building, or publishing.
-
The workflow creates a regular release by default. Set
prerelease: truein.github/workflows/release.ymlwhen needed.
Most functions in src/api.ts return an ApiResponse object instead of returning the kernel data directly:
const response = await sql("select * from blocks");
if (response.ok) {
console.log(response.data);
}Use response.ok before reading response.data; response.raw contains the original kernel response.
Developers of SiYuan need to pay attention to the following specifications.
If plugins or external extensions require direct reading or writing of files under the data directory, please use the kernel API to achieve this. Do not call fs or other electron or nodejs APIs directly, as it may result in data loss during synchronization and cause damage to cloud data.
Related APIs can be found at: /api/file/* (e.g., /api/file/getFile).
When creating a daily note in SiYuan, a custom-dailynote-yyyymmdd attribute will be automatically added to the document to distinguish it from regular documents.
For more details, please refer to Github Issue #9807.
Developers should pay attention to the following when developing the functionality to manually create Daily Notes:
- If
/api/filetree/createDailyNoteis called to create a daily note, the attribute will be automatically added to the document, and developers do not need to handle it separately - If a document is created manually by developer's code (e.g., using the
createDocWithMdAPI to create a daily note), please manually add this attribute to the document
