Repository: bokeh/bokeh

Issue:
All gallery examples bundle unnecessary extension code
All the gallery examples have the code for ion range slider, surface3d, etc. Perhaps we will need to run every export for the gallery in a separate process to avoid this. Alternatively, is there an easy way to clear out any custom models that the sphinx extension could do between exports?

cc @mattpap 


Discussion:
Process isolation slows things down considerably as you might expect, also was still not able to get it work yet given the need for a global resources object in the html page context. However, I think the issue is may simply be that `Resources` just always unconditionally returns all js files currently, even in a fresh interpreter:
```
base) ❯ ipython
Python 3.6.5 |Anaconda custom (64-bit)| (default, Mar 29 2018, 13:14:23)
Type 'copyright', 'credits' or 'license' for more information
IPython 6.3.1 -- An enhanced Interactive Python. Type '?' for help.

In [1]: from bokeh.resources import Resources

In [2]: resources = Resources(mode="server", root_url="/en/latest/")

In [3]: resources.components('js')
Out[3]: ['bokeh', 'bokeh-widgets', 'bokeh-tables', 'bokeh-gl']
```
So, to be clear, there are actually two issues:

* custom extension code is getting included, even when it is not used

* all standard js/css files are getting rendered, even when only `bokeh.min.js`, etc is only needed

As a quick test, this diff:
```
diff --git a/bokeh/resources.py b/bokeh/resources.py
index bd657112b..c15e9064e 100644
--- a/bokeh/resources.py
+++ b/bokeh/resources.py
@@ -318,7 +318,7 @@ class JSResources(BaseResources):

     '''

-    _js_components = ["bokeh", "bokeh-widgets", "bokeh-tables", "bokeh-gl"]
+    _js_components = ["bokeh"] #, "bokeh-widgets", "bokeh-tables", "bokeh-gl"]

     @property
     def js_files(self):
```
causes only `bokeh.min.js` to be rendered, which works for the earliest plots in the docs, but fails as soon as the extension examples are renderered, since they require widgets. And fails for any plots after that, since the extension code is included in all subsequent plots. 
just running an `output_file`/`show` type example does not include everything, so I think this problem is specific to `autoload_static`, and possibly `components` since it also uses `bundle_all_models`
This sounds correct. We include all bundles when we can't predict what will be used.
@mattpap how is that the case here? Both `autoload_static` and `components` are passed a doc or a set of models and that should determine what is needed completely unless I am missing something.

As for the extensions, doing this before each plot seems to fix as I would expect:
```

+    Model.model_class_reverse_map = {
+        k:v for k,v in Model.model_class_reverse_map.items() 
+        if getattr(v, "__implementation__", None) is None
+    }
+
```
So is the best immediate thing to add a `Model.clear_extensions` under test? That could be used immediately by the sphinx ext (or advanced users) then hopefully later we could find a way to make it unnecessary. 

Resolving patch:
diff --git a/bokeh/model.py b/bokeh/model.py
--- a/bokeh/model.py
+++ b/bokeh/model.py
@@ -561,6 +561,13 @@ def _attach_document(self, doc):
         self._document = doc
         self._update_event_callbacks()
 
+    @staticmethod
+    def _clear_extensions():
+        MetaModel.model_class_reverse_map = {
+            k:v for k,v in MetaModel.model_class_reverse_map.items()
+            if getattr(v, "__implementation__", None) is None
+        }
+
     def _detach_document(self):
         ''' Detach a model from a Bokeh |Document|.
 
diff --git a/bokeh/sphinxext/bokeh_plot.py b/bokeh/sphinxext/bokeh_plot.py
--- a/bokeh/sphinxext/bokeh_plot.py
+++ b/bokeh/sphinxext/bokeh_plot.py
@@ -82,6 +82,7 @@
 
 from ..document import Document
 from ..embed import autoload_static
+from ..model import Model
 from ..resources import Resources
 from ..settings import settings
 from ..util.string import decode_utf8
@@ -119,6 +120,10 @@ def _process_script(source, filename, env, js_name, use_relative_paths=False):
     # This is lame, but seems to be required for python 2
     source = CODING.sub("", source)
 
+    # Explicitly make sure old extensions are not included until a better
+    # automatic mechanism is available
+    Model._clear_extensions()
+
     # quick and dirty way to inject Google API key
     if "GOOGLE_API_KEY" in source:
         GOOGLE_API_KEY = getenv('GOOGLE_API_KEY')


Test patch: