Establishing a performance culture

Abstract

If you have not been living under a solid rock for at least a year you should have heard/read a lot about numerous performance optimizations you should apply to your project. Most of the time you will have read tips like "use a CDN", "minify and concat your JavaScript and CSS" or "reduce your images". All these tips are totally valid and should be easily applicable to almost any website or web project. What most of them lack, from my personal persuasion, is that they do not facilitate establishing a deeper kind of "performance culture" and an according knowledge for you alone or the team you are working with. It is my honest belief that a deeper understanding of every single aspect of frontend performance will soon become a very valuable good. More and more people spread all over the internet seem to slowly realize that with the growing amount of devices (as well as corresponding limitations and connection speeds) there will have to be other, more suitable, approaches to the whole complex. So what I did when I developed my site qoopido.com was to try and develop a structural concept to deal with this to a degree that goes beyond the simple and obligatory methods mentioned above.

Now that I have been using this concept for a couple of months (having put countless additional hours and days into improving it further) I think I have reached a point where I would like to share my insights and findings with you.

Introduction

My interest in the aforementioned matter basically became an obsession when Chris Coyier from css-tricks.com gave me the opportunity to have my article about REMux (a concept about a solely rem based approach to responsive web design) published on his site. I knew I wanted my long planned (but by that time not even started) personal website to be online when the article got published and I wanted it to also make use of REMux as well as all the other nice little to medium things I had been developing before. The resulting amount of "pressure" was both, frustrating and very helpful. By the moment I really started I knew I would manage to keep up the pace and make the site something I could be proud of.

The idea

What I wanted to achieve was a site where only the parts absolutely necessary are loaded directly with the HTML and everything else is lazy-loaded. The latter should ideally include HTML as well as JavaScript and even a combination of both I entitled "widgets" (which are, in a way, similar to what we know as web components by now). What I really wanted to minimize was the perceived loading time for the visitor but without sacrificing any user experience afterwards by having to block the UI and/or give them the impression they had to wait for something. Beside that I made the decision that it would be OK for this site to only work in "modern" browsers (Chrome, Safari, Firefox and - with some limitations - IE9+).

My personal advantage in this case is that I am not only a frontend developer but have been developing backend solutions ever since. The one thing I learnt over the years is that focussing yourself on keeping things lean, modular and separated almost guarantees a more versatile solution, even for future challenges yet unkown.

Foundation

As a technical basis for the site I quickly decided to utilize my own PHP Framework called qoopido.glue. It is not that important which system you decide to use but that you choose the one you are most familiar with and which is able to get the job done best. As mentioned in one of the previous paragraphs using REMux was a mandatory feature I really wanted and needed to incorporate. As REMux itself is based on my very own, object based JavaScript inheritance/extension concept I also had to utilize it as well. It consists of numerous parts available through my qoopido.js library as well as some jQuery plugins I outsourced from it into seperate repositories.

So I ended up having a quite flexible and modular "toolbox" already at hand when starting to practically work on the idea I had in mind.

The other (external) parts of my technological foundation were

  • require.js: for all the lazy-loading needs of modules
  • handlebars.js: to be able to transfer the template logic to frontend modules as well

With the help of my already existing library in combination with require.js and handlebars.js I quickly developed a fully functional prototype where I was able to load everything as separate modules. After this proof of concepts had worked out quite well I started implementing further optimizations as mentioned above.

Lazy-Loading wherever possible

The prototype I developed still had the limitation to load everything immediately after the page was loaded. Performance-wise it actually made things far worse than before by having a lot more server requests due to using require.js. Luckily I had already developed two jQuery plugins that came in really handy to solve part of the problem:

  • qoopido.emerge: to react on HTML elements entering, leaving or nearing the currently visible area of the document
  • qoopido.lazyimage: to specifically lazy-load images based on qoopido.emerge events

Both together enabled me to unobtrusively load optional parts of completely functional JavaScript-/template-modules on demand (almost) without reducing the user experience for the visitor by giving him the impression of having to wait for something.

To give you a better understanding I will explain one of the modules from my site in detail: The "Latest commits" section currently visible on the homepage shows my latests activities to any of my public GitHub repositories. The surrounding container (which gets loaded directly with the page) has its dimensions set but is otherwise absolutely empty. Its visibility is observed by qoopido.emerge and reacted upon by the main application which starts to load the functional GitHub JavaScript module as well as one of two possible templates (which differenciates my solution from web components afaik) when the container is nearing the visible browser area. When the module is loaded and initialized it starts to load its JSON-data from the server. When loading the necessary data is finished it is applied to the previously loaded template which finally gets added to the DOM.

This lazy-load principle is also applied to some more elements on my site:

  • Disquss comment box below any article
  • Full list of GitHub repositories on some pages
  • Contact form and all of its functionality

Further optimizations

In addition to lazy-loading there are some more techniques I use to improve the overall user experience and to reduce the perceived loading time. If you have a look at the slideshow on my homepage you will see that it also follows the modular loading scheme described in the previous paragraph but adds a new layer when it comes to loading the actual images. Normally a slideshow would be expected to load all images concurrently when its HTML is added to the DOM. In this case the loading of images is queued in addition so that the images are loaded sequentially one after the other (microdata for the win). So the image first shown to the visitor will get requested first and therefore be loaded earlier than having requested all of the images at once.

Another layer of optimization is my qoopido.shrinkimage jQuery plugin which can be used to reduce the file size of transparent PNGs by about 60-80% by converting them to a proprietary JSON format that separates the alpha channel from the color information and stores the latter as JPEG with variable compression. qoopido.shrinkimage is able to re-combine the JSON-data loaded via HTML5 canvas element and should gracefully fallback to the original PNG for browsers without canvas support. The plugin is, for example, used within the headphone visual widget on my homepage although it may not be as obvious.

Last but not least I set up a separate CDN domain for all my static assets. Beside setting a rather long expires header it also suppresses any kind of cookies to further reduce response times. To make sure that any visitor still gets the latest version of any asset I also incorporated a directory structure that allows the use of version numbers and included it in my Grunt build process. For very common external resources like jQuery and jQuery easing I stayed with CDNJS to profit even more fromt its performance gain.

Minification

As stated in the abstract of this article any possible and helpful kind of minification should always be used self-evidently and, in an ideal world, happen completely automatic and transparent for the developer. What I did to achieve the latter two points is that I directly incorporated the necessary tools into my build process.

By the time of the development I am describing here I already used LESS for writing CSS paired with LESS.app (I am on OSX) to watch and compile the CSS files whenever needed. LESS is not only helpful for minification but allows you to work on a CSS structure that is easier to understand and maintain than pure vanilla CSS.

Regarding JavaScript minification I immediately fell in love with Grunt (a tool to create and manage complex build processes) when it first appeared and have been using it ever since where it makes sense. Grunt offers tons of plugins for many usually separate tasks like linting, concatenation, minification and compilation of handlebars templates which makes it an ideal solution for my task!

The only (partly) manual optimization I frequently use is ImageOptim. ImageOptim is an OSX application on which you can drag & drop any kind of image or multiple images. It will try different standalone optimizers (with adjustable parameters) and save the resulting image with the smallest file size.

Conclusion

What you have read up to now might sound rather complex and very difficult but rest assured that most of it was (only) combining well known tools & techniques into something new and capable to fit my needs. The first version (more or less the prototype with added layout) of the site was developed in only a couple of days and than got refined over time. My personal learnings were immense and I am absolutely sure they are worth the effort several times!

What I would love to see is more people realizing that a kind of "performance culture" will be needed in the near future and already makes sense today, regardless of whatever that means for the individual :)

Keep in mind that this article represents my personal way of approaching the matter but does not claim to be the holy grail for everyone!

Final words

My PHP Framework as well as all my JavaScript libraries and modules are publicly available on GitHub as open source. So feel free to use them wherever you like and give feedback if you wish!