(pluginId, justInstalled = false)
| 5 | import actionStack from "./actionStack"; |
| 6 | |
| 7 | export default async function loadPlugin(pluginId, justInstalled = false) { |
| 8 | const baseUrl = await helpers.toInternalUri(Url.join(PLUGIN_DIR, pluginId)); |
| 9 | const cacheFile = Url.join(CACHE_STORAGE, pluginId); |
| 10 | |
| 11 | // Unmount the old version before loading the new one. |
| 12 | // This MUST be done here by the framework, not by the new plugin code itself, |
| 13 | // because once the new script loads, it calls acode.setPluginUnmount(id, newDestroy) |
| 14 | // which overwrites the old version's destroy callback. At that point the old |
| 15 | // destroy — which holds references to the old sidebar app, commands, event |
| 16 | // listeners, etc. — is lost and can never be called. Letting the framework |
| 17 | // invoke unmountPlugin() first ensures the OLD destroy() runs while it still |
| 18 | // exists, so all old-version resources are properly cleaned up. |
| 19 | acode.unmountPlugin(pluginId); |
| 20 | |
| 21 | // Remove the old <script> tag so the browser fetches the new source. |
| 22 | const oldScript = document.getElementById(`${pluginId}-mainScript`); |
| 23 | if (oldScript) oldScript.remove(); |
| 24 | |
| 25 | const pluginJson = await fsOperation( |
| 26 | Url.join(PLUGIN_DIR, pluginId, "plugin.json"), |
| 27 | ).readFile("json"); |
| 28 | |
| 29 | let mainUrl; |
| 30 | if ( |
| 31 | await fsOperation(Url.join(PLUGIN_DIR, pluginId, pluginJson.main)).exists() |
| 32 | ) { |
| 33 | mainUrl = Url.join(baseUrl, pluginJson.main); |
| 34 | } else { |
| 35 | mainUrl = Url.join(baseUrl, "main.js"); |
| 36 | } |
| 37 | |
| 38 | return new Promise((resolve, reject) => { |
| 39 | const $script = ( |
| 40 | <script id={`${pluginId}-mainScript`} src={mainUrl}></script> |
| 41 | ); |
| 42 | |
| 43 | $script.onerror = (error) => { |
| 44 | reject( |
| 45 | new Error( |
| 46 | `Failed to load script for plugin ${pluginId}: ${error.message || error}`, |
| 47 | ), |
| 48 | ); |
| 49 | }; |
| 50 | |
| 51 | $script.onload = async () => { |
| 52 | const $page = Page("Plugin"); |
| 53 | $page.show = () => { |
| 54 | actionStack.push({ |
| 55 | id: pluginId, |
| 56 | action: $page.hide, |
| 57 | }); |
| 58 | |
| 59 | app.append($page); |
| 60 | }; |
| 61 | |
| 62 | $page.onhide = function () { |
| 63 | actionStack.remove(pluginId); |
| 64 | }; |
no test coverage detected