Jump to content

AJAX and caching structural problem


joe_g
 Share

Recommended Posts

Hi,

I think I fell into a bit of a structural trap. I built a site using pushstate and client side routing. 

On the top of all pages I check if the request is an ajax request like so:

if(!$config->ajax) {
  echo $pages->get('/')->render(); 
} else {
  ...serve the page
}

...if the user ask for /an/url/ they will get / instead but the clientside routing will handle the path. And, in the future, it would be easy to check if the request is from a search spider, then I would also just serve the content straight up. Clever, I thought.

Except it doesn't work with caching. (doh!). With this method an url using client side routing cannot be the same as the 'real' url underneath. How do you experts solve this? I was hoping there was a generic method that would work with all urls. I would like to have the same client side structure as server side structure as possible. I can see my options being

1. making separate urls for ajax request for everything /url and /url-ajax (ugly and high maintenance)

2. prefix the client side url with something client side /site/url/ maps to server side /url/ (easy and generic, but a bit weird for the user)

3. prefix the ajax calls with /ajax/url/ then server side get /url/ and remap all url segments (cleanest but url segments will cause trouble)

4. The traditional web app way: Use .htacces to serve / instead of /url/ if it's not a ajax call. (this might be the best option perhaps? Although I'm not an expert with .htaccess, this is what puts me off). I suppose with this method I could still use the caching, since the pages are effectively always ajax from processwire perpective (except root "/"). But this solution won't work with procache, I assume.

Is there an easier way that I've missed? I have a feeling I'm missing some common knowledge, since this might be a common problem?

I guess it would have been handy if /url/?ajax would create a separate cache entry than /url/, then I could simply append ?ajax to all ajax calls. But I think I understand that won't work since any GET variables basically turns off the caching, as far I understand.

Any thoughts, tips, or comments are highly appreciated. 

thanks,

J

Link to comment
Share on other sites

To be honest I'm not really sure what you're trying to achieve here, but what I'd probably consider (without fully understanding your situation, so this might be completely off!) would be serving the page user is asking for without current "render home page if this isn't an AJAX request" trick. This way there shouldn't be any caching issues and as an added "bonus" all sorts of crawlers, users with JS disabled, screen reader users etc. could still use your site.

Assuming that pages requested via AJAX (using this clientside routing you mentioned) can be directly mapped to "real pages" by their URLs (and are, in fact, identical to those) I can't see what the problem with that approach would be. Unless there's something on your home page that is required for the rest of the site to work properly, i.e. other pages actually only contain part of what the user should end up seeing, in which case I'd consider fixing current template structure to take care of that by including common header/footer files etc. if the request isn't AJAX.

Anyway, I'm sure we could come up with various tricks to enable caching here (been there, done that) but first I'd really like to understand why this is even necessary in the first place. There's probably a reason, I'm just not seeing it right now :)

Link to comment
Share on other sites

Thanks Teppo, appreciate the help. My issue might be more about general pushstate/AJAX than processwire, probably. Sorry if the question is a bit sweeping.

Maybe I can be more clear with an example (ignoring SEO for now):

What I do now:

1. I have an url /list/open/first-item/ that shows a list of things where the first item is selected

2. The request is not ajax, so / gets sent instead

3. Client side, I load the two parts /list/ and /first-item/ and put them in place

It works, but I can't cache /list/. In other words the URL's collide. I have to make sure the ajax fragments have separate urls (option 1 above).

What I probably should be doing:

1. The url /list/open/first-item/ should recreate the exact same output as if it was done client side

2. send response to client, done

In general, what I think I have to do is:

1. create separate url's for all fragments like (/list-fragment/ and /open-item-fragment/first-item/) so that the urls doesn't collide.

2. For every url, server side, paste together a response that is identical if it would be done client side.

Is there any good way to do the double logic both server and client side? To at least try and do this as DRY as possible ;) ?

thanks!

J

Link to comment
Share on other sites

To conclude my lengthy rant:

1. Any ajax page combining parts of html fragments must be re-done server side. I guess there is no way around that everything has to be done twice (both server and client side).

The alternative seems to be node (but then missing all the processwire goodness):

http://stackoverflow.com/questions/20588865/node-framework-to-render-on-both-ends

2. Then my other problem I had is that any html fragment used for ajax loading can't have conditionals combined with caching (if ajax then), but that's quite obvious really.

cheers,

J

Link to comment
Share on other sites

  • 2 months later...

The only option I see is adding an url segment to the 'ajax' links with javascript and only if your browser is compatible with pushState.

Say you push ajax/ to the end of the url, that way you can have the page cached and the URL segment cached.

I know this is ugly...  :rolleyes:

if($config->ajax && $input->urlSegment(1) === 'ajax') {
  ...serve the page
} else {
  echo $pages->get('/')->render(); 
}

It's not ugly if you do it like this:

$.ajax({
    url: default.url + "ajax/", // assumed the url to get is in default.url, and we append the ajax urlSegment
    cache: true
}).done(function (markup) {
    $("#container").html(markup);
});
Edited by Martijn Geerts
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...