Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions src/lib/loadPlugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,27 @@ export default async function loadPlugin(pluginId, justInstalled = false) {
const baseUrl = await helpers.toInternalUri(Url.join(PLUGIN_DIR, pluginId));
const cacheFile = Url.join(CACHE_STORAGE, pluginId);

// Unmount the old version before loading the new one.
// This MUST be done here by the framework, not by the new plugin code itself,
// because once the new script loads, it calls acode.setPluginUnmount(id, newDestroy)
// which overwrites the old version's destroy callback. At that point the old
// destroy — which holds references to the old sidebar app, commands, event
// listeners, etc. — is lost and can never be called. Letting the framework
// invoke unmountPlugin() first ensures the OLD destroy() runs while it still
// exists, so all old-version resources are properly cleaned up.
try {
acode.unmountPlugin(pluginId);
} catch (e) {
// unmountPlugin() itself is safe when no callback is registered (it no-ops),
// but a plugin's destroy() callback may throw. We catch here so a faulty
// cleanup in the old version does not block reloading the new one.
console.error(`Error while unmounting plugin "${pluginId}":`, e);
}

// Remove the old <script> tag so the browser fetches the new source.
const oldScript = document.getElementById(`${pluginId}-mainScript`);
if (oldScript) oldScript.remove();

const pluginJson = await fsOperation(
Url.join(PLUGIN_DIR, pluginId, "plugin.json"),
).readFile("json");
Expand Down