Search code examples
javascriptcsscachingpython-sphinxbrowser-cache

How to force custom js/css files in Sphinx to always load changes without caching?


In Sphinx's conf.py I have:

html_css_files = ['css/custom.css']
html_js_files = ['js/custom.js']

However if I make any change in custom.js or custom.css then this change does not reflect to in the user's browser unless http://www.example.com/_static/js/custom.js is forcefully reloaded on the client (similarly for CSS).

How can I force the custom CSS + JS to never cache on the user's browser?


Solution

  • For newer Sphinx (> v7.2.0?)

    Builds with the below solution in them are now failing with:

    Reason: ThemeError("Local asset file paths must not contain query strings: '_static/custom.css?v=12345678'")

    According to bug reports this also broke builds with several other large projects like MathJax, NumPy, Gentoo & bokee.

    According to a Sphinx contributor, the reason is that Sphinx should now natively handle cache busting via a content checksum, meaning that manual cache busting no longer needs to be done (per the guide below).

    For older Sphinx (<= v7.2.0?)

    Although the config file looks like it only accepts normal string values, it is really just a Python script, so we can import and use functions such as a random number generator.

    At the top of conf.py add this line:

    from secrets import token_urlsafe
    

    Change your custom CSS + JS to:

    html_css_files = [f'css/custom.css?v={token_urlsafe(8)[:8]}']
    html_js_files = [f'js/custom.js?v={token_urlsafe(8)[:8]}']
    

    This will make your custom CSS + JS files load like the vanilla CSS + JS files, with a random 8-character slug at the end - thus disabling caching:

    <!-- Sphinx vanilla CSS: -->
    <link rel="stylesheet" type="text/css" href="../_static/pygments.css?v=80d5e7a1" />
    <link rel="stylesheet" type="text/css" href="../_static/css/theme.css?v=19f00094" />
    <link rel="stylesheet" type="text/css" href="../_static/copybutton.css?v=76b2166b" />
    
    <!-- Our custom CSS now has a random slug, like vanilla: -->
    <link rel="stylesheet" type="text/css" href="../_static/css/custom.css?v=Rdy7RNCQ" />
    
    <!-- Sphinx vanilla JS: -->
    <script src="../_static/jquery.js?v=5d32c60e"></script>
    <script src="../_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
    <script data-url_root="../" id="documentation_options" src="../_static/documentation_options.js?v=e91dff3d"></script>
    <script src="../_static/doctools.js?v=888ff710"></script>
    <script src="../_static/sphinx_highlight.js?v=4825356b"></script>
    <script src="../_static/clipboard.min.js?v=a7894cd8"></script>
    <script src="../_static/copybutton.js?v=f281be69"></script>
    
    <!-- Our custom JS now has a random slug, like vanilla: -->
    <script src="../_static/js/custom.js?v=8QronLhw"></script>
    

    Note that if you're running Sphinx in Docker then the ?v=xxxxxxxx slug will not change unless you run your docker build with the --no-cache option.