34

today a question was raised here and I don't have an evident answer.

Assume that we concatenate and minify all resource files (CSS and Javascript) and declare them in the "Master-Page".

On a multi-page app, if a CSS file changes it will be recharged on the next full page load.

On a single-page app, the user can keep working for days and never recharge the main page where the CSS files are declared. The user will never see the changes until a Ctrl-F5 is issued.

I'm sure someone already thought of this and have an experience to share :)

For me, using WebSockets is not an option. First because it's overkill and second because not all my clients support the technology. Same reason applies to all WebSockets fallbacks... I won't keep hitting my servers because of this.

So, any ideas anyone? :)

BTW, we're using AngularJS if that can help for a specific solution.

Thanks!

AlexCode
  • 4,055
  • 4
  • 33
  • 46

3 Answers3

32

I've getting through this same problem. My solution which is opinionated and may not respond to your criterias:

When I package my front-app and my server-app, I share a configuration file containing the current version of the front-app.

Front side: 75% of my routes change implicitly call a Webservice (route change resolve). SO each time I call my server I include a custom HTTP header (or a GET/POST param) containing the client version of the front-app.

Server side : I compare the front-app version (the one in the browser of the user, loaded last time user refreshed/loaded the SPA) with the front-app version of the shared configuration file :

  • If version matches : I Do nothing.
  • If version don't match I send a custom HTTP status error code (418 for example)

Then front side: I added a response Interceptor that intercepts any 418 error code and do a force-refresh of the whole app

That's it. Basically the event that "check" if the front-app version is the latest is a route change (that calls a WS via ajax). But you could add some infinite $interval calling a dedicated WS each 5 minutes or so... I can add some code if needed.

Hope this helps ;)

hatef
  • 5,491
  • 30
  • 43
  • 46
Jscti
  • 14,096
  • 4
  • 62
  • 87
  • My initial idea was to do it the other way around, make the back-end send the version and do the comparison on the client but there's a common problem in both approaches: I have multiple RESTful services each ones with independent versions and know nothing about a specific app so they can never validate this. Althogh, as I'm writing, I'm thinking that maybe the reverse proxy, that is application specific, could do the job... – AlexCode Apr 14 '14 at 10:01
  • infinite $timeout translates to WebSockets or it's fallbacks more specifically Longpolling which I don't want to use for this. This won't often enough to justify continuously hitting the server for verification. – AlexCode Apr 14 '14 at 10:04
  • Yep, the choice here is dependant on your whole technical architecture.. BTW if websockets are overkill and too recent, you coulsd take a look at SSE (server sent events : http://www.w3schools.com/html/html5_serversentevents.asp) which are way lighter that socket.io for example (it's uni-directionnal server->client push) – Jscti Apr 14 '14 at 10:06
  • Yep there are some polyfills available but as always with more or less constraints. You have all the possible choices now ;) – Jscti Apr 14 '14 at 10:14
  • So we went for a reduced solution for now. As we have a "proxy service" that is (again for now) the only one that interacts with this application, we added the application version on the http header of all responses. If we receive a newer version, a popup appears notifying the user and a full page refresh is issued... This solution won't work for applications that connect to multiple services, and I don't agree completely with it but it works for now. – AlexCode Apr 15 '14 at 12:36
  • @Cétia: Hi. Can you please provide suggestions or tips as to how to manage versions of a single page application? Do I manually add a version on the server side that I retrieve on the client side? Is there an automated way around this? – balteo Aug 30 '15 at 11:48
2

Assuming that you are using AngularJS' routing via $route service and provider, then you can use $routeChangeSuccess event to perform a server request if there are significant changes that needs to be changed; if there are any then you can do a window.location.reload() to refresh the page and get all the updated resources and htmls.

The following process can be changed depending on how you want to implement it:

1. Setup a config file in your server indicating the app's version. You may also choose to assign different versions for different files but since you have concatenated all your resource files then I guess you may limit your version options in your configuration.

2. Create a service that contains all the necessary information(versions of files from the server) and methods to perform a server request to your server to check against the current file versions stored in the service.

3. Use $routeChangeSuccess event to perform a server request using the service that you have created in step 2, if the request returned a valid confirmation that there were changes then do the force page reload via window.location.reload().

ryeballar
  • 29,658
  • 10
  • 65
  • 74
2

I decided to add my final thoughts as an answer here too:

We went for a reduced solution for now.

As we have a "proxy service" that is (again for now) the only one that interacts with this application, we added the application version on the http header of all responses. If we receive a newer version, a popup appears notifying the user and a full page refresh is issued...

This solution won't work for applications that don't have their own "private" service.

AlexCode
  • 4,055
  • 4
  • 33
  • 46
  • 1
    I still can't find a satisfied solution. I asked my question here with new information https://softwareengineering.stackexchange.com/questions/423068/options-to-notify-users-single-page-application-spa-static-resources-have-upda – Qiulang Mar 06 '21 at 04:26