retorquere/generator-zotero-plugin

Zotero not defined in bootstrap.js

Dominic-DallOsto opened this issue · 13 comments

I just generated a new bootstrap plugin, but am getting the following error here that Zotero is not defined. Line 267 of bootstrap.js corresponds to line 59 of bootstrap.ts. I'm running with Zotero directly reading from the plugin's build folder, but the same happens if I install the xpi.

1641819681880	addons.xpi	WARN	Error loading bootstrap.js for api-endpoint@hotmail.com: ReferenceError: Zotero is not defined (resource://gre/modules/addons/XPIProvider.jsm -> file:///home/dominic/zotero-api-endpoint/build/bootstrap.js:267:3) JS Stack trace: install__startup__shutdown__uninstall<@bootstrap.js:267:3
@bootstrap.js:1:45
loadBootstrapScope@XPIProvider.jsm:4299:9
callBootstrapMethod@XPIProvider.jsm:4363:9
processFileChanges@XPIProviderUtils.js:1606:13
checkForChanges@XPIProvider.jsm:3291:34
startup@XPIProvider.jsm:2196:25
callProvider@AddonManager.jsm:253:12
_startProvider@AddonManager.jsm:728:5
startup@AddonManager.jsm:892:9
startup@AddonManager.jsm:2981:5
observe@addonManager.js:63:9 

Am I missing something?

generator-zotero-plugin@0.1.0
npm@8.3.0
yo@4.3.0

Oops, bootstrap was supposed to be behind an "experimental" flag; I haven't yet found out how bootstrap extensions can learn that Zotero is up and running.

Ahh, all good!

Maybe not all good, but I have not found a way to safely wait until Zotero is available. I thought cita was bootstrapped but I can't find how they do this... I can't even find their chrome.manifest currently.

Here it is. It seems that Zutilo (and Cita I think is based off it) uses Components.utils.import to load the main script in the bootstrap

That call to Components.utils.import brings in generic firefox infrastructure, not zotero infra. If there is a clean path to Zotero, I'll happily add it to the generator. For now, I only know how to make overlay plugins work reliably.

Like this in Zutilo, which leads to a bunch of jumping through zutilo.js until here where the Zotero overlay is imported.

I'm testing this at the moment - just having some issues getting it to run through esbuild properly

Let me know if you hit on something that works reliably -- I'll be happy to add that to the generator.

I'll also gladly help with esbuild

Ok, it's not very nice but this at least works, more or less copying and simplifying Zutilo/Cita.

The idea seems to be:

  • wait for the window called 'navigator:browser' to load - now we can access Zotero as a property of the window
  • if we load a script with Services.scriptloader.loadSubScript, it will have access to Zotero like a global variable
    • for this to work, I needed to specify it as an extra entry point in esbuild.js

I couldn't get it to work if I imported the script normally. I could pass in a reference to Zotero but it wouldn't exist globally and I couldn't manage to declare/initialise a global variable properly.

I didn't yet try waiting for the window before exporting the bootstrap functions.

I don't think you can wait before exporting them. Those bootstrap functions need to exist from the start or the extension won't load. But this isn't so bad. The one thing I'm wondering about is this line. To my knowledge, after the first call to resolve or reject, further resolves/rejects become no-ops.

I have some other cleanup I'm working on now that I understand your solution. One major problem with restartless addons is that the lifecycle functions (install, uninstall, startup and shutdown) are not async, and trying to do async cleanup in shutdown is most likely going to error out if you do anything of substance. Good news is that Firefox does have (separate) async shutdown listeners and I can probably pass on the work to them.

I don't think you can wait before exporting them. Those bootstrap functions need to exist from the start or the extension won't load. But this isn't so bad. The one thing I'm wondering about is this line. To my knowledge, after the first call to resolve or reject, further resolves/rejects become no-ops.

Ahh yep. It seems the idea is that the it's only resolved once, but I don't know if it's possible to code it so that's guaranteed, or we just rely on there only ever being one window with that name.

I'm doing cleanup based on the information you unearthed that will make things much clearer.