Friday, May 10, 2013

Partial page load issue with ASP.NET MVC and head.js


I've been working with a small team over the past year or so on a large-scale web application built in ASP.NET MVC 3. We're using some of the best new client-side technologies with it as well - jQuery,Bootstrap and head.js to name a few. Overall, the project has gone very smoothly, with only a few minor hiccups or delays.
Well, except for one lingering issue.
We began experiencing intermittent partial page loads almost as soon as the first draft of the UI was released to our testing servers. The following behaviors were exhibited:
  • This issue could happen on any page in the application when it loaded.
  • 65-70% of the time a page would load correctly.
  • Pressing F5 (refresh) would reload the page and always fixed the issue.
  • Generally, either part of the main menu bar wouldn't load, or our datagrid wouldn't load. Both controls could have a problem on a given page if you reloaded it multiple times.
Perplexing and frustrating to say the least. First, we thought it was a problem with the tiny VMs we had in our testing environment. Then we guessed it might be a packet delivery issue with the VPN tunnel between the testing network and the office network. Then we supposed maybe our self-hosted CDN wasn't set up correctly, and switched to using Amazon S3 (which we were planning on doing anyway).
Each of these theories (and others) were tested and debunked. No love. There's no way it could be in our code, right??
What ended up working for us was moving our "core" libraries outside of head.js and using their "execute in-order" method for the rest of our libraries. Our _Layout.cshtml page looks like this:
<!doctype html>
<html lang="en">
<head>

(... stylesheets and other head content ...)

<script type="text/javascript" src="http://cdn.company.com/JS/head.min.js" />
<script type="text/javascript" src="http://cdn.company.com/JS/jquery-1.7.1.min.js" />
<script type="text/javascript" src="http://cdn.company.com/JS/jquery-ui-1.8.18.min.js" />
<script type="text/javascript" src="http://cdn.company.com/JS/modernizr-2.5.3.min.js" />
<script type="text/javascript" src="http://cdn.company.com/JS/bootstrap-2.1.0.min.js" />
<script type="text/javascript" src="http://cdn.company.com/JS/flexigrid.pack.js" />

<script type="text/javascript">
    head.js(
        "http://cdn.company.com/JS/jquery.validate.min.js",
        "http://cdn.company.com/JS/another.script.js",
        (... other javascript files ...),
    );
</script>

(... other code / markup ...)

</html>
We implemented this change about a week ago, and have yet to experience the issue once since then. Couple of additional notes / comments to share about the change:
  • This seems to work because generally all of the other javascript files you'll want to load probably depend on one or more of these "core" files to work properly. Letting head.js handle this becomes even more delicate when you consider the fact that ASP.NET is trying to load multiple Partial Views per page, many of which contain controls that need the "core" in place to be built properly. Any interruption of loading a "core" file before a control needs it may break part of the page.
  • While the head.js usage documentation lists what we have here as a correct way of using the library, this is not how their demo is built ('View Source' to check it out).
  • The most similar issue we could find was here on the head.js GitHub project site. This is where we got the idea to try an alternate implementation.
  • Since the purpose of head.js is to improve page load times, you may be wondering if this change hurt our delivery speed. Unfortunately, because pages weren't reliably loading for a number of months, it was hard to measure where we were at before the change, so I'm unable to determine a speed difference.

I decided to document this because we weren't able to find any instances online of someone else having the problem; hoping this post will save a few other teams some time and headaches.

No comments:

Post a Comment