jupyterlab-plugin-playground icon indicating copy to clipboard operation
jupyterlab-plugin-playground copied to clipboard

Question regarding JupyterLab Widgets

Open TK-21st opened this issue 4 years ago • 4 comments

Thank you so much for this work! We've been looking for a quick way to develop/debug JLab extensions for quite some time now, and this seems to be of great help!

I have a question regarding JupyterLab widgets, particularly those that subclass @lumino/widgets. Simply put, if we use the

As a barebone example, I was trying to see if it'd be possible to dynamically load the tutorial widget/extension (https://github.com/jupyterlab/jupyterlab_apod).

So in this case, the index.js of the APOD Widget/Extension compiles into something like

define(["require", "exports", "@jupyterlab/application", "@jupyterlab/apputils", "@lumino/widgets"], function (require, exports, application_1, apputils_1, widgets_1) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    ;
    class APODWidget extends widgets_1.Widget {
    ...
    }

    function active(app, palette, restorer) {
    }

    /**
     * Initialization data for the jupyterlab_apod extension.
     */
    const extension = {
        id: 'my-apod-extension',
        autoStart: true,
        requires: [apputils_1.ICommandPalette, application_1.ILayoutRestorer],
        activate: activate
    };
    exports.default = extension;

And I tried to create a JS file which looks like

return function()
{
  return {
    id: 'dynext-test-extension',
    autoStart: true,
    requires: ["jupyter.extensions.jupyterWidgetRegistry"],
    activate: function(app, widgets) {
      require.config({
        // take the widget from `unpkg.com`
        baseUrl: "/Users/tingkailiu/Projects/FFBO/JLab2/dynext-test-extension/lib"
      });

      let widget = "index";
      // note that we are using require js here to load the AMD module
      // requirejs is automatically loaded with jupyterlab-dynext.
      // * (star) selects the latest version from unpkg, and then loads the `/dist/index.js` file
      // the final URL will be something like https://unpkg.com/bqplot@^0.5.2/dist/index.js
      require([widget], function(plugin) {
        widgets.registerWidget({
            name: widget,
            version: plugin.version,
            exports: plugin
        });
      });
    }
  };
}

But it seems like jupyter.extensions.jupyterWidgetRegistry is not found and it's because I'm not using jupyterlab-manager since I'm trying to load a lab widget instead of a ipywidget.

Could you suggest a way for dynamically loading and developing jupyterlab widget/extension?

TK-21st avatar May 21 '20 21:05 TK-21st

thanks! yes, I believe we need to expose more JavaScript modules to the dynamically loaded extension. I can try to use your example to see if we can get something to work.

wolfv avatar May 22 '20 06:05 wolfv

Hi wolfv! I managed to put something together here https://github.com/TK-21st/jupyterlab-apod-dynext. What I'm doing is instead of loading extension dynamically, I'm injecting the Widget Module dynamically to an extension that's bundled into JLab the usual way.

I think making both work together would be the ideal solution. For now, I think I spend more time debugging/developing the Widget than the Extension so it works for me.

TK-21st avatar May 22 '20 15:05 TK-21st

awesome! Do you think we can combine these two solutions into one repo?

wolfv avatar May 24 '20 07:05 wolfv

That'd be great!

Having said that, I'm actually not 100% clear how the workflow should look like combining the two. There seem to be 3 packages involved in a common workflow

  1. dynext: this needs to be installed to JLab as a normal extension so that requirejs can be injected on start up
  2. custom-extension: this is the part that I'm unsure about. How should a user automate the process of developing and injecting custom extension into browser? Suppose I want to create a new extension, how do I tell JLab to use dynext to load this extension in browser? I guess you could use filebrower to open the index.ts file and do some magic there but I feel like this step could be more automated.
  3. custom-widget: this widget (JupyterLab Widget, not Ipywidget) can be dynamically loaded into the custom-extension with my current solution (require a locally served widget)

And it'd also be really nice to have an NPM script which automatically bundles the custom-extension/widget into JLab as per normal.

TK-21st avatar May 24 '20 16:05 TK-21st