-
Notifications
You must be signed in to change notification settings - Fork 19
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for custom widgets loaded from CDN #4
Comments
Our ipywidgets implementation currently only supports the default set of widgets provided in @jupyter-widgets/controls. We aren't set up to support custom widgets. This would require adding some logic that understands how to load widget dependencies outside the standard set. If you have any ideas on how to approach this, feel free to share in this thread. |
@captainsafia Back in our prototype for the Python extension, we did manage to get this working. Unfortunately that prototype hasn't seen the light of day for the past 2 months due to other priorities. The widget manager supports loading dependencies asynchronously, hence I used the pouplar amd library FYI - this works very well (in our prototype), and I've managed to get most of the 3rd party widgets up and running: // Source borrowed from https://github.com/jupyter-widgets/ipywidgets/blob/master/examples/web3/src/manager.ts
// tslint:disable: no-any no-console
const cdn = 'https://unpkg.com/';
function moduleNameToCDNUrl(moduleName: string, moduleVersion: string) {
let packageName = moduleName;
let fileName = 'index'; // default filename
// if a '/' is present, like 'foo/bar', packageName is changed to 'foo', and path to 'bar'
// We first find the first '/'
let index = moduleName.indexOf('/');
if (index !== -1 && moduleName[0] === '@') {
// if we have a namespace, it's a different story
// @foo/bar/baz should translate to @foo/bar and baz
// so we find the 2nd '/'
index = moduleName.indexOf('/', index + 1);
}
if (index !== -1) {
fileName = moduleName.substr(index + 1);
packageName = moduleName.substr(0, index);
}
return `${cdn}${packageName}@${moduleVersion}/dist/${fileName}`;
}
async function requirePromise(pkg: string | string[]): Promise<any> {
return new Promise((resolve, reject) => {
const requirejs = (window as any).requirejs;
if (requirejs === undefined) {
reject('Requirejs is needed, please ensure it is loaded on the page.');
} else {
requirejs(pkg, resolve, reject);
}
});
}
function requireLoader(moduleName: string, moduleVersion: string) {
const requirejs = (window as any).requirejs;
if (requirejs === undefined) {
throw new Error('Requirejs is needed, please ensure it is loaded on the page.');
}
const conf: { paths: { [key: string]: string } } = { paths: {} };
conf.paths[moduleName] = moduleNameToCDNUrl(moduleName, moduleVersion);
requirejs.config(conf);
return requirePromise([`${moduleName}`]);
}
export class WidgetManager extends HTMLManager {
public kernel: Kernel.IKernelConnection;
public el: HTMLElement;
constructor(kernel: Kernel.IKernelConnection, el: HTMLElement) {
super({ loader: requireLoader }); |
@captainsafia I'm happy to submit a PR if this solution is acceptable. |
@DonJayamanne Thanks for posting this update and sharing the code snippet! I like the approach of mapping the package names to an unpkg-based CDN URL and loading client-side dependencies. Generally, I'd like us to shy away from using Would it be possible to scope it so that requirejs isn't registered on the |
Just FYI (as indicated above in the credit to the ipywidgets web3 example), this loading from a CDN using requirejs is also the approach taken by the ipywidgets html manager:
Voila also uses a similar approach, but IIRC can also load the amd modules supplied by custom widgets for the classic notebook. CC @maartenbreddels and @SylvainCorlay. @SylvainCorlay and I were also talking this last week at the widgets sprint about strengthening this story around loading custom widgets from the web. @wolfv also has a nice demo showing how to load custom widgets from the web in JupyterLab without having to install them. |
Also, one more thing - we will probably switch from unpkg to jsdelivr as the default cdn for these sorts of things in ipywidgets 8: jupyter-widgets/ipywidgets#1627 |
Updating the issue title and moving this to the new repo where the outputs transforms live. With @jasongrout's comments in mind, I think we can add fallback logic in the widget implementation to load widgets from jsdeliver. That should address most of the scenarios users have. |
@captainsafia, just following up on the constructive discussion on this thread. We are looking into adding support for custom ipywidgets and it's great to see some work already in that direction. I am currently doing some learning spikes to get more clarity in the space and would be happy to take it forward. Stay tuned for updates. |
Sounds good. You might find some of the stuff in #11 helpful. |
So exciting to see initial widgets support in recently released 0.18!
Application or Package Used
nteract desktop
Describe the bug
The Jupyter widget Qgrid does not render in nteract.
To Reproduce
Steps to reproduce the behavior:
!pip install pandas numpy qgrid
Source line in
widget-manager.ts
, in theloadClass
function:Expected behavior
The widget (Qgrid) should display / render.
Desktop:
Additional context
Add any other context about the problem here.
The text was updated successfully, but these errors were encountered: