pythonhtmlhashbokehno-cache

How to add hash strings to custom resources urls in a Bokeh Application?


I am programming a Bokeh Server Application with templates. I have added some custom CSS and JS files. But when I make some changes the files are reloaded from the cache and I cannot see the new changes. One solution is to add a variable at the end of the URL in order to load them from scratch just if there were some changes. Bokeh resources work like that.

I have added the resources as in this example so far

{% extends base %}

<!-- goes in head -->
{% block preamble %}
    <link href="app/static/css/custom.min.css" rel="stylesheet">
    <script type="text/javascript" src="app/static/js/custom.min.js"></script>
{% endblock %}

<!-- goes in body -->
{% block contents %}
    <div> {{ embed(roots.scatter) }} </div>
    <div> {{ embed(roots.line) }} </div>
{% endblock %}

Is there a builtin way to add these hashes? The result I would like to have is:

<link href="app/static/css/custom.min.css?v=f5ee62ee57a37d94c35e8f7be218e11fc63df459" rel="stylesheet">

This hash string must be added before the page is loaded to make it work well

I found this class, but it seems just for Bokeh resources


Solution

  • Bokeh uses Jinja2 templates but it doesn't provide any access to template variables. One of possible workarounds is to create a custom template class:

    from hashlib import md5
    
    from jinja2 import Template
    
    from bokeh.io import save
    from bokeh.models import Div
    
    
    class ExtendedTemplate(Template):
        def render(self, *args, **kwargs):
            if 'with_hash' not in kwargs:
                kwargs['with_hash'] = with_hash
            return super().render(*args, **kwargs)
    
    
    t = ExtendedTemplate("""\
    <link href="{{ with_hash('app/static/css/custom.min.css') }}" rel="stylesheet">
    """)
    
    
    def with_hash(s):
        with open(s, 'rb') as f:
            return f'{s}?v={md5(f.read()).hexdigest()}'
    
    
    save(Div(), template=t)
    

    Note that this particular code assumes that the CSS file's path is accessible from its current working directory.