Angular template versioning

2019-08-18 22:49发布

问题:

I observed that often unexpected issues occurs with my apps as the user has templates cached in browser. I tried $window.location.reload(true) but even then chrome serves templates from the cache.

Is there an easy solution for this like adding a version query parameter to template URL dynamically using something like Interceptor?

回答1:

Although on other similar question people sugested to use $templateCache and load everything in one go. This isn't the solution I was looking for as it would increase app first load time by increasing app size and sacrifing on lazy loading provided by angular-ui-router.

So, below is what I did. Created a value provider for which contains version. This file is minified and include in index page and thus gets loaded along with the page.

angular.module('my-app').value('version', 'X.X.X');

I noticed that all my templateUrl in states, directives and even in ng-include is loaded via $http service and thus at time of fetching template I can inject a query parameter. So I added following lines in app's config block:

angular.module('my-app').config(['$httpProvider', function($httpProvider){
    $httpProvider.interceptors.push(['$q', 'version', function($q, version) {
        return {
            'request': function (request) {
                if (request.url.substr(-5) == '.html') {
                    request.params = {
                        v: version
                    }
                }
                return $q.resolve(request);
            }
        }
    }]);
}]);

So, all my templates are called with version number and now browser waits for new template to load if version is increased. I periodically check for version update via an api. And if a new version is detected, I prompt user to reload the page. On user approval, I reload it via $window.location.reload(true)

Update

Following is snippet to check for new version. It can vary according to use case. As we have ad-hoc release cycle here, we check for new version on each window focus and also during first load.

angular.module('my-app').run(['$rootScope', '$window', 'version', 'configService', function($rootScope, $window, version, configService){
    $rootScope.checkVersion = function () {
        configService.getVersion().then(function (data) {
            if (data.version != version) {
                // show user a message that new version is available
                promptUserForReload().then(function () {
                    $window.location.reload(true);
                })
            }
        });
    }

    $window.addEventListener("focus", $rootScope.checkVersion);

    $rootScope.checkVersion();
}])


回答2:

Without interceptor u can just add post fix version variable to template url. templateUrl:'scripts/apps/blabla.html?version?ver='+version