Let's talk a bit …
Jan 31st
No more JS / CSS browser cache refresh pain
We often have the following problem :
- a CSS or a Javascript file is changed in a package
- we make a release (or not) and put it to production
- some visitors still gets old CSS and Javascript versions (except if by chance we remembered to reinstall package / re-save portal_css and portal_javascripts configs) and need to flush their browser cache
As we do not have great memory and as our customer’s Helpdesk was tired of doing remote cache flush, we wanted to do something (automatic) about it.
Plone adds cache keys as suffixes for CSS and JS files, as for example base-cachekey6247.css.
This cache key doesn’t change, even after an instance restart. This is why browsers can keep the “old” versions cached.
To avoid that (and without touching to Apache or whatever), we wrote a little script that exectutes at the end of the instance startup process.It forces the “cook” of resources which generates a new cache key so that browser cannot cache CSS and JS anymore !
This script can of course be improved, but it fits our needs.
[Please note that this code is written for Plone 3.]
First, we subscribe to IDatabaseOpenedWithRootEvent (too bad we couldn’t use IProcessStarting because we have no context to get Plone sites) :
<subscriber for="zope.app.appsetup.interfaces.IDatabaseOpenedWithRootEvent" handler=".resources.clear_cache" />
Then, our handler gets the work done :
# -*- coding: utf-8 -*- from Products.CMFCore.utils import getToolByName from zope.app.appsetup.bootstrap import getInformationFromEvent import transaction from our.package import logger def clear_cache(event): """ Force cache key renewal for CSS and JS on all Plone sites at startup. This avoids any caching of changed CSS or JS. """ db, connection, root, root_folder = getInformationFromEvent(event) app = root_folder for obj_tuple in app.items(): (obj_name, obj) = obj_tuple if obj.get('portal_type') == 'Plone Site': p_css = getToolByName(obj, 'portal_css') p_css.cookResources() p_js = getToolByName(obj, 'portal_javascripts') p_js.cookResources() logger.info('Cache key changed for CSS/JS on Plone %s' % obj_name) transaction.commit()
And voilĂ , no more browser cache flush hassle for our customer and their Helpdesk
If you have any thoughts on this, or think that this should be packaged in a collective egg (useful for you ?), feel free to comment.
February 8, 2017 - 8:51 am
Hmm, if you are running multiple Zope instances, it will get cooked once per instance, even though it only needs to happen once. That could even cause a ConflictError on the transaction commit.
I have the same problem but would prefer to add a step to my deployment process (an ansible playbook) to cook the resources once. If you want to stick with doing it as part of instance startup, maybe you want to find a way to keep it from cooking multiple times, or at least catch and ignore the potential ConflictError.
Finally: really, Plone 3?