In this post I’m going to talk about what I’ve done (and what I’ve not done) with trntxt in order to get the fastest page load times possible. I’ve split this up into two sections. The first part might be interesting to most of you, whereas the second part goes into technical detail that will look like complete gobbledygook if you haven’t programmed using Node before.
You have been warned.
I’m also going to say I know that there are train times apps available, and they’ll probably use less data than my site, but I’m not going to talk about that today.
Part 1: Trim out the fat
When you load the First Great Western website on a computer with a good connection, you’ll notice it’ll load in about 5 seconds. “That’s fine” I hear you say, and it is, until you try it on a mobile connection.
A good 3G connection is 0.375 megabytes per second and the FGW website is 2 megabytes on the first page load, meaning it should take almost 6 seconds to load. Unfortunately this isn’t the case. The FGW site is full of pictures, scripts and other files. In fact, a single page load requires over 140 different files, all of which are separate requests. Each request has overhead, meaning there is a delay after the phone makes the request before the file starts downloading. In reality a 3G connection will load the site in about 20 seconds according to Chrome dev tools:
That’s a lot of bloat, especially when you only want to know the time of the text train to Trowbridge.
Now, those of you who live in the cities may forget that not all of England is covered in concrete. Many areas of the country don’t even have a 3G connection! Instead they might have an “Edge” connection, where the FGW page load time is measured in minutes, not seconds. By the time the page loads, your train will have already left your station, and maybe even arrived at its destination.
It’s this type of slow connection where trntxt really shows its advantage.
With trntxt, your phone makes 1 request, not 140. The response contains the information you need and very little else. When you want the time of a train, you don’t need pretty pictures, custom fonts, tracking cookies, styled buttons, pop-up calendars, sliding menus or a plugin that sends data every time you click on the screen. The best way to have quick responses is to send back less data, and that’s exactly what trntxt does.
Part 2: Minification in Node
Normally when I write in this blog, I’ll make an effort to ensure that my non-technical readers can still understand what I’m talking about.
If you are a non-technical person, well done for making it this far. However I make no effort in trying to make this next section understandable for you. Sorry about that.
In order to make the responses just that little bit faster, I run my CSS through a minifier, stick it inline with the HTML and then I minify the HTML as well. In reality, for trntxt at least, the gains from minification are negligible but it was a good exercise anyway.
I chose to use the Jade templating engine to design the layout of the page. Jade uses a whitespace-aware syntax, so you are forced to indent your text properly (hooray!). It’s easy to pass variables into the page, making it great for pages where the data keeps changing – much like trntxt!
My gulpfile uses gulp-cssmin to minify the CSS, and gulp-jade to precompile the static Jade files. Check it out of you’re interested. By default, Jade minifies its HTML output. It removes all newlines and whitespace in order to save some extra bytes. The output looks ugly, but the browser doesn’t care.
It is a good idea to precompile any static webpages since the server will not need to process the page before sending it to the client. This is the case for the trntxt homepage. Since the text on that page never changes, it doesn’t need to be dynamically generated each time a user requests it. Here, any time I save index.jade, gulp will make an HTML version with the minified CSS inline and save it in the public folder. The CSS is only a few bytes in size, so it doesn’t really make sense to have it as a separate file to download. If it were a separate file, the time spent setting up the extra request will far outweigh the time spent actually downloading the CSS. Precompiled files reduce the response time because the server already has the response it needs to send.
Right, I think I must have alienated everybody by now! I’ll be back to my normal not-so-technobabbly self in the next post!
Aside: Things that have changed since I started writing this post 2 weeks ago
Unfortunately in the technology world, as soon as you learn something it’s out of date. While I was writing this post, I learned that the HTTP2 standard advises against inlining styles and scripts as these can’t be cached on the client. I’m going to stick with it though, since I don’t really see an advantage of caching a <100 byte CSS file on the client browser.
Also, trntxt responses are now almost twice as big due to app icon listings, which I’ll write about in the next post. Devices requesting trntxt will now make a second request for the favicon. This doesn’t appear in the Chrome dev tools screenshot because trntxt didn’t have an icon back then. This is why it’s important to write things up as soon as possible!