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:
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.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 CSSurl(...)
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 ignoredata:
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=94251If 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
, andlist-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
CSS - Smooth Button Gradient Color Transition on Hover
How to Set Different Font-Weight for Fallback Font
Align Flex-Box Items to Baseline of Last Text Line in a Block
Diamond Menu Items Using CSS and Svg
How to Prevent Shifting When Changing Border Width
Problem with Position Absolute in Ie7, Div Moves 10Px to The Right
Intellij Idea 11: How to Compile .CSS from .Less
Blue Border Around Image Maps in Internet Explorer 9
Absolute Positioned Item in a Flex Container Still Gets Considered as Item in Ie & Firefox
How to Style Radio Button or Checkbox Inside a Bootstrap Table
How to Prevent CSS Declaration Dropped Errors Cross Browser
How Does: Nth-Child(N+4):Nth-Child(-N+8) Select a Range of Elements
Add Additional Box-Shadow to an Element Where Existing Shadow Is Unknown
Bootstrap-Affix: Div Underneath Affix "Jumps" to Top. How to Make It Smoothly Scroll Behind
Importing Style Sheets in Angular4
Matdialog Doesn't Open as Dialog
How to Target The First and The Last Element Per Row in a Flex Layout