Faster Page Loads – Bundle Your CSS and Javascript with lighttpd
March 18, 2008 – 4:23 pmHello again,
Preface
This time I have been busy playing with Lighttpd and mod_magnet. I found a blog post where darix mentions a post from sitepoint where they demostrate a technique to speed up the HTTP GET of javascript and CSS files.
Its quite simple really, instead of doing
<link href="/css/styles1.css" rel="stylesheet" type="text/css" /> <link href="/css/styles2.css" rel="stylesheet" type="text/css" /> <link href="/css/styles3.css" rel="stylesheet" type="text/css" />
you simply do
<link href="/css/styles1.css,styles2.css,styles3.css" rel="stylesheet" type="text/css" />
and then this script will automagic concat them together into one big file, and make lighty serve that one instead. (The same goes for javascript files, or anything really)
This could save ALOT of HTTP GET’s to your server, and increase the overall loadtime and performance of your site alot, especially if you use alot of Web2.0 stuff
However, the Lua source for their script was not made public, so nobody could benifit from their otherwise impressive speed gains.
Until now.. or, well, almost – its not their script, but my own attempt to mimic what they did in pure Lua
I tried to keep the dependencies down to a minimum, however I decided to use one, md5.
You can find the source here (5.1, 5.0)
Config
- charset (Line 42)
- Set it so it matches the headers in your lighttpd.conf file. Must match your mod_compress settings aswell to utilize that feature
- prefix (Line 43)
- Could be anything really, its just a mean to “namespace” your cached files so you can run the script with multiple configs
- rootPath (Line 44)
- The path to look for the files to concat, default should be fine for most DOC_ROOT/js and DOC_ROOT/css
- concatRoot (Line 45)
- The folder to store the concated files, can be anywhere
Setup
- Put the source below somewhere on your disk, I asume you name it bundle.lua
- Enable mod_magnet in lighttpd.conf
- Add magnet.attract-physical-path-to = ( “YOUR_PATH/bundle.lua” ) to your config where needed
- Restart lighttpd
- Modify your css/js links to utilize the new feature:)
Optimal you can enable mod_compress aswell, bundle.lua works out of the box with any other lighttpd module you may have
Source
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | --- get stat information on a path -- @param path to stat -- @param the ftype to return -- @return false if ftype or path does not exist function file_info(path, ftype) local attr = lighty.stat(path) if attr and attr[ftype] then return attr[ftype] end return false end --- Wrapper for reading a full file into a string -- @param filename Full path to the file -- @return a string with the content of the file function read_file(filename) local content = "" if file_info(filename, "is_file") then local file = io.open(filename, "r") content = file:read("*a") io.close(file) end return content end --- Wrapper for writeing content to a file -- @param filename Full path to the destionation file -- @param content The string to write function write_cache(filename, content) local file = io.open(filename, "w") file:write(content) io.close(file) end --- Concat multiple files into one file -- @param lighty lighty global variable passed to the method -- @param match The files that will be concat into a file -- @param fileExtension Do !NOT! include the dot ( . ) function combine_files(lighty, files, fileExtension) require "md5" local charset = "; charset=utf-8" local prefix = "cache-" local rootPath = lighty.env["physical.doc-root"] .. fileExtension .. "/" local concatRoot = "/tmp/cache/" local lastModified = 0 for file in string.gmatch(files, "(.-\." .. fileExtension .. "),?") do local fullPath = rootPath .. file modTime = file_info(fullPath, "st_mtime") if type(modTime) == "number" then lastModified = math.max(lastModified, modTime) end end local hash = lastModified .. "-" .. md5.sumhexa(files) lighty.header["Etag"] = '"' .. hash ..'"' local cacheFile = prefix .. hash .. '.' .. fileExtension if not file_info(concatRoot .. cacheFile, "is_file") then local content = "" for file in string.gmatch(match, "(.-\." .. fileExtension .. "),?") do content = content .. "\n" content = content .. "/**\n" content = content .. " *\n" content = content .. " * " .. file .. "\n" content = content .. " *\n" content = content .. " */\n" content = content .. "\n" content = content .. read_file(rootPath .. file) end write_cache(concatRoot .. cacheFile, content ) end lighty.env["physical.path"] = concatRoot .. cacheFile end if (not file_info(lighty.env["physical.path"], "is_file")) then css = string.match(lighty.env["physical.path"], "css/(.*\.css)") if css then return combine_files(lighty, css, "css") end js = string.match(lighty.env["physical.path"], "js/(.*\.js)") if js then return combine_files(lighty, js, "js") end end |
Tags: english, lighttpd, lua, mod_magnet
10 Responses to “Faster Page Loads – Bundle Your CSS and Javascript with lighttpd”
This is really good news, congratulations. Also nice guide, thanks.
By 2ge on Mar 18, 2008
Hi,
It seems that you posted a script with an error in line 62. There’s a reference to unitialised variable “match” – should be “files” instead
At least it works for me with “files”
By redvasily on Jul 30, 2008
WOW! nice tutorial! that’s what I exactly need. You are explaining in such a simple and straightforward! why others can’t do it as you’ve done? may be it’s a talent… thanx a lot!
By Eve - Photostock Expert on Jan 15, 2009
Hi,
I want some of .js, .css files to be loaded before HTML contents. How can I able to do with your code.
By Sander on Jun 8, 2009
I just added “mod_compress” to the modules in the array “server.modules” and
compress.cache-dir = “/var/www/cache/”
compress.filetype = (“text/css”, “text/javascript” )
in the /etc/lighttpd/lighttpd.conf file. Obviously I created the directory /var/www/cache giving to it the permission needed by lighttpd to write there.
And that’s just a small part of the unlimited capacities of Lighttpd!
By CMS Website on Jul 3, 2009
Basically, what the plugin does is:
1 it combines multiple CSS or Javascript files into one big file (bundle)
2 it compacts this bundle by removing whitespace and comments
3 it caches the bundle by using Rails default page caching mechanism
4 it creates an “accesspoint” to the bundle by adding a route.
I was using this already, but nice tutorial anyway…
By Lischet cms on Jul 3, 2009
Can anyone tell me how I disable bundling in development mode? Its very very annoying during development…
By Laatste Nieuws on Jul 30, 2009