Back
Apr 3, 2011

Sprite cache invalidation

When we use css-sprites it's important to make browser cache them for longest period possible. On other hand, we need to refresh them when they are updated. This is especially visible when all icons are stored in single sprite. When it's outdated - entire site becomes ugly.

To solve this task I've implemented this small script that adds file's hash to url:

background-image: url(images/icons.png);
background-image: url(images/icons.png?a3844c660);
#!/usr/bin/python

import os.path
import re
import hashlib


def file_hash(filename, block_size=2**20):
    md5 = hashlib.md5()
    with open(filename, 'rb') as f:
        for data in iter(lambda: f.read(block_size), ''):
            md5.update(data)
    return md5.hexdigest()


def find_replace(match, basedir):
    match = match.replace("'", '')
    if '?' in match or '#' in match or match.startswith('http://'):
        print 'skipping: ', match
        return None

    filename = os.path.join(basedir, match)
    return '%s?%s' % (match, file_hash(filename)[:10])


def insert_hash(filename, debug=False):
    basedir = os.path.dirname(filename)
    css = open(filename).read()
    matches = re.findall(r"url\((.*?)\)", css)
    replacements = dict([
        (match, find_replace(match, basedir))
        for match in matches
    ])

    if debug:
        for key, value in replacements.iteritems():
            print key, '    =>    ', value
    else:
        for match, repl in replacements.iteritems():
            if repl:
                css = css.replace(match, repl)

        out = open(filename, 'w')
        out.write(css)
        out.close()


if __name__ == '__main__':
    from optparse import OptionParser
    usage = 'usage: %prog filename.css'

    parser = OptionParser(usage=usage)
    parser.add_option("", "--debug", action="store_true", dest="debug", default=False,
                      help="When set, just output list of substitutions.")

    (options, args) = parser.parse_args()

    if len(args) < 1:
        print 'You must provide file name.'

    insert_hash(os.path.realpath(args[0]), options.debug)

Update

This is pretty old article. Now it's better to use something integrated to your build process - grunt, webassets, etc.

Subscribe for the news and updates

More thoughts
Jul 13, 2022Technology
Prosemirror: Render node as react component

In this article I’m going to show how to declare custom prosemirror node, how to render it with toDom method and how improve that with custom NodeView using React component.

Mar 2, 2017Technology
API versioning with django rest framework?

We often handling API server updates including backwards-incompatible changes when upgrading web applications. At the same time we update the client part, therefore, we did not experience any particular difficulties.

Aug 8, 2016TechnologyBusiness
How To Add HTML5 Geolocation To Your Web App?

In this article I will describe how to integrate geolocation HTML5 function to a web app so you can then easily implement it in your apps or websites. As an example we are going to create small web app which will be able to calculate the shortest route between detected user’s location and predefined destination using Google Maps API.

May 12, 2010Technology
Twitter API, OAuth and decorators

In my current project I had a task to use twitter API. Twitter uses OAuth for authentication, which is pretty dreary. To avoid fiddling with it all the time, I've moved authentication to decorator. If key is available - nothing happens, just view is launched as usual. It's convenient that there's no need for additional twitter settings in user profile. Code is in article.

Mar 6, 2010Technology
Ajax form validation

There was a task to submit form with ajax, with server side validation of course. Obvious solution is to do validation and return json with erros. I didn't like idea of writing separate view for validation and then inserting errors in form html on client side. Especially since I already had a generic template for django form with errors display. In this article I'll describe how I solved the task.

Feb 18, 2010Technology
Business logic in models

In my recent project there was a lot of data business logic, so I had to organize this code somehow. In this article I'll describe a few hints on how to it.