Web Performance Calendar

The speed geek's favorite time of year
2013 Edition
ABOUT THE AUTHOR

Barbara Bermes

Barbara (@bbinto) has been captivated by the web since the millennium and has always been passionate about its capabilities. After working for web agencies in Germany and Canada, and most recently working as a Senior Architect and performance advocate for Canada's national public radio and television broadcaster (CBC), she recently joined OANDA as the Product Manager for their Developer Program and API. Barbara is an international speaker and organizer of the Toronto Web Performance Meetup Group.

ESI stands for Edge Side Include and is an XML-based markup language. ESI support is offered by content delivery network (CDN) vendors like Akamai and F5 and also now Varnish (but only a very limited subset). If you use any of these vendors, you have ESI at your disposal. ESI can be used for caching purposes, however, in today’s post I will focus on how it could help you with your mobile strategy and performance.

The W3C states:
“ESI allows for dynamic content assembly at the edge of the network, whether it is in a Content Delivery Network, end-user’s browser, or in a “Reverse Proxy” right next to the origin server.” (http://www.w3.org/TR/esi-lang)

So, let’s pay attention to “dynamic content assembly” in the context of the title’s blog post.

If you are familiar with Server-Side-Include (SSI) and XML/XSLT, you will have no problem understanding ESI. It also supports the same access to variables based on HTTP request attributes, e.g. you can easily check for HTTP_USER_AGENT or HTTP_HEADER. ESI can also include fragments or snippets of additional content via an include command. To make this even more powerful, ESI supports conditional processing, which means logic can be applied to execute specific content <include/>s based on specific conditions, e.g. user agents. All of this is done at the edge; the user will never get content they are not supposed to receive. Additionally, when processing ESI, there is no need to go back to the origin for processing, hence the load at the origin is cut down.

What is (your) Mobile Strategy?

A mobile strategy or approach could range from “We don’t have one”, or “We swear on responsive web design” to “We take mobile very seriously and have dedicated sites”. If you opt for the first statement, please read this and then come back. If you opt for the second or third statement, please continue reading. While there are several options out there to do device detection via PHP or any other server-side language, I’d like to provide several insights on how the same can be achieved with ESI. Similar to other redirect strategies out there, ESI can be used to redirect users to a different site based on the visitor’s user agent. The redirect occurs at the edge and is faster than putting the redirect logic at the origin, hence, you experience performance improvements. ESI is powerful and cheap tool, and your way to a proper mobile device strategy could work by following the steps below.

Please note: the examples are based on Akamai’s ESI implementation (EdgeSuite) and have additional features enabled.

Step 1: Setup a Device List and Buckets

A couple of questions to ask yourselves when developing for mobile are:

  1. Where to set breakpoints for devices?
  2. What devices do you want to support and redirect to your mobile site?

Using the user agent string of the browser is the best indicator of which device the user has landed from. You can set a variable with a regular expression to find the mobile browsers you want to check against.

devicelist.html

<esi:comment text="Regular expression to match tablets' user agents"/>
<esi:assign name="tablet"value="'(iPad|Nexus 10|PlayBook|Xoom|hp-tablet|Dell Streak)'"/>

<esi:comment text="supported OS list: iOS >= 5, Android >=4.x, BB10 and up"/>
<esi:assign name="special_case_newer_devices"value="'((iPhone|iPod) OS [6-9]\.|Android [4-9]\.|BB10)'"/>

<esi:comment text="List of all mobile devices, taken from https://gist.github.com/dalethedeveloper/1503252 "/>
<esi:assign name="mobile_ua"value="'Mobile|iP(hone|od)|Android|BlackBerry|IEMobile|Kindle|NetFront|
  Silk-Accelerated|(hpw|web)OS|Fennec|Minimo|Opera M(obi|ini)|Blazer|Dolfin|Dolphin|Skyfire|Zune'"/>

You can move this content into one file, e.g. devicelist.html, and all your web properties should include this file when using the filter in their ESI redirect logic (see Step 2.1).

You could use WURFL or any other device catalogs to populate this list automatically based on their latest devices and your defined criteria. It is up to you to decide how customized or generic you want to structure the filter and conditions (see more resources at the bottom). In the example provided above, I wanted to illustrate that you could get very granular with your fragmentation and filtering of user agents and operating systems (see "special_case_newer_devices").

Step 2.1: Redirect to Dedicated Mobile Sites

When you work with high-scale web properties, legacy content and several content management systems (CMS), you unfortunately don’t always have the ability to make everything mobile-friendly. Some of your properties might not be ready to be mobile-friendly. If you need to pick and choose which parts of your properties should be redirected, the following ESI snippets and ideas might be useful to you.

(Please note that by elaborating on the example below, I am by no means against the idea that all content should be accessible via any device.)

If your URL redirect mapping does not fit any regular pattern, a dictionary as described below might be useful for you. However, to make your life easier, you should aim for a consistent mobile URL pattern.

Include devicelist.html

<esi:comment text="Regular expression to match tablets' user agents"/>
<esi:assign name="tablet"value="'(iPad|Nexus 10|PlayBook|Xoom|hp-tablet|Dell Streak)'"/>

<esi:comment text="supported OS list: iOS >= 5, Android >=4.x, BB10 and up"/>
<esi:assign name="hybrid"value="'((iPhone|iPod) OS [6-9]\.|Android [4-9]\.|BB10)'"/>

<esi:comment text="List of all mobile devices, taken from https://gist.github.com/dalethedeveloper/1503252 "/>
<esi:assign name="mobile_ua"value="'Mobile|iP(hone|od)|Android|BlackBerry|IEMobile|Kindle|NetFront|
  Silk-Accelerated|(hpw|web)OS|Fennec|Minimo|Opera M(obi|ini)|Blazer|Dolfin|Dolphin|Skyfire|Zune'"/>

Include dictionary.html

<!--esi
<esi:assign name="find_m_url_route"value="{
  '/mypath/':'/mobile/mypath/',
  '/mypath/anotherpath/':'/mypath/m/anotherpath'
}"/>
-->

This file can be updated if there is a new property that was added that also has a mobile version

invoke.html

This is the file that handles the actual redirect, this can be included at the very top of your page:

<!--esi
<esi:include src="devicelist.html"/>
<esi:include src="dictionary.html"/>
<esi:assign name="url"value="$lower($(REQUEST_PATH))"/>
<esi:assign name="m_url"value="$(find_m_url_route{$(url)})"/>
<esi:choose>
  <esi:when test="$(HTTP_USER_AGENT) matches_i $(mobile_ua)">
  <esi:choose>
     <esi:when test="$(find_m_url_route{$(url)})">$set_redirect($(m_url))</esi:when>
  </esi:choose>
  </esi:when>
</esi:choose>
-->

Step 2.2: One Single URL

Having one single URL for your desktop and mobile site can help you with search engine optimization, and avoiding sharing nightmares and redirects (to enhance performance). ESI can also be helpful here. Instead of conditional content snippet replacement, you can create a content and markup switch for the entire page.

/oneurl.html

<!--esi
<esi:choose>
  <esi:when test="$(HTTP_USER_AGENT) matches_i $(mobile_ua)">
    <!--  Mobile head and body -->
  </esi:when>
  <esi:otherwise>
    <!-- Desktop head and body -->
   </esi:otherwise>
</esi:choose>
-->

Step 2.3: REES and (Custom) HTTP headers

I think I am coining a new acronym here, REES, which stands for Responsive Web Design with Edge Side Components, opposed to RESS (Responsive Web Design with Server Side Components). Whatever you consider “server side”; it might just be RESS after all. You get the idea? Before you deliver anything to the client, you massage and optimize the content on the edge (or origin). The idea behind “dynamic content assembly” can especially be used for this scenario.

Native apps can send custom HTTP headers when opening URLs in a web view. This is a great tool to let your web code know what to load when the page is being viewed in a web view.

  • Custom header use case, e.g. don’t show specific content when pulled into a web view in a native app:
    <!--esi
    <esi:choose>
       <esi:when test="!($(HTTP_HEADER_FROM_APP))">
        <!-- include footer -->
        </esi:when>
     </esi:choose>
    -->
  • Common header use case, e.g. use non-mobile Ads code when tablets or mobile devices in general accessing the page:
    <!--esi
    <esi:choose>
      <esi:when test="$(HTTP_USER_AGENT) matches_i $(tablet) || $(HTTP_USER_AGENT) matches_i $(mobile_ua)">
       <!-- include mobile ads -->
       </esi:when>
       <esi:otherwise>
        <!-- include desktop ads -->
       </esi:otherwise>
    </esi:choose>
    -->

Although I am showcasing ESI as a tool for conditional loading of content or redirecting of URLs for your mobile strategy, it is still important to mention that this technology hasn’t been updated for over 10 years and other proposals and technologies have been popping up lately to help out with device and client detection. For example, client-hints, proposed by Ilya Grigorik, aims to help proper detection of features, devices, and any client browser.

Feel free to reach out to me if you have any questions or feedback.

References: