Using Typekit the right way (with an improved embed code)

Sebastian Kippe ·

TL;DR: If you use Typekit’s advanced embed code, our improved version will dramatically improve load times for your users on slow connections or who use third-party resource blocking via e.g. browser extensions like Ghostery.

Background

At 5apps we use Webfonts for all our sites; both self-hosted icon fonts as well as beautiful typefaces hosted by Typekit (and sometimes Google).

In general, Typekit works very well, and they improved the loading process quite a bit over time. But one major problem still exists when using the advanced embed code to improve load times of your pages by not blocking all other rendering until the fonts are loaded:

If you want to hide FOUT–the “Flash Of Unstyled Text”, occuring when Webfonts are loaded after the page has been rendered with fallback system fonts–then you’ll use CSS to hide either the whole page, or the parts using Webfonts, until Typekit removes the wf-loading class from your body element.

For the case of something going wrong with loading the fonts from Typekit, the advanced embed script uses a timeout (3 seconds by default), which will trigger the wf-loading class to be removed (and a wf-inactive class to be added), if the font(s) couldn’t be loaded during that time.

Problems

The major problem with this approach is that (until the font could be loaded and cached successfully) it might take up to 3 seconds for your users to be able to see any content; not once, but for every single page load.

There are at least two more or less regular scenarios in which this will be the norm:

  • Slow Internet connections

    Even if you’re not catering to low-bandwidth users on the countryside or people in developing economies, mobile networks everywhere are slow and unreliable. This could hit any one of your users.

  • Third-party resources being blocked

    The regular reason for this (at least in our experience) is, that the person is using a privacy-enhancing browser extension like e.g. Ghostery, and has set it to block all 3rd-party resources, unless explicitly allowed. Another reason could be some kind of protective Web proxy (e.g. FreedomBox) being used. In either case, it’s not visible to the user why your site or application is so incredibly slow.

Solution

Our solution for this is rather simple (it took about 10 minutes to develop), yet quite effective. If the timeout is hit during a page load, we’ll just tell the browser that it shouldn’t try to load Typekit fonts anymore until the tab or window is closed.

By using the browser’s sessionStorage– the lesser-known, non-persistent sibling of the more well-known localStorage– we don’t even have to flush that configuration key, or jump through any other hoops, in order to get exactly the behaviour we want.

So, without further ado, here’s our adapted version of the advanced embed code, loading pages instantly during the rest of the visit, after running into the configured timeout for the first time:

(function(d) {
  var tkTimeout=3000;
  if(window.sessionStorage){if(sessionStorage.getItem('useTypekit')==='false'){tkTimeout=0;}}
  var config = {
    kitId: 'a1b2c3f4',
    scriptTimeout: tkTimeout
  },
  h=d.documentElement,t=setTimeout(function(){h.className=h.className.replace(/\bwf-loading\b/g,"")+"wf-inactive";if(window.sessionStorage){sessionStorage.setItem("useTypekit","false")}},config.scriptTimeout),tk=d.createElement("script"),f=false,s=d.getElementsByTagName("script")[0],a;h.className+="wf-loading";tk.src='//use.typekit.net/'+config.kitId+'.js';tk.async=true;tk.onload=tk.onreadystatechange=function(){a=this.readyState;if(f||a&&a!="complete"&&a!="loaded")return;f=true;clearTimeout(t);try{Typekit.load(config)}catch(e){}};s.parentNode.insertBefore(tk,s)
})(document);

And here’s a Gist on GitHub.

I hope this can help you improve load times for some of your users, as it did for ours. But I’d also like to encourage you to think about potential problems on the edges of your userbase, and especially to never rely solely on third parties for your content to be available or visible. Otherwise you might end up with situations like these…

Tweet

Feedback

Please leave a comment below or ping us on Twitter (or even better yet, fork the Gist and improve it), if you find a problem with this approach or an better way of solving the problem.

Using Travis CI to make sure your Chef repo and server are in sync

Greg Karékinian ·

Here’s the first post by our 5ops team, who are building and maintaining all our infrastructure. We’re glad to have Greg Karékinian on board as the latest 5apper, and in his first article he’s going to share a little trick for users of Chef Server and Travis CI. Enjoy!

At 5apps we use Chef to automate our infrastructure, so far in a traditional client/server model. Using Chef Server comes with an extra level of complexity, though: if you’re not careful, your Git repository and the server will get out of sync and you will likely end up scratching your head figuring out what is happening.

Fortunately, there’s a gem for that: knife-inspect, formerly known as health_inspector. I couldn’t live without this Knife plugin and I’m glad to announce that I just took over as the new maintainer (thanks to the original author, Ben Marini!). I actually asked to become the new maintainer after I added support for return codes, which is necessary for using the gem in a continuous integration setting. You will need at least version 0.7.1 (just released yesterday), which fixes a small bug with the return code for data bags.

For continuous integration of our applications we use the Pro service by our friends and office mates at Travis CI. Before this setup, I would run knife-inspect every couple of weeks (when I remembered) and fixed the differences between our Chef repo and Chef server. But as a developer and automation engineer I really like to turn painful manual steps into automated bliss, so I thought about using Travis to run knife-inspect after every push.

While working on this I realized Travis CI gives you secure environment variables so you don’t have to commit a clear-text version of your Chef user’s credentials. Check out Travis CI’s doc for more information. Here’s what the .travis.yml file of our Chef repo looks like (minus irrelevant sections such as notifications):

language: ruby
rvm:
  - 1.9.3
before_script:
  - secret=`openssl rsautl -decrypt -inkey ~/.ssh/id_rsa -in .chef/travis_secret`
  - openssl aes-256-cbc -k "$secret" -in .chef/travis-ci.pem.enc -d -a -out .chef/travis-ci.pem
env:
  global:
    - OPSCODE_USER=travis-ci
script: "bundle exec knife inspect"

And here’s a screenshot of knife-inspect running on Travis CI:

Travis CI knife-inspect

So knife-inspect will now make the build of our Chef repository fail, in case repo and Chef server are out of sync. Here’s an example from our private IRC channel:

20:37 !GitHub gregkare pushed 1 new commit:
  https://github.com/5apps/chef/compare/beefdead...beefdead
20:37 !GitHub [chef] Add some great feature - Greg Karékinian
20:43 !Travis Build status for chef (master:beefdead): Still Failing
  [https://magnum.travis-ci.com/5apps/chef/builds/2055018]
20:46 !GitHub gregkare pushed 1 new commit:
  https://github.com/5apps/chef/compare/beefbeef...deaddead
20:46 !GitHub [chef] Add missing updated preproduction environment - Greg
  Karékinian
20:52 !Travis Build status for chef (master:deaddead): Fixed
  [https://magnum.travis-ci.com/5apps/chef/builds/2055128]

Happy shipping!

New app icon sizes

Sebastian Kippe ·

While the number of different icon sizes supported by Web app install- and bookmarking mechanisms grows, we’re constantly adding these new versions to our icon upload processing, as well as to the affected deployment strategies.

With the latest update, introduced today, the number of versions grew to a whopping 16 different sizes. The latest additions are:

  • Firefox OS: 30×30px, 60×60px
  • iOS 7 and latest Apple devices: 76×76px, 120×120px, 152×152px
  • Chrome Mobile (install-to-homescreen): 196×196px;
  • Open Web Apps, Ubuntu Web Apps: 256×256px

We actually had to redesign our icon settings page in order to fit all these sizes in the UI. So, while at it, we also made it easier for you to directly reach the deployed icon files, as well as to see what the various versions are used for:

Screenshot

Next up in the icon department will be an improved uploading interface. And we’ll obviously continue to add more icon versions whenever we see new vendor specifications for them.

Change app ownership

Sebastian Kippe ·

We just introduced a new feature to 5apps Deploy: it is now possible to transfer an app to another user account. Just head to the newly redesigned collaboration settings page of any of your apps:

Screenshot collaboration page

This is very useful e.g. when you want to create a new user account for your organization and move apps from your personal account over to the new one.

Enjoy!

Introducing our Status Dashboard

Sebastian Kippe ·

Good news everyone! We just launched a new system status site on status.5apps.com, where you can check the operational status of all our products and services:

Screenshot

Downtime: our common enemy

In a perfect world, there would be no downtime, of course. And luckily, we had very little in the past. Especially our app hosting is virtually indestructible, and as a service provider, it’s our main priority to keep things fast and available.

But, naturally, issues do arise sometimes. And even with just a few minutes of downtime, we think you should know what’s going on immediately, and be kept in the loop about everything until the problem is resolved.

Apart from updating the site whenever an event occurs, a note will also be published on Twitter (@5apps). And on this new site, you can even subscribe to RSS feeds containing all status updates and notes – either for single services, or all of them at once.

Stashboard

The new status site is based on the fantastic Stashboard, an open-source software written in Python with Django and running on Google App Engine. Many thanks to Twilio for making it available to the world!

Archive of all entries