IITC-CE / ingress-intel-total-conversion

intel.ingress.com total conversion user script with some new features. Should allow easier extension of the intel map.
https://iitc.app
ISC License
284 stars 110 forks source link

Plugins loading order #76

Closed johnd0e closed 4 years ago

johnd0e commented 5 years ago

Some things are not obvious and should be documented somewhere.

In fact IITC core may be loaded before plugins, after plugins, or somewhere in the middle. Although in some environments we could control the order, but if scripts are loading asynchronously, then bigger scripts will finish loading later (no matter of initial order).

So in general we can't expect particular order of IITC/plugins loading.

But plugin's function setup is called when iitc is booted, and we can rely on this.

So the rule: Plugin can use all service API's (IITC/jQuery/Leaflet/...) only after setup called

johnd0e commented 5 years ago

But sometimes order is important, and here we can run into issues, because there is no reliable way just to execute some plugins before others.

So it's essential to have some control under execution order.

I want to discuss here all possible issues.

johnd0e commented 5 years ago
  1. There are plugins which rewrite/extend functions of other plugins.

It is possible if other plugin's functions is already defined at the moment of 'extending'. So it's not usually a problem, if following conditions met:

Otherwise we need some additional tricks to ensure correct order of operations.

johnd0e commented 5 years ago
  1. There are plugins which provide service via hooks (pluginCreateHook/addHook).

And we can run into issue if some plugin calls addHook before such hook created: https://github.com/IITC-CE/ingress-intel-total-conversion/blob/d77562b91a5b1e0bf170b4257eb33316a0b9daa3/code/hooks.js#L99-L104

I suppose this check should be removed (do not see any other way to resolve the issue). Edit: the same was proposed here: https://github.com/iitc-project/ingress-intel-total-conversion/issues/1248

johnd0e commented 5 years ago
  1. Some plugins may want to extend Leaflet, or load some other lib, or provide utility function, or any 'feature'.

And for plugins which are in need of that 'feature' we have to use special handling, like this:

Currently there is no nice way to resolve this. The best we can do now: wait by putting pending actions into hook (addHook), and that hook should be provided by service plugin (when the issue from previous comment get resolved).

But honestly it is not friendly method. I wonder if we can provide service function like require.

Edit: I have to mention alternative way: force load required plugin, like proposed here: iitc-project/ingress-intel-total-conversion#1207 (comment) (Haven't test such method yet, but do not think that we can do it)

johnd0e commented 5 years ago
  1. There is currently iitcLoaded hook run from here: https://github.com/IITC-CE/ingress-intel-total-conversion/blob/d77562b91a5b1e0bf170b4257eb33316a0b9daa3/code/boot.js#L697

It is used in plugins:

It is intended to run after all plugins are loaded (and their setup executed). Well.. As load order is unpredictable it just cannot be reliable, as it's possible that some plugin is loaded later (so this hook never run for it).

But it works in most cases, I suppose because iitc core is much bigger that most plugins, and loads longer.

P.S. More reliable solution would be using promise like here: https://github.com/IITC-CE/ingress-intel-total-conversion/issues/76#issuecomment-479861577

johnd0e commented 5 years ago
  1. I can imagine some 'service' plugin that need to be executed before leaflet map initialized. Perhaps this should be done in other way, by map re-creation. But we should consider already existent map hooks..

Edit Perhaps plugins could provide some function like setup, which would be executed separately, before map creation.

I suppose it should work.

johnd0e commented 5 years ago

I have an idea for API which is able to solve issue 3 smoothly.

IITC could provide function like this:

whenReady('plugin_id', callback);
// or
whenReady('plugin_id').done(callback); // https://api.jquery.com/deferred.done/

To make this work service plugin (in it's setup function) should run some hook:

whenReady('plugin_id').resolve(args); // optional `args` to pass to all callbacks

(It's even possible to run such hook automatically if we include it into wrapper code)

Proposed addition to iitc code is extremely simple:

hooks.js ```js var Promises = []; window.whenReady = function (id, callback) { if (!Promises[id]) { Promises[id] = $.Deferred() } Promises[id].done(callback); return Promises[id]; } ```
johnd0e commented 5 years ago

So let me summarize. setup function runs much later then rest of the plugin code, and we have to use this fact.

So, I suppose most of issues on this topic is (more or lesser) clear to me now.

modos189 commented 5 years ago

IITC could provide function like this: whenReady('plugin_id', callback); // callback function could receive something in arguments

I would like that if the plugin is not installed, the hook also worked, but with relevant arguments. Sometimes is to determine that the plugin is missing.

johnd0e commented 5 years ago

Sometimes is to determine that the plugin is missing.

I need to mention that we have most features already:

The only thing I am concerning about is rare possibility of delayed plugin's loading. This possibility is covered by such wrapper code:

if(window.iitcLoaded && typeof setup === 'function') setup();

In this case new whenReady will be more reliably than plain iitcLoaded hook.

But how we should check plugin existence for sure? It is not loaded now, but it may get loaded in 2 minutes (or even in 2 hours, if we implement dynamic plugin loading).

In any case, if we expect immediate plugin availability then we can check it's namespace as before. Or we can make compromise solution, like reject Promise on some timeout (say, 1 minute).