[JLab] When are deferred extensions that define functionality triggered by UI interactions loaded?

From the doc for deferredExtensions -

deferredExtensions controls which extensions should not load until they are required by something, irrespective of whether they set autoStart to true.

However, if an extension that is independent (not required by any other extension) and defining functionality that can be triggered only through UI interactions (say a menu item or a command palette item) were to be deferred, will it be loaded at all?

Is it valid to assume that such an extension is not a good candidate to be deferred?

Right: the deferred extension mechanism is for fairly specific use cases, and doesn’t really support much dynamism. One could for example ship a “core” extension and mountain of provider extensions (think IGitLabManager, IGitHubManager, etc.) that might not make sense to all be loaded at once, so none of them would be loaded, and would need to be configured explicitly.

For the more general case, as pertains to the bottom-line load time (e.g. the moon animation starts), one can rely on using dynamic import statements at natural async boundaries. This pattern is encouraged, for example, when registering new Jupyter Widgets, as its registerWidgets needs some concrete information (the name and version of the widget) up-front, but accepts a promise for the actual implementation, such as in bqplot.

A pithy example might look like:

// doesn't trigger up-front load
import type { Thing } from 'the-big-thing';

activate(app: JupyterFrontEnd): void {
  app.commands.register('do-big-thing', {
    execute: async (args: any): Promise<Thing> =>  {
       // actually load
       const { Thing } = await import('the-big-thing');
       return Thing(args);
    }
  })
}

Of course, the type isn’t super relevant in a command setting, as it’s one of the “squishier” untyped interfaces, so no downstream will really be able to make use of these typings.

2 Likes

Thanks, this is very helpful!

I am indeed looking to decrease the load-time by deferring plugins to when they are needed. However, all the plugins involved are external and I do not have access to the source to use the dynamic import strategy mentioned.

I’ll look into potentially disabling a few extensions instead.

Yep. Getting load time down is a team effort.

There’s some work on this PR to create a developer- or end-user-installable plugin for benchmarking/profiling which might end up being helpful for your investigations.

A longer con would be make this available in an easy-to-consume format for extension developers, e.g. a github action:

- use: jupyterlab/benchmarking@vX
  with:
    extensions:
      - dist/my-extension-*.whl # and probably even auto-detect this
    output: build/reports/jupyter-benchmarking

As to actually fixing an issue once found: a lot of it boils down to the techniques above, and ensuring that multiple packages can reuse the same sharedModules. I guess it just takes the hard work of making the case for performance vs simplicity and getting a PR through the upstreams… I’ve had it take… years.

1 Like

Thanks! I’ve been following Mike’s PR for a while now and have gotten in touch with him recently; looking forward to the profiler extension.

I’ve been trying to improve performance related stuff in Jupyterlab for a while now, though nowhere as long as years. :sweat_smile:

For the original issue of potentially disabling extensions, is there a plan to add UI to enable/disable pre-built extensions? I feel that it could be a step in the right direction, if the user had the ability to enable only the required extensions, just using UI. If you’d rather this discussion were in Github, I’m happy to open an issue to discuss it further.

FTR - logged UI to enable/disable pre-built extensions · Issue #13689 · jupyterlab/jupyterlab · GitHub to discuss the possibility of adding UI for enabling/disabling pre-built extensions.