Skip to content

Instantly share code, notes, and snippets.

@ProLoser
Last active September 10, 2020 12:54
Show Gist options
  • Star 43 You must be signed in to star a gist
  • Fork 13 You must be signed in to fork a gist
  • Save ProLoser/6181026 to your computer and use it in GitHub Desktop.
Save ProLoser/6181026 to your computer and use it in GitHub Desktop.
Elegant cache-busting for AngularJS HTML assets
anglar.module('myApp',['ui']).config(["$provide", function($provide) {
return $provide.decorator("$http", ["$delegate", function($delegate) {
var get = $delegate.get;
$delegate.get = function(url, config) {
// Check is to avoid breaking AngularUI ui-bootstrap-tpls.js: "template/accordion/accordion-group.html"
if (!~url.indexOf('template/')) {
// Append ?v=[cacheBustVersion] to url
url += (url.indexOf("?") === -1 ? "?" : "&");
url += "v=" + cacheBustVersion;
}
return get(url, config);
};
return $delegate;
}]);
}]);
@rmariuzzo
Copy link

Interesting.

@christopherthielen
Copy link

this gist is the second google result for 'cache busting $templateCache` 👍

@ericjames
Copy link

Cool now just how do we get cacheBustVersion

@Techek
Copy link

Techek commented Jan 11, 2017

@ericjames: I've done it this way

  1. Have Grunt get the buildVersion from AssemblyInfo (if available) or generate a unique string if version could not be extracted.
  2. Have Grunt build a file "config.js" using Node package "ngconstant"
  3. Configure ngconstant to add a "ENV"-parameter with eg. a property BuildNo set to the buildVersion in the config.js file (creates a module called "config" with an Angular-constant "ENV")
  4. The ENV-constant can then be injected in any app.module config-section and you can access ENV.BuildNo

If you have a localhost-target in your gruntfile, consider setting BuildNo to a fixed value, so you browser is not busted locally.

@Mexassi
Copy link

Mexassi commented Jan 13, 2017

Great and simple!

@spirant
Copy link

spirant commented May 24, 2017

Hi. Thank you for writing this. It has really helped me. I was just wondering if anyone could help in getting my Karma test to work for this? I am using the server to create a cache bust constant every time I run a build. I then pass this constant into the .config.

I have tried adding it where the constants required in a service would go, but I guess that the Constant needs to get to the module prior to running a service as it runs during the configuration phase?

Chrome 58.0.3029 (Windows 10 0.0.0) View Service setShowDeleted method Return 0 if undefined FAILED
        Error: [$injector:modulerr] Failed to instantiate module homer due to:
        Error: [$injector:unpr] Unknown provider: CACHE_BUST
        http://errors.angularjs.org/1.6.3/$injector/unpr?p0=CACHE_BUST
            at resources/bower_components/angular/angular.js:66:12
            at resources/bower_components/angular/angular.js:4789:19
            at getService (resources/bower_components/angular/angular.js:4944:32)
            at injectionArgs (resources/bower_components/angular/angular.js:4969:58)
            at Object.invoke (resources/bower_components/angular/angular.js:4995:18)
            at runInvokeQueue (resources/bower_components/angular/angular.js:4890:35)
            at resources/bower_components/angular/angular.js:4900:11
            at forEach (resources/bower_components/angular/angular.js:402:20)
            at loadModules (resources/bower_components/angular/angular.js:4880:5)
            at Object.createInjector [as injector] (resources/bower_components/angular/angular.js:4802:19)

    <script>
        angular.module("homer")
            .constant("CSRF_TOKEN", "{{ csrf_token() }}")
            .constant("CACHE_BUST", "[token created by server goes here]"));
    </script>
    .config(["$provide", "CACHE_BUST", function($provide, CACHE_BUST) {
    return $provide.decorator("$http", ["$delegate", function($delegate) {
        var get = $delegate.get;
        $delegate.get = function(url, config) {
            // Check is to avoid breaking AngularUI ui-bootstrap-tpls.js: "template/accordion/accordion-group.html"
            if (!~url.indexOf('template/') && !~url.indexOf('ui-grid')) {
                // Append ?v=[cacheBustVersion] to url
                url += (url.indexOf("?") === -1 ? "?" : "&");
                url += "v=" + CACHE_BUST;
            }
            return get(url, config);
        };
        return $delegate;
    }]);
}])
angular.module('homer').factory('VatBandPusherService', VatBandPusherService)
VatBandPusherService.$inject = ['$rootScope', 'PusherService', 'UiGridService']

function VatBandPusherService($rootScope, PusherService, UiGridService) {
    VatBandPusherService.config = function(scope, idName) {
        // Broadcasting Methods
        var pusher = PusherService.createNewInstance();
        var my_channel = pusher.subscribe('private-VatBand');
...
        return;
    };
    return VatBandPusherService;
};
describe('VatBandPusherService Test', function () {

    var VatBandPusherService, PusherService, mockPusherService;

    beforeEach(function() {
        module('homer', function($provide) {
            $provide.constant('CSRF_TOKEN', 'MOCK_CONSTANT');     // This is working
            $provide.constant('CACHE_BUST', 'MOCK_CONSTANT');    // This is not working

            var mockPusherService= { 
                createNewInstance: function () {
                    return 'mockReturnValue';
                }
            };
            $provide.constant('PusherService', mockPusherService);

        });
    });

    beforeEach(inject(function (_VatBandPusherService_) {
        VatBandPusherService = _VatBandPusherService_;
    }));


    // A simple test to verify the factory exists
    it('Service should exist', function() {
        expect(VatBandPusherService).toBeDefined();
    });


});

Any ideas would be much appreciated.

@jeffreygnatek
Copy link

not to be a jerk but typo on line 1 😄

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment