Skip to content

plugin/plugin-lifecycle

Node-side helpers for the plugin-lifecycle cases every plugin should be tested against, and which every suite used to hand-roll or skip:

  • reloadPlugin: disable the plugin, put its data.json into a given state — absent, as on a fresh install, or holding text that is not JSON, as after a crash mid-write or a bad Sync merge — and enable it again. The enable happens with the vault open and its layout ready, so it is also the “turned on later, in settings” path. - detectPluginUnloadLeak: disable the plugin and report whether its instance was garbage collected. A plugin that leaves a listener, an interval or a patch behind on unload keeps its instance alive through it, and every disable and re-enable then leaks a whole plugin.

Both run on the Node side, like app-config.ts, because each is several evaluations with work in between (a garbage collection is a CDP command, not something a renderer closure can ask for).

Interface Description
DetectPluginUnloadLeakParams Parameters for detectPluginUnloadLeak.
PluginLifecycleTarget Which plugin, and where. Shared by both helpers here.
PluginUnloadLeakResult What detectPluginUnloadLeak found.
ReloadPluginParams Parameters for reloadPlugin.
ReloadPluginResult What reloadPlugin found when it enabled the plugin again.
Function Description
detectPluginUnloadLeak Disables a plugin, checks whether its instance is garbage collected, and enables it again. The instance is the sentinel: everything a plugin owns is reachable only through it, so a collected instance means the unload released the plugin’s whole graph, and a surviving one means something outside the plugin still holds it. A WeakRef gives an exact answer where a heap measurement would be noisy. Needs a transport that can force a garbage collection (collectGarbage): desktop, and Android over local adb.
reloadPlugin Disables a plugin, optionally puts its data.json into a given state, and enables it again. Covers three cases a suite otherwise never reaches, because the setup always enables the plugin once, at startup, with whatever settings it last saved: - a fresh install: shouldRemoveDataJson: true, so loadData() resolves null; - a corrupt file: dataJsonText: '\{ not json', so loadData() resolves undefined (Obsidian’s readJson logs the parse error and returns nothing), and a plugin that then calls saveData() overwrites the user’s file; - enabled later: the enable runs with the layout already ready, so onLayoutReady fires at once. The result is returned rather than thrown, because a test of a corrupt data.json asserts on exactly whether the plugin’s onload survived it.