Single-page App Won't Lazy-load When Hash Fragment is Present

I’ve recently been tinkering with Durandal, which is an SPA framework that uses jQuery, Knockout, Sammy, and RequireJS. This is my first experience building an SPA that uses URL hash fragments to manage views/state, and honestly, I’m not very familiar with any of these libraries, aside from jQuery. My point is, I don’t really know if the WPT results I’m seeing are the result of a bug (in WPT)…or the result of how web browsers handle hash fragments. What I do know…is that the results are not what I expected.

(This is difficult to explain, so bear with me.)

Instead of creating an SPA in the traditional sense (i.e., where 100% of the web page’s content is dynamically inserted into the DOM), I want to design an app that functions more like a Flash widget. That is, I want to embed the app-controlled DOM element(s) into a standalone web page of static content (aka, the host page). Furthermore, I need the app to meet the following criteria:

[]Negligible impact on host page’s load time
]Not a single point of failure for the host page

In order to meet these criteria, I’m designing the app (including all the 3rd-party libraries mentioned above) to be lazy-loadable. This is something I’ve done many times before; the only major difference this time is that the app appends a hash fragment to the host page’s URL (compliments of Sammy.js).

So basically, the page load sequence I was expecting would look something like this:

[]host-page.html is downloaded
]style.css and script.js are downloaded/parsed
[]script.js defines a callback that dynamically loads app.js, and attaches it to window.load
]host-page.html static content is rendered
[]Document Complete (i.e., window.load event fires)
]app.js is dynamically inserted into the head section
[*]app.js begins downloading dependencies, populating its designated element on the host page, rendering content, etc.

In other words, I expected the WPT waterfall view to show 3 HTTP requests, then the Document Complete line, then app.js, followed by a long list of 3rd-party libraries and AMD modules.

What I’m actually seeing is…um…not that?

[]IE6 - IE9 show most of the app files being downloaded before the blue line. In other words, it looks like I’d expect if app.js were hard-coded right before the host page’s /body tag.
]IE10 looks right.
[]Chrome looks right.
]Firefox looks right.
[]Safari times out and doesn’t show the blue line at all.
]Android 2.1 is perhaps the most confusing. It looks like it downloads half the app files on the initial page view, and the other half on the repeat view?

Based on where IE6 - IE9 are drawing the blue line, it appears as though maybe they’re considering the URL change (i.e., when the #/ is appended) to be the point where the Document Completed?

Anyway, this whole thing is virtually impossible to explain without an example, so…I spent like 100 years creating a full demo, and I put it up on Github. You can find the repo here.

The repo is set up with Github Pages, so the test pages are live (links below). So far, I’ve tried 4 variations (e.g., changing the require.js config, initiating the app in different ways, etc.), all of which had similar results, except for the last one. For the last one, Page D, I modified Durandal so that it doesn’t automatically change the URL. This was the only real breakthrough I made; Page D lazy-loads as you’d expect. So there’s something about dynamically appending the hash fragment that causes WPT to act weird.

Or maybe it’s not WPT. Maybe this is such an esoteric use case that the browsers all respond to it differently?

Anyway, here are the test pages I’ve been playing around with:

Page A
Page B
Page C
Page D

[]Page D currently has a problem where the app is preventing link clicks from actually navigating to their respective URLs. So to get from Page D to Page C, you might need to click the Page C link and then hard-refresh the page.
]The WPT results (linked to from each test page) are just a snapshot–the test page has changed since the tests were originally run–so be sure to click “Rerun this test” to get updated results.
[*]I’ll most likely continue to make (arbitrary) changes to this repo. In other words, the live pages are not stable.

Bottom Line: Can someone please explain why WPT shows weird test results for web pages that embed asynchronously lazy-loaded single-page applications that dynamically append hash fragments to their URLs?

One piece about how WPT works may help explain what you are seeing and it is going to depend on how the browsers treat the url change with the /# addition. WPT draws the onload line for the “last” document-level onload notification. If what is happening is that you are seeing navigate->onload->insert js->url change triggers another “navigate”->onload then WPT’s onload will be at the end.

That should mean that the browsers where you see that happening are also getting an onload event again at the end.

This is largely to deal with the fairly common case of javascript redirects where javascript code in the page after it starts loading does a location change (usually see it with authentication on websites).

As far as the browsers go, there’s a good chance that the HTML 5 spec firmed up the behavior definition for some piece of what you are doing which is why it changed from IE9->10 and why IE10 matches chrome and firefox. The HTML 5 spec firmed up a LOT about the processing model for the DOM and it came out after IE 9 was released.

The Android agent is somewhat different and it may be stopping the measurement at the onload event (I don’t think it has a way to wait for network activity to stop like the desktop agents do).

Hi Patrick. Thanks for that detailed response. I spent like 5 days asking that question, so had you replied with a one-liner, I probably would have thrown my computer and/or myself out the window. :smiley:

What you said about WPT recording the last document onload makes sense, and I suspected that might be the case, based on the observation that older IEs were loading favicon.ico well before the Document Complete line. But then I started to second-guess that theory when I looked at the Safari results. 2 out of the 3 results don’t show any Document Complete line, and the one that does…shows it in a place that doesn’t make sense.

Also, when I view the Network tab in Safari’s dev tools (Safari 5.1.2 on Windows 7), I see the document’s load event right where I expect it to be: after the 3rd HTTP request. In other words, I can’t duplicate WPT’s results for Safari.

Any insight here?

The other thing I wanted to ask you about is the possibility of configuring WPT to track the first document load event (in addition to what it’s already tracking), for example, by modifying my window.load function to insert a unique element (e.g.,

) into the DOM…and telling WPT to record when that element becomes available. (I thought I remembered doing something like this in the past, but I can’t find any documentation on this feature.) If you could suggest a workable strategy here, I’d really appreciate it.