I have suggested some time back that you could modularize and stitch together fragments of js and css to spit out in one HTTP connection. That makes the page load faster. I also indicated that there ways to tune them by adding cache-control headers.
On the server-side however, you could have a memcache layer on the stitching operation. This saves a lot of Resources (CPU) on your server. I will demonstrate this using a python script I use currently on my site to generate the combined js and css fragments.
So My stitching method is like this
The method joinAndPut is *decorated* by memize. What this means is, all calls to joinAndPut are now wrapped (at runtime) with the logic in memize. All you want do is use the someregion+files+ext as your key in memcache. I extended an example in App Engine CookBook.
This version of memize takes a region instead of key. The intention is a key is generally given at runtime, and is controlled by application logic, so it goes into the *actual* call (ex given below). But the region is (generally a prefix) decided at coding time to avoid runtime collisions. You could also update memcache by force at runtime. A sample call would be something like
For people coming from java background, this is similar to an around Advice in Aspect Oriented Programming. If I get time, may be I'll post another sample in AOP :)
On the server-side however, you could have a memcache layer on the stitching operation. This saves a lot of Resources (CPU) on your server. I will demonstrate this using a python script I use currently on my site to generate the combined js and css fragments.
So My stitching method is like this
@memize(region="jscss")
def joinAndPut(files, ext):
res = files.split("/")
o = StringIO.StringIO()
for f in res:
writeFileTo(o, ext + "/" + f + "." + ext) #writes file out
ret = o.getvalue()
o.close()
return ret;The method joinAndPut is *decorated* by memize. What this means is, all calls to joinAndPut are now wrapped (at runtime) with the logic in memize. All you want do is use the someregion+files+ext as your key in memcache. I extended an example in App Engine CookBook.
def memize(region="", time=3600):
"""Decorator to memoize functions using memcache.
The calling function must give a memizekey named parameter
"""
def decorator(fxn):
def wrapper(*args, **kwargs):
if (not "memizekey" in kwargs):
raise Exception("memize-d function does not send key")
key = region + kwargs["memizekey"]
del kwargs["memizekey"]
data = memcache.get(key)
if data is None or not settings.DEBUG:
data = fxn(*args, **kwargs)
memcache.set(key, data, time)
logging.info("Cached");
else: logging.info("Cache hit");
return data
return wrapper
return decoratorThis version of memize takes a region instead of key. The intention is a key is generally given at runtime, and is controlled by application logic, so it goes into the *actual* call (ex given below). But the region is (generally a prefix) decided at coding time to avoid runtime collisions. You could also update memcache by force at runtime. A sample call would be something like
class MainPage(webapp.RequestHandler):
def get(self, files, ext):
if ext == "css":
self.response.headers['Content-Type'] = 'text/css'
elif ext == "js":
self.response.headers['Content-Type'] = 'text/javascript'
forceUp = self.request.get("force");
if 'true' == forceUp:
forceUp = True
else:
forceUp = False
self.response.headers["Cache-Control"] = "public, max-age=432000"
con = joinAndPut(files, ext , memizekey=files + "." + ext, memizeforce=forceUp)
self.response.out.write(con);
For people coming from java background, this is similar to an around Advice in Aspect Oriented Programming. If I get time, may be I'll post another sample in AOP :)