Relative Paths and PushState in Durandal
Tim Kye
Modern browsers support the history.pushState
api for changing the URL without actually navigating on the page. This is a nice replacement for hash-based navigation (where a hash-route is used to change the page without navigating, due to the hash not going to the server) since the URL looks like a normal, clean url. Other than smoother navigation, the implementation is invisible to the user.
But the server has to support this. It can do this in a couple ways, but it really depends on how the client is handling things.
- The server can respond to requests for individual pages by rendering them for the client in their final state.
- The server can respond to all requests with the same initial page, leaving the work of rendering the correct page state to the client
- The server can perform some half-breed solution.
Durandal expects the 2nd scenario. It's router is fully responsible for the client-side rendering as well as navigation. It will examine the URL and load the correct page via its own composition sytem. But you can run into a problem, as I did, with relative paths. Consider the following two requests:
www.site.com
www.site.com/projects/first
In this case, if the shell that Durandal gets from the server references is initial css and js files using paths like lib/require
and css/main.css
, the second request will look for those under the projects
directory. And fail. If, like me, you were using a wildcard route in NodeJS, after it fails to find a static file, the wildcard will return the initail html for those css and js requests. All kinds of crazy errors will result.
As I found out from this stackoverflow question, the solution is simple. Just add /
to the begining of paths to make them absolute. /lib/require
and /css/main.css
. Now both responses will correctly retrieve their static files.
Note: if you are hosting your project under a non-root directory, you will need to add it to all of these links.