Imagine that you just coded a HTML/CSS Editor in Javascript that leaves nothing to be desired. Your app knows about the most arcane CSS properties, offers instant preview and has a GUI that simply rocks. But there is one weak point: when the user wants to save his creation, he has to copy/paste the code from TEXTAREAs and create the necessary html/css files on his own.

The Woes of server-side zipping

Wouldn’t it be nice if your app could serve a ZIP archive of all created files? “But this requires a server-side script!” I hear you complaining. And as soon the server side gets involved, the problems start: you have to construct quite complex AJAX requests to submit the user’s code and preserve its structure (Themeroller users might now what I’m talking of ). You’d also have to implement some security measures to prevent abuse of your script. This could go as far as forcing your users to log in before they can use your app, making it less attractive for “drive-by”-users

Welcome to client-side zipping

In this blog post, I present you a receipe for client-side zipping, implemented almost in pure Javascript. Our first ingredient is Stuart Knightley’s fantastic JSZip library. It takes a few Javascripts Strings, stuffs them as individual files in a zip archive and returns the binary content of the archive. Note that JSZip doesn’t perform any compression, it simply concatenates the string data and adds some information about the file organisation. When you extract the archive, the specified files are created and filled with their content.

The strengths and weaknesses of JSZip

The only weak point of Stuart’s approach is the delivery of the zips to the user: he dumps out a base-64-encoded version of the zip archive to the browser’s address bar. This concept is called data URI and causes the browser to trigger a zip download. Unfortunately, data uris have some disadvantages: the required base-64 encoding increases the file size by about 33%. The poor cross-browser support for data URIs (IE 7: nada, IE8: length limited to 32 kb) makes this approach a no-go for our purpose.

Gears to the rescue

Our second ingredient, Gears, comes to the rescue. Among other features, Gears acts like an emergency battery for web applications: it offers offline continuation for web applications by hosting all required files on a tiny webserver called LocalServer. Luckily, we can add new files to LocalServer programmatically via Javascript and thus make Gears serve our dynamically created zip archive. Contrary to the data URI approach of JSZip, we don’t need to base-64-encode our resulting zip archive. This results in a smaller filesize, – but much more important – in a faster compression time. Furthermore, Gears doesn’t impose limits on the size of the generated zip archive and thus makes our solution work across all modern browsers (Note: if your browser uses an older/less advantaged javascript engine, you will surely experience performance impacts. However, GearsZipper is not designed to create multi-gigabyte zips).

The basic recipe as pseudo-code

Here is the basic recipe of my approach as pseudo-code. I admit that a certain knowledge of the Gears Javascript API is required to fully understand it, but nothing prevents you from diving into it.

  1. Invoke JSZip with all the Javascript strings and desired filepaths for the zip archive. Use JSZip.generate(true) to avoid the base-64 encoding of the result string.
  2. Convert the binary result string of JSZip to a Gears Blob using the BlobBuilder class
  3. Store the created Blob on Gears’ LocalServer by using the captureBlob method ofLocalServer’s RessourceStore class. captureBlob also allows you to specify an URL under which the Blob content will be served.
  4. After the creation process is done, insert the generated URL into the webpage or redirect to it to cause an immediate download.

The Demo, please!!!

After digesting all this technical stuff, you really deserve a cool demo. Note that this Demo already includes features that I will introduce in the second part of this tutorial: the inclusion of “real” files and canvas items to the archive.