Repository: bokeh/bokeh

Issue:
Load multiple versions of Bokeh into a single web page
**Is your feature request related to a problem? Please describe.**

I maintain an open-source webapp [[link]](https://compute.studio/PSLmodels/Tax-Cruncher/333/) where you can run models and archive the results from your model runs. Many of the archived results are bokeh plots. I need a way to render archived Bokeh plots that were created with Bokeh version 1.4.0 or earlier, and I need to render new plots that are created with Bokeh 2.0. and newer.

**Describe the solution you'd like**

I would like a function that is similar to JQuery's [`noConflict()`](https://api.jquery.com/jQuery.noConflict/) function for Bokeh that would work like the code in this [Stack Overflow post](https://stackoverflow.com/questions/1566595/can-i-use-multiple-versions-of-jquery-on-the-same-page):

```html
<!-- load jQuery 1.1.3 -->
<script type="text/javascript" src="http://example.com/jquery-1.1.3.js"></script>
<script type="text/javascript">
var jQuery_1_1_3 = $.noConflict(true);
</script>

<!-- load jQuery 1.3.2 -->
<script type="text/javascript" src="http://example.com/jquery-1.3.2.js"></script>
<script type="text/javascript">
var jQuery_1_3_2 = $.noConflict(true);
</script>
```

**Describe alternatives you've considered**
I've considered reformatting archived results to meet the new API, but this doesn't seem like a sustainable solution. What do I do for future breaking changes or if it is not possible to reformat the archived results to meet the new API?

Another option is to set the correct Bokeh version in the HTML template when it is rendered on the server side. However, since the JSON output objects take some time to download from cloud storage, they are loaded dynamically after the page is rendered. This means that I'd have to reload the page if the Bokeh version for the outputs is mismatched. This isn't the end of the world, but it is a little clunky.

I've also begun implementing a one-off, quick-fix solution for my project that looks like this:

```HTML
  <script type="text/javascript" src="https://cdn.pydata.org/bokeh/release/bokeh-1.3.4.min.js"></script>
  <script type="text/javascript" src="https://cdn.pydata.org/bokeh/release/bokeh-widgets-1.3.4.min.js"></script>
  <script type="text/javascript">
    var Bokeh134 = window.Bokeh;
  </script>

  <script type="text/javascript" src="https://cdn.pydata.org/bokeh/release/bokeh-2.0.0.min.js"></script>
  <script type="text/javascript" src="https://cdn.pydata.org/bokeh/release/bokeh-widgets-2.0.0.min.js"></script>
  <script type="text/javascript">
    var Bokeh200 = window.Bokeh;
  </script>
```

```js
const BokehComponent: React.FC<{ output: BokehOutput }> = ({ output }) => {
  // @ts-ignore
  let bokeh = window.Bokeh134;
  // @ts-ignore
  if (output.data.doc.version === "2.0.0") {
    // @ts-ignore
    bokeh = window.Bokeh200;
  }
  console.log(bokeh);
  // @ts-ignore
  bokeh.embed.embed_item(output.data, output.id);
  return <div id={output.id} data-root-id={output.id} className="bk-root"></div>;
};
```

**Additional context**
@bryevdv discussed this with me in this discourse [thread](https://discourse.bokeh.org/t/archived-bokeh-plots-and-upgrades/4977) and suggested that I open an issue.

Also, if the Bokeh project is interested in this feature, then I'd be happy to help implement it. Thanks in advance for taking a look at this.



Discussion:
This would be a useful feature, but this proposal would make it usable only from bokehjs. It would be better to have this work in general across all bokeh's embedding types. I've been contemplating a solution where only the first instance would store `global.Bokeh` and all instances would store `global.Bokeh[version]`. This would be done on bokeh's bundle logic level, and should cover all cases. Though it would be also good to provide a solution for users who repack bokehjs' bundles with webpack, etc.
@mattpap Thanks for your reply! So I can get up to speed, what are the other embedding types? 

> I've been contemplating a solution where only the first instance would store global.Bokeh and all instances would store global.Bokeh[version].

For my use case, does this mean that I could access version 2.0 at `window.Bokeh["2.0.0"]`? Would the additional bokeh instances store a reference to themselves at `window.Bokeh["x.y.z"]`?

> This would be done on bokeh's bundle logic level, and should cover all cases.

I'm pretty new to javascript. Can you elaborate a little more on what it means to do this at the bundle level?

Resolving patch:
diff --git a/bokeh/io/export.py b/bokeh/io/export.py
--- a/bokeh/io/export.py
+++ b/bokeh/io/export.py
@@ -362,7 +362,7 @@ def _maximize_viewport(web_driver: "WebDriver") -> Tuple[int, int, int]:
   window._bokeh_render_complete = true;
 }
 
-var doc = window.Bokeh.documents[0];
+var doc = Bokeh.documents[0];
 
 if (doc.is_idle)
   done();
diff --git a/release/git.py b/release/git.py
--- a/release/git.py
+++ b/release/git.py
@@ -10,6 +10,7 @@
 import re
 from os.path import abspath, dirname, join, pardir
 from subprocess import CalledProcessError
+from typing import List
 
 # External imports
 from packaging.version import Version as V
@@ -124,12 +125,9 @@ def update_changelog(config: Config, system: System) -> None:
 
 
 def update_bokehjs_versions(config: Config, system: System) -> None:
+    regex_filenames: List[str] = []
 
-    regex_filenames = [
-        "bokehjs/src/lib/version.ts",
-    ]
-
-    json_filenames = [
+    json_filenames: List[str] = [
         "bokehjs/package.json",
         "bokehjs/package-lock.json",
     ]


Test patch:
diff --git a/bokehjs/make/tasks/test.ts b/bokehjs/make/tasks/test.ts
--- a/bokehjs/make/tasks/test.ts
+++ b/bokehjs/make/tasks/test.ts
@@ -103,7 +103,7 @@ function bundle(name: string): void {
     cache: join(paths.build_dir.test, `${name}.json`),
     transpile: "ES2017",
     externals: [/^@bokehjs\//],
-    prelude: default_prelude({global: "Tests"}),
+    prelude: () => default_prelude({global: "Tests"}),
     shims: ["fs", "module"],
   })