Improve onDataChanged method (#16472)

* 🐛 Improve onDataChanged method

fix https://github.com/siyuan-note/siyuan/pull/16244

重构、修复插件重启逻辑

重构

比如插件在 onload() 中插入了图标,uninstall 会把图标删除,afterLoadPlugin 又不能执行 onload() 把图标加回来

使用 getElementById

先加载插件样式

避免插入重复的样式

改进插件样式插入位置

* reloadPlugin
This commit is contained in:
Jeffrey Chen 2025-12-02 09:57:50 +08:00 committed by GitHub
parent d620daa530
commit bcdef64d0f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 60 additions and 37 deletions

View file

@ -16,8 +16,7 @@ import {BlockPanel} from "../block/Panel";
import {Setting} from "./Setting"; import {Setting} from "./Setting";
import {clearOBG} from "../layout/dock/util"; import {clearOBG} from "../layout/dock/util";
import {Constants} from "../constants"; import {Constants} from "../constants";
import {uninstall} from "./uninstall"; import {restartPlugin} from "./loader";
import {afterLoadPlugin} from "./loader";
export class Plugin { export class Plugin {
private app: App; private app: App;
@ -103,7 +102,7 @@ export class Plugin {
}); });
} }
public onload() { public onload(): Promise<void> | void {
// 加载 // 加载
} }
@ -118,8 +117,7 @@ export class Plugin {
public onDataChanged() { public onDataChanged() {
// 存储数据变更 // 存储数据变更
// 兼容 3.4.1 以前同步数据使用重载插件的问题 // 兼容 3.4.1 以前同步数据使用重载插件的问题
uninstall(this.app, this.name, false); restartPlugin(this.app, this);
afterLoadPlugin(this);
} }
public async updateCards(options: ICardData) { public async updateCards(options: ICardData) {

View file

@ -29,22 +29,15 @@ const runCode = (code: string, sourceURL: string) => {
export const loadPlugins = async (app: App, names?: string[]) => { export const loadPlugins = async (app: App, names?: string[]) => {
const response = await fetchSyncPost("/api/petal/loadPetals", {frontend: getFrontend()}); const response = await fetchSyncPost("/api/petal/loadPetals", {frontend: getFrontend()});
let css = '<style id="pluginsStyle"></style>'; // 用于将内联样式插入到插件样式前的标识 const pluginsStyle = getPluginsStyle();
// 为加快启动速度,不进行 await const pluginsToLoad = !names
response.data.forEach((item: IPluginData) => { ? response.data
if (!names || (names && names.includes(item.name))) { : response.data.filter((item: IPluginData) => names.includes(item.name));
loadPluginJS(app, item); pluginsToLoad.forEach((item: IPluginData) => {
} // 为加快启动速度,不进行 await
if (item.css) { loadPluginJS(app, item);
css += `<style id="pluginsStyle${item.name}">${item.css}</style>`; insertPluginCSS(item, pluginsStyle);
}
}); });
const pluginsStyle = document.getElementById("pluginsStyle");
if (pluginsStyle) {
pluginsStyle.insertAdjacentHTML("afterend", css);
} else {
document.head.insertAdjacentHTML("beforeend", css);
}
}; };
const loadPluginJS = async (app: App, item: IPluginData) => { const loadPluginJS = async (app: App, item: IPluginData) => {
@ -70,7 +63,7 @@ const loadPluginJS = async (app: App, item: IPluginData) => {
displayName: item.displayName, displayName: item.displayName,
name: item.name, name: item.name,
i18n: item.i18n i18n: item.i18n
}); }) as Plugin;
app.plugins.push(plugin); app.plugins.push(plugin);
try { try {
await plugin.onload(); await plugin.onload();
@ -80,15 +73,30 @@ const loadPluginJS = async (app: App, item: IPluginData) => {
return plugin; return plugin;
}; };
const getPluginsStyle = () => {
let pluginsStyle = document.getElementById("pluginsStyle");
if (!pluginsStyle) {
pluginsStyle = document.createElement("style");
pluginsStyle.id = "pluginsStyle"; // 用于将内联样式插入到插件样式前的标识
document.head.append(pluginsStyle);
}
return pluginsStyle;
};
const insertPluginCSS = (item: IPluginData, pluginsStyle: HTMLElement) => {
if (!item.css) {
return;
}
const styleElement = document.createElement("style");
styleElement.id = "pluginsStyle" + item.name;
styleElement.textContent = item.css;
pluginsStyle.insertAdjacentElement("afterend", styleElement);
};
// 启用插件 // 启用插件
export const loadPlugin = async (app: App, item: IPluginData) => { export const loadPlugin = async (app: App, item: IPluginData) => {
const plugin = await loadPluginJS(app, item); const plugin = await loadPluginJS(app, item);
if (item.css) { insertPluginCSS(item, getPluginsStyle());
const styleElement = document.createElement("style");
styleElement.id = "pluginsStyle" + item.name;
styleElement.textContent = item.css;
document.head.append(styleElement);
}
afterLoadPlugin(plugin); afterLoadPlugin(plugin);
saveLayout(); saveLayout();
getAllEditor().forEach(editor => { getAllEditor().forEach(editor => {
@ -229,16 +237,31 @@ export const reloadPlugin = async (app: App, data: {
} }
}); });
}); });
app.plugins.forEach(item => { // 先收集需要处理的插件,避免在遍历过程中修改数组导致重复执行
if (upsertDataPlugins.includes(item.name)) { const dataChangedPlugins = app.plugins.filter(item => upsertDataPlugins.includes(item.name));
try { dataChangedPlugins.forEach(item => {
item.onDataChanged(); try {
} catch (e) { item.onDataChanged();
console.error(`plugin ${item.name} onDataChanged error:`, e); } catch (e) {
} console.error(`plugin ${item.name} onDataChanged error:`, e);
} }
}); });
/// #if !MOBILE /// #if !MOBILE
saveLayout(); saveLayout();
/// #endif /// #endif
}; };
// 重启插件
export const restartPlugin = async (app: App, plugin: Plugin) => {
uninstall(app, plugin.name, false, true);
app.plugins.push(plugin);
try {
await plugin.onload();
} catch (e) {
console.error(`plugin ${plugin.name} onload error:`, e);
}
afterLoadPlugin(plugin);
getAllEditor().forEach(editor => {
editor.protyle.toolbar.update(editor.protyle);
});
};

View file

@ -8,7 +8,7 @@ import {Constants} from "../constants";
import {setStorageVal} from "../protyle/util/compatibility"; import {setStorageVal} from "../protyle/util/compatibility";
import {getAllEditor} from "../layout/getAll"; import {getAllEditor} from "../layout/getAll";
export const uninstall = (app: App, name: string, isUninstall: boolean) => { export const uninstall = (app: App, name: string, isUninstall: boolean, keepCSS: boolean = false) => {
app.plugins.find((plugin: Plugin, index) => { app.plugins.find((plugin: Plugin, index) => {
if (plugin.name === name) { if (plugin.name === name) {
try { try {
@ -75,7 +75,9 @@ export const uninstall = (app: App, name: string, isUninstall: boolean) => {
editor.protyle.toolbar.update(editor.protyle); editor.protyle.toolbar.update(editor.protyle);
}); });
// rm style // rm style
document.getElementById("pluginsStyle" + name)?.remove(); if (!keepCSS) {
document.getElementById("pluginsStyle" + name)?.remove();
}
return true; return true;
} }
}); });

View file

@ -22,7 +22,7 @@ import {
import {initMessage} from "../dialog/message"; import {initMessage} from "../dialog/message";
import {getAllTabs} from "../layout/getAll"; import {getAllTabs} from "../layout/getAll";
import {getLocalStorage} from "../protyle/util/compatibility"; import {getLocalStorage} from "../protyle/util/compatibility";
import {init} from "../window/init"; import {init} from "./init";
import {loadPlugins, reloadPlugin} from "../plugin/loader"; import {loadPlugins, reloadPlugin} from "../plugin/loader";
import {hideAllElements} from "../protyle/ui/hideElements"; import {hideAllElements} from "../protyle/ui/hideElements";
import {reloadEmoji} from "../emoji"; import {reloadEmoji} from "../emoji";