# Rendering custom widgets: \`Bokeh.register\_plugin is not a function\`

**URL:** <https://discourse.bokeh.org/t/rendering-custom-widgets-bokeh-register-plugin-is-not-a-function/6637>\
**Category:** Community Support\
**Tags:** customjs, bokehjs\
**Created:** [October 30, 2020, 9:29am UTC](https://discourse.bokeh.org/t/rendering-custom-widgets-bokeh-register-plugin-is-not-a-function/6637 "2020-10-30T09:29:13Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![stefanv](https://discourse.bokeh.org/user_avatar/discourse.bokeh.org/stefanv/32/2815_2.png) [@stefanv](https://discourse.bokeh.org/u/stefanv)\
**Post date:** [October 30, 2020, 9:29am UTC](https://discourse.bokeh.org/t/rendering-custom-widgets-bokeh-register-plugin-is-not-a-function/6637/1 "2020-10-30T09:29:13Z")

</div>

Hi everyone,

I am in the process of upgrading an application from Bokeh 0.12 (!) to 2.2.3.

I have defined a custom widget, which compiles correctly. On the backend, I generate a Bokeh document and export it in two parts: as JSON (using `bokeh_embed.json_item`) and JavaScript (for our custom models, using `bundle_models`). On the frontend, I then do the following:

```auto
import * as Bokeh from "@bokeh/bokehjs";

const { bokehJSON, modelJS } = plotData;

window.Bokeh = Bokeh;
const root = { Bokeh: window.Bokeh };
eval(modelJS.replace("this", "root"));

Bokeh.embed.embed_item(bokehJSON, `bokeh-${bokehJSON.root_id}`);

```

(The `bokeh-xyz` div is created elsewhere in the code.)

A similar scheme worked under 0.12, but now I see the following error:

```auto
Bokeh.register_plugin is not a function

```

I am curious whether:

1. I am trying to do something I am not supposed to (export JSON + JS and render on frontend);
2. importing Bokeh the way I am is supported; and
3. if so, whether exposing `register_plugin` would be an option?

Thank you for your advice!

---

<div class="post-metadata">

**Author:** ![Bryan](https://discourse.bokeh.org/user_avatar/discourse.bokeh.org/bryan/32/3625_2.png) [@Bryan](https://discourse.bokeh.org/u/Bryan)\
**Post date:** [October 30, 2020, 4:52pm UTC](https://discourse.bokeh.org/t/rendering-custom-widgets-bokeh-register-plugin-is-not-a-function/6637/2 "2020-10-30T16:52:59Z")

</div>

@Philipp_Rudiger how does hv/panel register or inject its extensions? also cc @mateusz

---

<div class="post-metadata">

**Author:** ![stefanv](https://discourse.bokeh.org/user_avatar/discourse.bokeh.org/stefanv/32/2815_2.png) [@stefanv](https://discourse.bokeh.org/u/stefanv)\
**Post date:** [October 30, 2020, 7:48pm UTC](https://discourse.bokeh.org/t/rendering-custom-widgets-bokeh-register-plugin-is-not-a-function/6637/3 "2020-10-30T19:48:57Z")

</div>

Looking at the Panel source code, it looks like they use:

```auto
import * as Panel from "./models"
export {Panel}

import {register_models} from "@bokehjs/base"
register_models(Panel as any)

```

I don’t have my models defined externally, although that is a route I can investigate. It would be useful to be able to register models written in Python in ` __implementation__ ` clauses, though.

---

<div class="post-metadata">

**Author:** ![mateusz](https://discourse.bokeh.org/user_avatar/discourse.bokeh.org/mateusz/32/762_2.png) [@mateusz](https://discourse.bokeh.org/u/mateusz)\
**Post date:** [October 30, 2020, 10:30pm UTC](https://discourse.bokeh.org/t/rendering-custom-widgets-bokeh-register-plugin-is-not-a-function/6637/4 "2020-10-30T22:30:49Z")

</div>

> `import * as Bokeh from "@bokeh/bokehjs";`

`@bokeh/bokehjs` is a non-module JS bundle (it has no exports), so `Bokeh` will be `{}` (give or take; assuming webpack is being used to package things, there may be some webpack’s cruft there). However, `window.Bokeh` (well, global `Bokeh`) should be set up properly nevertheless. So, this:

> `window.Bokeh = Bokeh;`

is definitively not necessary.

> `const root = { Bokeh: window.Bokeh };`  
> `eval(modelJS.replace("this", "root"));`

If bokeh generated `modelJS` and you are issuing `Bokeh.embed.embed_item()`, then you are doing the work twice, because bokeh’s generated JS boils down to calling `embed_item()`.

---

<div class="post-metadata">

**Author:** ![stefanv](https://discourse.bokeh.org/user_avatar/discourse.bokeh.org/stefanv/32/2815_2.png) [@stefanv](https://discourse.bokeh.org/u/stefanv)\
**Post date:** [October 30, 2020, 11:11pm UTC](https://discourse.bokeh.org/t/rendering-custom-widgets-bokeh-register-plugin-is-not-a-function/6637/5 "2020-10-30T23:11:47Z")

</div>

@mateusz Thank you for your response.

I am confused, though: as I wrote, I use `bokeh_embed.json_item` and `bundle_models`, e.g.:

```auto
const modelJSON = bokeh_embed.json_item(tabs);
const modelJS = bundle_models([CheckboxWithLegendGroup]);

```

I don’t see how to skip one of the above and how to only apply the other. If I try _not_ to call `modelJS`, then it complains that my custom model (`CheckboxWithLegendGroup`) has not been registered.

---

<div class="post-metadata">

**Author:** ![mateusz](https://discourse.bokeh.org/user_avatar/discourse.bokeh.org/mateusz/32/762_2.png) [@mateusz](https://discourse.bokeh.org/u/mateusz)\
**Post date:** [October 31, 2020, 12:19am UTC](https://discourse.bokeh.org/t/rendering-custom-widgets-bokeh-register-plugin-is-not-a-function/6637/6 "2020-10-31T00:19:54Z")

</div>

> (…) and `bundle_models`

I didn’t register that part. So, this should work:

```ts
import "@bokeh/bokehjs";

const { bokehJSON, modelJS } = plotData;
eval(modelJS);
Bokeh.embed.embed_item(bokehJSON, `bokeh-${bokehJSON.root_id}`)

```

Essentially you’re replacing a `<script>` tag with an import, but the rest of the code is the same in both cases. Not ideal, but I don’t think we can get anything better right now (at least not without improving bokeh and/or bokehjs).

---

<div class="post-metadata">

**Author:** ![mateusz](https://discourse.bokeh.org/user_avatar/discourse.bokeh.org/mateusz/32/762_2.png) [@mateusz](https://discourse.bokeh.org/u/mateusz)\
**Post date:** [October 31, 2020, 12:28am UTC](https://discourse.bokeh.org/t/rendering-custom-widgets-bokeh-register-plugin-is-not-a-function/6637/7 "2020-10-31T00:28:05Z")

</div>

Actually that’s not going to work because we define the scope of a model bundle as `this`, which will be bound to local module scope in this case, instead of the global scope. Try this instead:

```auto
import "@bokeh/bokehjs";

const { bokehJSON, modelJS } = plotData;
Function(modelJS).bind(window)();
Bokeh.embed.embed_item(bokehJSON, `bokeh-${bokehJSON.root_id}`)

```

---

<div class="post-metadata">

**Author:** ![stefanv](https://discourse.bokeh.org/user_avatar/discourse.bokeh.org/stefanv/32/2815_2.png) [@stefanv](https://discourse.bokeh.org/u/stefanv)\
**Post date:** [November 2, 2020, 10:02pm UTC](https://discourse.bokeh.org/t/rendering-custom-widgets-bokeh-register-plugin-is-not-a-function/6637/8 "2020-11-02T22:02:40Z")

</div>

Thanks, @mateusz

In this configuration, I will have to include Bokeh via a script tag, I presume? Otherwise, I see:

```auto
Uncaught Error: Cannot find Bokeh. You have to load it prior to loading plugins.

```

---

<div class="post-metadata">

**Author:** ![stefanv](https://discourse.bokeh.org/user_avatar/discourse.bokeh.org/stefanv/32/2815_2.png) [@stefanv](https://discourse.bokeh.org/u/stefanv)\
**Post date:** [November 4, 2020, 4:55am UTC](https://discourse.bokeh.org/t/rendering-custom-widgets-bokeh-register-plugin-is-not-a-function/6637/9 "2020-11-04T04:55:59Z")

</div>

For completeness, what I see on the `import * as Bokeh from "@bokeh/bokehjs";` statement is everything from `index.js`:

```auto
export { version } from "./version";
export { index } from "./embed";
export * as embed from "./embed";
export * as protocol from "./protocol";
export * as _testing from "./testing";
export { logger, set_log_level } from "./core/logging";
export { settings } from "./core/settings";
export { Models } from "./base";
export { documents } from "./document";
export { safely } from "./safely";

```

But `register_plugins` is not included there.

---

<div class="post-metadata">

**Author:** ![stefanv](https://discourse.bokeh.org/user_avatar/discourse.bokeh.org/stefanv/32/2815_2.png) [@stefanv](https://discourse.bokeh.org/u/stefanv)\
**Post date:** [November 6, 2020, 12:50am UTC](https://discourse.bokeh.org/t/rendering-custom-widgets-bokeh-register-plugin-is-not-a-function/6637/10 "2020-11-06T00:50:35Z")

</div>

I managed to solve my problem as follows:

1. Moved custom models into a separate file, `BokehModels.js`. Since I am not using TypeScript, I had to translate my custom model from TypeScript to JavaScript.
2. Inside my JavaScript plotting component, I do:

```auto
import * as Bokeh from "@bokeh/bokehjs";
import * as Models from "./BokehModels"; // my custom models

// `plotData` is shipped to the frontend by my Python backend
// which generates it with `bokeh_embed.json_item(layout)`
const { bokehJSON } = plotData;

Bokeh.Models.register_models(Models);
window.Bokeh = Bokeh;
Bokeh.embed.embed_item(bokehJSON, `bokeh-${bokehJSON.root_id}`);

```

The full set of changes can be seen in my [pull request to SkyPortal](https://github.com/skyportal/skyportal/pull/1293/files).

Thank you to the Panel project, whose source code provided me with a route to the solution.

---

<div class="post-metadata">

**Author:** ![system](https://discourse-uploads.bokeh.org/original/2X/1/14eb24f9e10e4e9b78e3f10f66c04ffa96446e5a.svg) [@system](https://discourse.bokeh.org/u/system)\
**Post date:** [July 21, 2021, 9:29pm UTC](https://discourse.bokeh.org/t/rendering-custom-widgets-bokeh-register-plugin-is-not-a-function/6637/11 "2021-07-21T21:29:34Z")

</div>


