anywidget icon indicating copy to clipboard operation
anywidget copied to clipboard

`export` WidgetWrapper / allow app plugins as argument to `createRender`

Open ntjess opened this issue 4 months ago • 3 comments

Describe the problem

Using primevue requires app plugins for theming and optionally the toast service. Typically this is done as:

import PrimeVue from "primevue/config";
import ToastService from "primevue/toastservice";

app = createApp(Component);
app.use(PrimeVue);
app.use(ToastService);
app.mount(...);

However, since @anywidget/vue directly creates -> mounts the app, we have no way to hook into the plugin ecosystem.

We can't even redeclare WidgetWrapper from the calling scope, since the unique RENDER_CONTEXT_KEY Symbol means the inject/provide won't match up. So (I think) the only solution is to paste the entire contents of @anywidget/vue/index.js in the calling code, and add the plugins from the new createRender.

Describe the proposed solution

If WidgetWrapper was exported, the calling code would only need to redefine createRender, which is a much smaller task.

Alternatively, createRender could take a list of middleware (or transformer/etc) as an input argument that would be called with app before mounting.

Importance

would make my life easier

ntjess avatar Aug 13 '25 02:08 ntjess

Thanks for flagging — I’m not super familiar with Vue either, but I think I get the issue. Exporting WidgetWrapper sounds like one option, though maybe something like a use: or enhanceApp: hook could work too, e.g.:

createRender(widget, {
  use: [PrimeVue, ToastService],
});

Any thoughts? @aryan02420

manzt avatar Nov 11 '25 19:11 manzt

Thanks for looping me in!

Vue’s application instance exposes several extension APIs like app.component() and app.directive(). Moreover, app.use(Plugin, options) can also take an additional arg for plugin options. Considering this, we might want a general mechanism that supports all these patterns instead of just use:.

Building on @manzt idea for enhanceApp and @ntjess idea of transformers, I suggest we could expose the entire app instance through a callback passed to createRender, which would make the API both flexible and familiar to Vue users. For example:

createRender(widget, (app) =>
  app.use(PrimeVue).use(ToastService)
);

And the implementation could look something like:

export function createRender(Widget, enhanceApp) {
  return ({ el, model, experimental }) => {
    const app = createApp(h(WidgetWrapper, { model, experimental }, h(Widget)));
    enhanceApp?.(app);
    app.mount(el);

    return () => app.unmount();
  };
}

We could also export WidgetWrapper and RENDER_CONTEXT_KEY, in case someone wants that extra bit of flexibility.

aryan02420 avatar Nov 12 '25 07:11 aryan02420

My 2 cents is that createRender is a small enough function that it doesn't make too much sense to augment it substantially. I'd be more in favor of e.g. renaming it to createBasicRender (if desired), and exporting WidgetWrapper and RENDER_CONTEXT_KEY for anything more. I'm happy to add a docs example demonstrating PrimeVue integration in a custom createRender to bridge the gap

ntjess avatar Nov 13 '25 14:11 ntjess