"Pre-built extensions" without bokeh server

Hello,
I have been happily using the very nice inline Bokeh extension mechanism, but I have gotten to the point where I want to have two classes derived from ColumnDataSource share a common third class derived from DataSource. So I’ve embarked on the path set out in pre-built extensions. I haven’t gotten there yet, but I am beginning to wonder if prebuilt extensions are only useful if the Bokeh server is used? If they can be used with just web-browser plotting, what hook is used to load the pre-built extension so that it can be referenced from the Python classes? In other words, once I have the extension, how do I use it?

Does anyone know if this is the case? In my case, the Bokeh Python functions are called from the user’s python session, so no Bokeh server is available.

Thanks very much for any advice!

cc @Philipp_Rudiger @mateusz can one of you comment?

Thanks for your help @Bryan Below is the solution I came up with (some time ago!). It seems to work well but does introduce some dependencies on BokehJS internals. The idea is that a call like:

initialize_bokeh( )

or if using the local development build of the library, like:

initialize_bokeh( “mylibraryjs/dist/mylibraryjs.min.js” )

is made at startup.

It would be nice if something similar (but generic) could be provided as part of the standard API.

version = "0.0.3"
...
@static_vars(initialized=False)
def initialize_bokeh( libs=None, dev=0 ):
    """Initialize `bokeh` for use with the ``mylibraryjs`` extensions.

    The ``mylibraryjs`` extensions for Bokeh are built into a stand-alone
    external JavaScript file constructed for the specific version of
    Bokeh that is being used. The URL or the local path to a locally
    built verion must be supplied as the ``libs`` parameter. If ``libs``
    is ``None`` then the default is to use the published verison of
    ``mylibraryjs`` extensions built and installed for `HTTP` access.

    Parameters
    ----------
    libs: None or str or list of str
        javascript library to load could be a local path, a URL or None.
        None is the default in which case it loads the published library
        for the current version of ``mylibraryjs`` and ``bokeh``
    dev: int, optional
        Chrome caches the javascript files. This parameter allows for
        specifying `dev` allows for including a development version
        for incremental updates to JavaScript from website.
    """

    if initialize_bokeh.initialized:
        ### only initialize once...
        return

    library_hashes = {
        ### --------------------------------------------------------------------------------------------------
        ### Generate hashes with:
        ### echo `cat mylibraryjs-v0.0.2.0-b2.3.js | openssl dgst -sha384 -binary | openssl base64 -A`
        ### ---  ---  ---  ---  ---  ---  ---  ---  ---  ---  ---  ---  ---  ---  ---  ---  ---  ---  ---  ---
        ### NOTE: with the conversion from Bokeh 2.3.3 to 2.4.1, it seems that the security hashes are no
        ### longer included in the generated HTML.
        ### --------------------------------------------------------------------------------------------------
        'mylibraryjs-v0.0.2.0-b2.3.js': 'EtB9H3ooIK3inPGx9RsRXeUv/COHtArEjhZUr7P75GBUPl+lAoGH/tqoAc1sV5jD',
        'mylibraryjs-v0.0.2.0-b2.3.min.js': 'jAFFXRC9B93jSanS1dmqo+l/3rkcBqM48uTMN+SFcY7GPC/IPeEoI+p+Za5ztkcm',
        'mylibraryjs-v0.0.3.0-b2.4.min.js': '23DOS7ISXIG8BRyIsD7vINUllDbo8NDCozIGBy7jGC+M14Z+axfF7j4bruA2ZnzL',
        'mylibraryjs-v0.0.3.0-b2.4.js': 'OmIWKy37YXZf973kemdoFd2L/h0I9AY/hsP5PMdk5/g5xlgj16yk6b0cgO01UMxM'
    }

    mylib = None
    mylibraryjs_libs = None
    mylibraryjs_url = None

    if libs is None:
        mylib = "mylibraryjs-v%s.%d-b%s.min.js" % (version,dev,'.'.join(bokeh_version.split('.')[0:2]))
        mylibraryjs_url = "https://example.com/download/javascript/mylibraryjs/%s/%s" % (version,mylib)
        mylibraryjs_libs = [ mylibraryjs_url ]
    else:
        mylibraryjs_libs = [ libs ] if type(libs) == str else libs
        mylibraryjs_libs = list(map( path_to_url, mylibraryjs_libs ))

    from bokeh import resources
    resources.JSResources._old_hashes = resources.JSResources.hashes
    def hashes( self ):
        result = self._old_hashes
        if mylib is not None and mylib in library_hashes:
            result[mylibraryjs_url] = library_hashes[mylib]
        return result

    resources.JSResources._old_js_files = resources.JSResources.js_files
    def js_files( self ):
        result = self._old_js_files
        result = result + mylibraryjs_libs
        return result

    resources.JSResources.hashes = property(hashes)
    resources.JSResources.js_files = property(js_files)
    initialize_bokeh.initialized = True