How to load UI assets from external resources (Preferable a CDN?)

Hello!

I am looking for some guidance, general advice or resources on how plugin developers might be able to load their UI assets from an external resource? (Is it possible to do in JL 1.2?)

The idea is you will install the extension on the jupyter server once and then have that extension either fetch the assets from a CDN or an external location. From what I understand since JL 3.0 we can customize the webpack configuration via pre-built extensions and introduce the module federation plugin which would allow us to pull the assets from wherever you specify them. But in JL1.2 any update requires the jupyter server to re-build so the assets can be updated in the browser. So is it even technically possible to load them from an external reosurce in JL1.2?

Thanks,
Alfonso

I guess a quick run-down of why you’d want to do this would help… the performance gains of CDN are becoming more illusory. Further, a) you never know who’s listening in between and b) never know if that resource will be available in the future. This hit us (and others) non-trivially when the MathJax CDN sunset, leaving users stuck on older versions with hard-coded, broken default URLs.

technically possible to load them from an external reosurce in JL1.2?

If you control the lab server install, you can hack your index.html templates to point at whatever you want… but this is a high-effort path, and many extensions will be expecting to be served from the domain in question.

As to core: it seems unlikely much additional effort will be spent (or even welcomed much) on the legacy line to enable such things, and end user support for using the nodejs-based build tooling will eventually become opt-in (rather than broken-by-default after pip install).

From a support perspective, pip- (or conda- or whatever) managed extensions really tick the box, and have made it far easier for e.g. complex extension developers to ensure their front- and backend components are in sync and for users to reliably compose complex behaviors from uncoordinated parties.

1 Like

Hi Nicholas,

Appreciate the prompt response and your initial thoughts. The general reason for wanting to do something like this would be to decrease the “deployment” time of our plugin. Our current process takes several weeks (due to some other reasons that are out of our control, non technical tbh) so if our idea was technically feasible then having our UI assets “update” dynamically would allows us the ability to deploy faster.

If you control the lab server install, you can hack your index.html templates to point at whatever you want…

This is a good point and something I had not given much thought too, I am going to dig into this a bit more to see how feasible it is for us.

Lastly, I think the question I am really struggling with is “Does the static assets jupyter need for each plugin (JS, CSS, etc…) have to be in the FileSystem in order to be served? or can they be downloaded before they are served”

Thanks,
Alfonso

Does the static assets jupyter need for each plugin (JS, CSS, etc…) have to be in the FileSystem in order to be served? or can they be downloaded before they are served

You’d need something that was a “beachhead,” e.g.

// plugin.ts
...
function activate(app) {
  const script = document.createElement('script');
  script.src = 'https://d3js.org/d3.v7.min.js';
  script.onload = () => {
     console.log('d3 is loaded', window.d3);
  }
  document.body.appendChild(script);
}

In Lab <3, this file would get compiled into the lab, and served from $PREFIX/share/jupyter/lab/static but the d3 source would be loaded hot every page load… until that URL stopped working, of course.

In Lab 3, this would be its own file in a well-known $PREFIX/share/jupyter/lab/extensions/<name>/static/, but still wouldn’t cache the d3 somehow.

As a user/administrator, I would be super dubious of this behavior, and would almost always prefer to have everything I needed locally/in my jupyterhub. If anything, I’d recommend some approaches such as:

  • encapsulating the remote behavior in a well-known mechanism (e.g. an iframe) so that crashes are more localized
  • shipping the last-known-good version so it’s at least going to keep working
  • adding user/admin settings to allow opting out of the hot-loading behavior in case something breaks
1 Like