diff --git a/app/src/plugin/index.ts b/app/src/plugin/index.ts index 3295c9006..b75c55725 100644 --- a/app/src/plugin/index.ts +++ b/app/src/plugin/index.ts @@ -16,8 +16,7 @@ import {BlockPanel} from "../block/Panel"; import {Setting} from "./Setting"; import {clearOBG} from "../layout/dock/util"; import {Constants} from "../constants"; -import {uninstall} from "./uninstall"; -import {afterLoadPlugin} from "./loader"; +import {restartPlugin} from "./loader"; export class Plugin { private app: App; @@ -103,7 +102,7 @@ export class Plugin { }); } - public onload() { + public onload(): Promise | void { // 加载 } @@ -118,8 +117,7 @@ export class Plugin { public onDataChanged() { // 存储数据变更 // 兼容 3.4.1 以前同步数据使用重载插件的问题 - uninstall(this.app, this.name, false); - afterLoadPlugin(this); + restartPlugin(this.app, this); } public async updateCards(options: ICardData) { diff --git a/app/src/plugin/loader.ts b/app/src/plugin/loader.ts index 68821691f..6dc5cd19b 100644 --- a/app/src/plugin/loader.ts +++ b/app/src/plugin/loader.ts @@ -29,22 +29,15 @@ const runCode = (code: string, sourceURL: string) => { export const loadPlugins = async (app: App, names?: string[]) => { const response = await fetchSyncPost("/api/petal/loadPetals", {frontend: getFrontend()}); - let css = ''; // 用于将内联样式插入到插件样式前的标识 - // 为加快启动速度,不进行 await - response.data.forEach((item: IPluginData) => { - if (!names || (names && names.includes(item.name))) { - loadPluginJS(app, item); - } - if (item.css) { - css += ``; - } + const pluginsStyle = getPluginsStyle(); + const pluginsToLoad = !names + ? response.data + : response.data.filter((item: IPluginData) => names.includes(item.name)); + pluginsToLoad.forEach((item: IPluginData) => { + // 为加快启动速度,不进行 await + loadPluginJS(app, item); + 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) => { @@ -70,7 +63,7 @@ const loadPluginJS = async (app: App, item: IPluginData) => { displayName: item.displayName, name: item.name, i18n: item.i18n - }); + }) as Plugin; app.plugins.push(plugin); try { await plugin.onload(); @@ -80,15 +73,30 @@ const loadPluginJS = async (app: App, item: IPluginData) => { 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) => { const plugin = await loadPluginJS(app, item); - if (item.css) { - const styleElement = document.createElement("style"); - styleElement.id = "pluginsStyle" + item.name; - styleElement.textContent = item.css; - document.head.append(styleElement); - } + insertPluginCSS(item, getPluginsStyle()); afterLoadPlugin(plugin); saveLayout(); getAllEditor().forEach(editor => { @@ -229,16 +237,31 @@ export const reloadPlugin = async (app: App, data: { } }); }); - app.plugins.forEach(item => { - if (upsertDataPlugins.includes(item.name)) { - try { - item.onDataChanged(); - } catch (e) { - console.error(`plugin ${item.name} onDataChanged error:`, e); - } + // 先收集需要处理的插件,避免在遍历过程中修改数组导致重复执行 + const dataChangedPlugins = app.plugins.filter(item => upsertDataPlugins.includes(item.name)); + dataChangedPlugins.forEach(item => { + try { + item.onDataChanged(); + } catch (e) { + console.error(`plugin ${item.name} onDataChanged error:`, e); } }); /// #if !MOBILE saveLayout(); /// #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); + }); +}; diff --git a/app/src/plugin/uninstall.ts b/app/src/plugin/uninstall.ts index a3a17fde7..4b73e7880 100644 --- a/app/src/plugin/uninstall.ts +++ b/app/src/plugin/uninstall.ts @@ -8,7 +8,7 @@ import {Constants} from "../constants"; import {setStorageVal} from "../protyle/util/compatibility"; 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) => { if (plugin.name === name) { try { @@ -75,7 +75,9 @@ export const uninstall = (app: App, name: string, isUninstall: boolean) => { editor.protyle.toolbar.update(editor.protyle); }); // rm style - document.getElementById("pluginsStyle" + name)?.remove(); + if (!keepCSS) { + document.getElementById("pluginsStyle" + name)?.remove(); + } return true; } }); diff --git a/app/src/window/index.ts b/app/src/window/index.ts index 7dc346da8..5716e267b 100644 --- a/app/src/window/index.ts +++ b/app/src/window/index.ts @@ -22,7 +22,7 @@ import { import {initMessage} from "../dialog/message"; import {getAllTabs} from "../layout/getAll"; import {getLocalStorage} from "../protyle/util/compatibility"; -import {init} from "../window/init"; +import {init} from "./init"; import {loadPlugins, reloadPlugin} from "../plugin/loader"; import {hideAllElements} from "../protyle/ui/hideElements"; import {reloadEmoji} from "../emoji";