Cache Busting Images Which Are Linked Inside SASS Files

Cache busting images which are linked inside SASS files

Using the answer from @Amo for inspiration, the solution I ended up using was a mixin, which makes use of the unique_id() function to generate a random value. This avoids having to define a custom SASS function, so it's simpler and as @Amelia pointed out, a bit cleaner too.

The mixin

@mixin background-cache-bust($url) {
background-image: #{'url('} + $url + #{'?v='} + unique_id() + #{')'};
}

Example

.sprite {
@include background-cache-bust('/build/images/common/sprite.png');
}

Result

.sprite {
background-image: "url(/build/images/common/sprite.png?v=u95ab40e0)";
}

Cache bust background images in my CSS with Gulp without having to edit my SASS?

The way I see it you have two options - both of which would use the hasher and cache busting plugins you listed:

  1. Write a gulp task that would automatically add ASSET{ ... } around all of the URLs in your CSS file. This would happen after concatenation and before hashing/busting. Since you have a bounty on this question, let me know if you would like me to write that task. I suggest you take a stab at it though b/c you might learn some neat things.

  2. Ideal solution: The cache busting plugin has an option for defining the regex to use to find assets. By default, the regex is set to /ASSET{(.*?)}/g, but you could easily update to something to match good ol' vanilla CSS url(...)s. Again, since you have a bounty let me know if you want help on the regex - but I suggest you take a stab at it b/c you might learn something neat (pssst, you want to ignore data: URLs).

    Try this regex in the cache bust config:

    /url\((?!['"]?data:)['"]?([^'"\)]*)['"]?\)/g

    If you want to ignore URLs which start with "http" (meaning they're hosted on another domain), then use the following regex. This assumes that all paths to your assets are relative, which they should be:

    /url\((?!['"]?(?:data|http):)['"]?([^'"\)]*)['"]?\)/g

    http://www.regexpal.com/?fam=94251

    If you want to be able to define the CSS attributes which will have hashed/busted URLs, you can use the following, which will only apply to URLs defined in background, background-image, and list-style CSS attributes. You can add more by adding a pipe | plus the name of the attribute after |list-style:

    /(?:background(?:-image)?|list-style)[\s]*:[^\r\n;]*url\((?!['"]?(?:data|http):)['"]?([^'"\)]*)/g

    http://www.regexpal.com/?fam=94252

bust cached CSS background-images with Grunt

Versioning the CSS files are unfortunately not good enough for Cache busting assets, this would force the browser to fetch the new CSS file itself from the server. But since the browser caches your CSS files and your images as separate items, you will need to bust the images/sprites as well separately.

When the image follows ? background-image: url(../img/some-sprite.png?version=20130205), the browser is forced to make a new request. This is important to notice that it DOES make a new request if the ? is found.

If you do have some special interest towards it - Read this article to get to know more about Cache busting in LESS

https://www.bennadel.com/blog/2643-cache-busting-css-images-with-less-css.htm


For Cache busting with only Gulp & not editing your SASS
follow this

You could also use numerous npm packages like gulp-cache-buster etc.


If you want cache busting in your SASS you could follow this

sass cache busting

Thanks Dawn for chiming in after all this time! I've since figured this out, but forgot I posted here about it.

I have a custom rb file that I reference when I run sass via the command line - like so:

sass --update sass:css -r file_mod.rb

in file_mod.rb, I have the following ruby function which does the trick:

require 'sass'

module GETMODINT
def file_url(staticFilePath,staticHost,filePath)
assert_type filePath, :String
filePath = filePath.value #get string value of literal
staticFilePath = staticFilePath.value
staticHost = staticHost.value
modtime = File.mtime(filePath).to_i
#Sass::Script::Number.new(modtime)

fileBaseName = File.basename filePath, '.*'
fileDir = File.dirname(filePath).sub(staticFilePath,'')
fileExt = File.extname(filePath)
path = "url('#{staticHost}#{fileDir}/#{fileBaseName}.#{modtime}#{fileExt}')"
return Sass::Script::String.new(path)
end
Sass::Script::Functions.declare :modInt, [:filePath]
end

module Sass::Script::Functions
include GETMODINT
end

Then, in a sass mixin, I simply reference the file_url function, passing it the parameters it needs to build the result:

@mixin backgroundImage($path, $position:0 0, $repeat:no-repeat) {
background: {
image:file_url($staticFilePath,$staticHost,$path);
position:$position;
repeat:$repeat;
}
}

In my case, I'm using it to construct a css background image path. Should be easily modified to suit other purposes.

How to use Sass in Django and versioning CSS and JS assets for cache busting

I use django_assets for this. For my CSS and SASS files, I use an assets.py file that looks like this:

css_bundle = Bundle(
'scss/main.scss',
depends=('scss/**/*.scss',),
filters='pyscss,cssmin',
output='compiled/main.min.css'
)

register('css_bundle', css_bundle)

Which I can then include in my templates like this:

{% assets "css_bundle" %}
<link rel="stylesheet" href="{{ ASSET_URL }}"/>
{% endassets %}

Cache busting is built right in, and you can do something similar for JS files.

What are the files in .sass-cache for?

From the Docs:

Sass caches parsed documents so that they can be reused without parsing them again unless they have changed.

It just makes compiling faster. If you delete them they will just be generated again the next time you compile.

Is it necessary to append querystrings to images in an img tag and images in css to refresh cached items?

The browser is making these requests after determining an absolute path, so if you are 'cache busting' your static assets in this way, you do need to do it for each file individually, no matter where it's called. You can, however, make it easer on yourself by making it a variable on the backend.

You can append the string as a variable that you only have to update in one place on your backend, probably in conjunction with a CSS pre-processor like LESS or SASS to get all your images.

Or use relative paths to your advantage by adding the version to the base url (site.com/folder/styles.css => site.com/v123/folder/styles.css). This can be added to an existing static asset base url variable in your app, then on the server you can just use a UrlRewrite to strip out the version. This way all the images relatively referred to from your CSS automatically get the version too, having the same 'cache busting' effect.

You could be extra clever and set the variable automatically as part of your build process as the last commit hash from you version control system - which will also make future debugging easier.



Related Topics



Leave a reply



Submit