Page MenuHomePhabricator

mw.loader: allow redirection in mw.loader.load/using during development
Closed, DeclinedPublic

Description

I have some scripts, some of which are Gadgets, that depend on "library" scripts.

For example, say I have user-script "Tool A" and gadgets "Gadget A" and Gadget B" that all depend on "Library A", which hangs its API from window.LibraryA. Library A is a Gadget too, so I can load it with mw.loader.using("ext.gadget.LibraryA") from Tool A, while Gadgets A and B declare it as a dependency in gadgets-definition.

However, when I am developing Tool A, I may want to also adjust Library A. Normally, I serve the JS locally for development, so I use something like mw.loader.load("https://localhost/libraryA.js"). This means that if I have Gadgets A and B enabled, I'll be loading two copies of Library A, one from the wiki and one locally, which will compete for the window slot. So I have to hack in guards somewhere (e.g. a per-script way to load deps locally) or manually disable any gadgets using Library A while working on Tool A. So then I need to serve all of them locally too to make sure my changes to Library A don't break them.

It would be much easier if I could temporarily redirect ext.gadget.LibraryA to the local script for dev purposes (which would apply to Gadget A and B too). So that any JS using that script will actually get the dev script, transparently.

[If I have missed an existing best practice for development here, I apologise, but I couldn't find one in the existing documentation.]

Event Timeline

Restricted Application added a subscriber: Aklapper. · View Herald Transcript

I don't currently have plans to develop or support a way to override dependencies at run-time. It seems that would require significant complexity and delays to make possible, which would be problematic for production performance more generally. However, I'm open to ideas for ways to do this in an efficient, stable, and secure manner.

There are a number of existing workflows that I think do solve your use case, though:

  • When developing a gadget, I think it's common to disable the gadget in question indeed. You can then load your own copy either from the console directly, or through a directory loaded as browser extension, or indeed by using mw.loader() with a URL to a local file server (simple file server).
  • If you want to locally debug the exact workings of the Gadget extension, I'd recommend installing MediaWiki and importing the gadgets in question from the source wiki(s) via Special:Gadgets. The Gadgets-2.0 project has proposed and drafted a number of improvements to make this easier to use, however this is currently not resourced. Note that MediaWiki can be downloaded as a zip file and run locally with nothing other than plain PHP. There is no need for Git, Composer, MySQL, Apache or anything like that. One zip file, and one command and you have a working wiki.
  • There is also Beta Cluster where you can ask to be an interface admin and import/experiment with gadget development.

@Krinkle fair enough I guess.

The issue is that you have to find and disable all the gadgets that use the library. If one of those is part of a piece of default site JS, you either have to live without that JS for as long as you are developing "Tool A" or "Library A" or you have to copy every single piece of it to the local dev server and fake up the RL dependencies manually (and if you want to check if Gadget A and B are not broken by changes to Library A, you have to do this anyway, since you can't point Gadget A/B's dependencies to localhost). This generally has resulting me in just duplicating things between scripts that might be Gadgets, because an RL shared "library" is too much effort to debug if you have to turn off all other users for the duration.

I normally develop using a local server like this: https://en.wikisource.org/wiki/User:Inductiveload/Script_development and mw.loader.load().

I also run MediaWiki locally (in Docker) for extension development, so that's kind of an option but it's really frustrating to have to keep porting gadgets back and forth, especially if they interact with on-wiki things like templates, which then all need to be synced.

Thanks, I agree it could be made simpler, but I don't see a feasible way to accomplish that within our current constraints and it would also take additional resourcing that I don't have at the moment. Ideas welcome, and small improvements in the form of a patch I will consider and try to review.