jupyter-widgets / ipywidgets

Interactive Widgets for the Jupyter Notebook
https://ipywidgets.readthedocs.io
BSD 3-Clause "New" or "Revised" License
3.16k stars 950 forks source link

Dynamic module loading from external CDN in Jupyterlab #2077

Closed DavidJVitale closed 5 years ago

DavidJVitale commented 6 years ago

Hello,

I have an ipywidget authored originally from the cookie cutter template. My ipywidget has require statements like this:

var webMap = require('esri/WebMap')

The esri JS module being used here is very large, and I want to dynamically import it at runtime from a CDN instead of bundle it. It is not listed anywhere as a dependency in packages.json, and I have my webpack externals configured to allow through all esri/ statements during my build phase:

externals: ['@jupyter-widgets/base',
            (context, request, callback) => {
                if (/^dojo/.test(request) || /^esri/.test(request)) {
                    if (request.includes("dojo/i18n!.")) {
                        request = request.replace(/^dojo\/i18n!\./, "dojo/i18n!./widgets");
                    }
                    return callback(null, "amd " + request);
                }
                callback();
            }

My widget can then build successfully with no errors. To make it load from CDN when the notebook is opened, I have my extension.js file configure requireJS to add those modules from the CDN to the global scope:

if (window.require) {
    window.require.config({
...
        packages: [{
            name: 'esri',
            location: 'https://js.arcgis.com/4.7/esri',
            },{
            name: 'dojo',
            location: 'https://js.arcgis.com/4.7/dojo'
            }
        ]
    });
}

This gives me the correct behavior in traditional Jupyter Notebooks. However, I get the following error when I attempt to use the widget in Jupyterlab:

Cannot find module "esri/WebMap" Stack trace: ...

From my understanding, this makes sense: extension.js is not included in the JS source when building the labextension.js widget for JupyterLab. This is because Jupyterlab doesn't have a configurable global requireJS in its implementation.

My question is:

In Jupyterlab, what is the recommended way to author my widget so as to dynamically load the esri module from that external CDN?

DavidJVitale commented 6 years ago

To add some additional info:

Madhu94 commented 5 years ago

@DavidJVitale I'm not sure if your problem is solved already, but yes you need a jupyterlab extension. You can look at the custom widget cookiecutter for an example.

vidartf commented 5 years ago

I would ask this question again on a jupyterlab forum, either the repo or on gitter. In general, I do not know if this can be configured to use a CDN, but you can definitively get JupyterLab's bundling step to create a separate chunk for your dependency. This can be achieved by lazily fetching your module with require.ensure.

DavidJVitale commented 5 years ago

I have solved this issue, I authored an extension that has seperate builds for classic notebook server and Jupyterlab, using a high level misdirection in the source code of my extension (using the bundled RequireJS with Classic Notebook server to load AMD modules from CDN, with JupyterLab dynamically importing a dojo loader and using that to load the same AMD modules from CDN).

For any curious, the extension is the https://www.npmjs.com/package/arcgis-map-ipywidget for the JS source code: the python end of things is the arcgis.widgets.MapView class from the ArcGIS API for Python. Works in both Classic Notebook and JupyterLab! :)