1

I have an angular app running in a browser on a tablet in a store. The app is a single page app, and the page is never reloaded. This gives a problem, because when I deploy a new version of the app to the server (html, css, js and backend services) the app will not be up to date unless I manually reload the page.

A workaround is to implement a scheduled page refresh in my js-code. The problem with this, is that if the reload happens when the server is down, I get a 404 or 500 and am stuck on this error page until I reload the page.

A workaround for this is to call a service to check that the server is fine before doing the page reload. This will minimize the risk, but not eliminate it.

But is it possible (in a fairly simple way) to have the angular app somehow fetch the new html, js, css from the server and only replace the version that is currently downloaded to the server if all requests result in a http status code 200?

Basically I want the result of a page reload but only if all elements can be fetched from the server. If not I want to keep what I had.

1
  • What do you need to reload? With angular's two way data binding you can reload your views after getting a response from the server. That way you have the new data (user info etc). When you get a response from the server, mutate the $scope with the new data Commented Jan 23, 2017 at 20:11

3 Answers 3

1

So, this answer is going to be a little more complicated than you might like, but will be the best way to handle the problem, in my opinion.

Yes, you could set up some kind of poll to detect when to update the app, then swap out the html with the new html, but, you can't scrub the JS from a page. So it's going to get nasty after a few updates.

Here's what you do, set up a WebSocketServer. When you need to update your app, do a ws.send to tell the app to refresh itself.

I'm assuming a refresh isn't bad, just inconvenient since your app is located in a tablet on the store floor somewhere.

Server Side:

const WebSocket = require('ws');

class WebSocketServer {
  constructor() {
    this.wss = new WebSocket.Server({port:8282, perMessageDeflate:false});
    console.log(`Websocket on: ${8282}`);
    this.clients = {};
    this.wss.on('connection', (ws) => {
    ws.on('message', (message) => {//collect clients for later messages
      this.myWebApp = ws;
    });
    ws.send("Connected to websocket");
  })
}
  updateApp(port, message) {
    this.myWebApp.send("refresh");
  }
}


const express = require('express');
const cors = require('cors');
const cookieParser = require('cookie-parser');
let bodyParser = require('body-parser');


class ExpressServer {
  constructor() {
    this.port = 8181;
    this.websocketServer = new WebsocketServer();
    let server = express();
    this.router = express.Router();
    this.router.use(cookieParser());
    server.use(cors());
    this.setupRoutes(server);
    server.listen(this.port);
    console.log(`Server listening on: ${this.port}`);
  }
  setupRoutes(server) {
    server.post('/updateApp', (req, res, next) => {
      this.websocketServer.updateApp();
      res.sendStatus(200)
    });
  }
}

let server = new ExpressServer();

Client Side:

let ws = new WebSocket('ws://ip.of.websocket.server:8282');
ws.onmessage = (data, flags) => {
  if(data === "refresh") {
    window.location.reload()
  }
}

The code here isn't intended to work, per se, but it should point you in the right direction.

I've assumed that you'll only have one app running. If you have multiple, you'd need to do a broadcast, as described here:

https://github.com/websockets/ws

The idea is that you can hit the updateApps endpoint and that will trigger a websocket send to your app.

This should avoid your 404/500 problem, since the app will never be asked to update when the server is down, since the server drives the updates.

You'll want to implement some stuff to maintain the websocket connection, but I'll let you do the digging on that.

Bonus Points: Look into Progressive Web Apps. They enable offline use, ensure http calls complete even if the connection goes down for a while, and allow push notifications.

Sign up to request clarification or add additional context in comments.

Comments

1

The way I'm handling this is I return a version number within a custom header option of each http response made to the backend. If the response header version mismatches my frontend's local app version then it would force a window.location.reload()

So whenever a change is made that requires reloading the frontend, just update the version on the backend, which you should have control of.

1 Comment

Another way I've seen this done is that you generate a version.json file within your build/prod directory with something like {"version": "1.1.1"} so when you rebuild your script you update that version each time. Then have your app run a http call against that file directly (example.com/version.json) every so often, so that if detects a change in that version number then do a app reload.
0

In this case I think that your best choice is to have the schedule reload function. This could be a function that periodically check from the server if a new version is available. If you get an 404 or 500 error, you just schedule the function in a short time after the error.

Only when a successful 200 response with a version change is detected you proceed to reload the page.

Example:

angular.app('app', [])
.run(['$timeout', '$http', '$window', function($timeout, $http, $window){

    var standardCheckInterval = 360000, criticalCheckInterval = 4000;
    var currentVersion = 0;

    // obtain the current version from the server
    function getCurrentVersion() {
        return $http.get('/app/version');
    }

    // get the current version
    getCurrentVersion().then(function(response) { currentVersion = response.Data; })

    // check an app version change
    function checkAppVersionChange() {

        getCurrentVersion()

                .then(function (response) {

                    // we get a different version, reload   
                    if(currentVersion != response.Data) {

                        $window.location.reload(); 
                    }
                    else {

                        // all good, just schedule again for a future update
                        $timeout(checkAppVersionChange, standardCheckInterval);

                    }

                }, function(error) {

                    // something bad happen 404 or 500, recheck soon
                    $timeout(checkAppVersionChange, criticalCheckInterval);

                });

    }

    // schedule the check function
    $timeout(checkAppVersionChange, standardCheckInterval);

}]);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.