UPDATE: New theme, new code. Click here to read about the way I use cache, and limit HTTP requests now.

Disclaimer: This is an experiment, and would probably not apply to most websites (if any). My mission: Load my homepage in 1 HTTP request without compromising layout or functionality. Just to be clear, the motivation is not to gain any performance from this, just to see if I can do it.

So, back to the point. Drupal has a lot of css, js and image files by default. To load them all you have to ask the server to serve them to you, simple as that. So if you have to ask less times, the page would load faster. In theory. This blog has over 40 requests on the front-page, out of the box. Luckily, Drupal has a number of tools you can use to minimize requests, and among them is the optimization you can find in core. You can find it under the “performance” settings (depending on what version you are on, this is located under “configuration->development” or “site configuration”). Cool. But this still leaves me at more than 10 HTTP requests. I want less! So what next.

So the next step was to avoid loading too many images, so I decided to start with base64 encoding my burning logo (which actually consists of one file pr. letter).

To base64 encode files is extremely simple. What I usually do is use a small php file containing only this:

// This is the file.
$file = file_get_contents('some.file'); 
print base64_encode($file);

If you open this up in a browser (or run it from the command line), you get a long string back. This is your image. To use this in a page, you just go like this:

<img src="data:image/gif;ALONGSTRINGBASE64”>

Change the “gif” part to whatever file format you need.

OK, so what else can I optimize. Ah, of course I can do the same with all css rules containing images. Fire up my base64 script again, and the css rule looks for example like this:

#someid {
  background-image: url('data:image/png;base64,A_LOOOOOOONG_STRING’);
}

Simple! Things are getting somewhere.

The next step was to embed the fonts I use, without querying google fonts (hope they don’t read this, as I am not sure if I am allowed to embed them like this, does anyone know?). Same step here with the base64 encoding, and the styles went in to the head tag something like this:

@font-face {
  font-family: 'My cool font';
  font-style: normal;
  font-weight: normal;
  src: local(''My cool font ') , url("data:font/opentype;base64,A_LOOOOONG_STRING”) format('woff')
}

Awesome! The number is decreasing, without compromising the layout.

The two next steps is kind of site-specific, but basically what I tried to do, was iterate over the scripts and stylesheets, and print the contents of the files instead of embedding them. So in a template file I put something like this:

<?php
print '<style>';
$style = ''
foreach ($css as $c) {
  // Do some checking of some media query stuff. 
  // ...
  // Then store the raw CSS.
  $style .= file_get_contents($c['data']);
}
//do some regex to remove some stuff, and remove whitespace.
print $style . '</style>';

Cool. We have no requests on css! And now to the JavaScript.

This was tricky. I have a combination of standard, custom and a couple of compatibility scripts on my site. I had to throw out a couple of them, and do some reordering of the scripts, and then iterate and print them out in a similar matter as the stylesheets.

Since you probably are looking at this page in a full node view (or you would not be able to read this), you may have looked in the inspector and seen that I have well over 30 HTTP requests. Ugh, those external services, eh? The main reason for this is actually the addthis stuff I have at the bottom. So I have over 30 requests extra just to look modern. BUT: If you navigate to the front page I have tossed out all sharing options and actually clock in at an awesome 4 requests. Two of them is google analytics. The other one is there for one and only reason: I use the boost module to serve static pages, so if I want to display that talking burning bird without using cached data, I just have to burden you with a lookup to search.twitter.com. I am sorry to burden you, visitor!

Mission is as much as it can be complete, and I am down to 1 internal HTTP request. Let’s celebrate with an animated gif, folks!