Closed billti closed 11 months ago
Since you're approaching a stage of wanting to have a component library to work with, I personally would go with creating a shared ES Module. I recommend trying out esbuild
as you can create an ESM bundle that can be reused by other ESM.
esbuild main.tsx --bundle --outdir=dist --format=esm
My name is appster
> ) } ``` **`main.tsx`** ```typescript import React from "https://esm.sh/react@18.2.0" import Component from "./component.tsx" export function render() { returnI am using esbuild and doing exactly what you describe. But how would I expose two different 'render' functions to be used by two different anywidget Python classes from that bundle? You can't, because the exported function is required to be called 'render', so a bundle can only export one function called 'render'.
Thanks for your suggestion on enhancing anywidget's API to allow dynamic determination of renderer function names. While this is an interesting idea, currently anywidget operates with a "one widget per file" approach for simplicity and clarity.
For your use case, I recommend continuing to use esbuild
and organizing your code by bundling separate entry points for each widget, while keeping the shared logic in a separate ES module. This way, each widget can import and use the shared functionality as needed:
esbuild --bundle --outdir=dist a-widget.js b-widget.js
// shared.js
export function sharedFunction() { /* Shared logic */ }
// a-widget.js
import { sharedFunction } from "./shared.js";
export function render({ model, el }) { /* Widget A specific logic */ }
// b-widget.js
import { sharedFunction } from "./shared.js";
export function render({ model, el }) { /* Widget B specific logic */ }
Thanks. That's what I'm doing now. Guess I'll continue down that path.
For reference, the motivation is partly due to VS Code and how convoluted loading JS files for widgets is there (https://github.com/microsoft/vscode-jupyter/wiki/Component:-IPyWidgets#loading-3rd-party-source), so just the one fetch for my collection of widgets would have been preferred, but that's not a blocker, and not your issue to solve :-)
Ah ok I see, great to know the use case! Thanks for understanding.
Unfortunately a current hard limitation of anywidget is that a widget entry-point cannot use relative imports. This means that widgets must be bundled separately, even if they share dependencies. With full ESM support, in theory the above could work without a bundler at all (and there would only be one browser request for shared.js
). I've been thinking for some time about whether we could support writing fully ESM natively, but have yet to come up with a solution due to the differences in where the ESM is served (i.e., in Jupyter vs JupyterLab vs Colab).
Love the project. Thanks for building it!
I have a number of components that will share code, but I still want to ideally ship one .js file containing my components (and their shared code). Being that anywidget expects the Python class for a Widget to contain something like
_esm = pathlib.Path("index.js")
and for that file to export arender
function, that doesn't seem possible however.Would it be possible to be able configure the render function to use from the esm module, e.g.
_esm_renderer = "render_Foo"
for example. (Or something more elegant). That way I could have multiple components use the same .js file but use a different renderer function for each.