Reputation: 3281
I have built a largely directive-based AngularJS HTML5 application. Each directive will load it's template from another file, using the templateUrl
syntax.
The application is a single-page application, let's pretend it's accessible via http://prod/index.html
, and when that page is loaded a directive will then load http://prod/partials/directive-a.html
I'm having problems when pushing out new releases of the website to my production enviroment. The browser is continuing to use cached assets from the previous version.
For example, if I navigate to http://prod
, all the assets are shown from the previous version. If I force-refresh the page (CTRL+F5
), the index.html page will be re-loaded from the server and reflect any changes.
This does not cause the browser to refresh the partials/directive-a.html
. Therefore, the new index.html
page still shows the old directive-a.html
.
If I navigate to the full partial HTML file (partials/directive-a.html
) in the browser address bar, the old version of the partial is presented to me. By hard-refreshing the partial page the correct (new) version of the partial will be shown, and also be updated when the directive on index.html
is reloaded.
What mechanisms are available to me to prevent the caching of partials?
I've seen commentary about appending a timestamp to the query arguments, but this seems overly clunky to put on all of my directives and routes.
Upvotes: 2
Views: 1013
Reputation: 4013
@Duncan gave you awesome way to deal with templates, but I think it is not the only problem. Please remember about caching js
, css
and index.html
.
Simple solution
If you want simple (almost ideal) solution for cache problem, you can force server to set session cookie at first request (for index.html
). Browser will cache html
and js
for session's length. You will still have partial cache support and no problems.
# First response header will set session id:
Set-Cookie:JSESSIONID=0E9AAA7D661A3E100C8EE9F421541B91; Expires=Sun, 29-Jan-2017 14:25:25 GMT; Path=/; HttpOnly
# Next browser request will contain session id from first response.
Cookie:JSESSIONID=0E9AAA7D661A3E100C8EE9F421541B91
Complicated solution
You should consider using custom headers for serving Angular assets. You can use mod_expires
inside of apache
.
ExpiresByType text/html "access plus 0 seconds"
ExpiresByType application/javascript "access plus 0 seconds"
ExpiresByType text/css "access plus 0 seconds"
...
The problem of this solution is losing cache mechanism. Returning users will not load your site faster and your server will experience more usage. You can run in performance problems.
You can improve this solution by building mechanism:
application.js
application.js
application.js
to application.[unique-id].js
index.html
The same applies to css
and 3rd party libraries.
After that you will be able to change
ExpiresByType text/html "access plus 0 seconds"
ExpiresByType application/javascript "access plus 1 year"
ExpiresByType text/css "access plus 1 year"
...
Obviously, there are automated solutions based on Grunt
or Gulp
. Personally, I can recommend https://github.com/yeoman/generator-angular
Both solutions are working in my current apps.
Upvotes: 2
Reputation: 95652
I haven't tested to see if this works (found with a quick Google search), though I think it should . It is decorating the $http
service so that any requests have a cache-buster added to the url. You probably want to change the logic to only decorate urls in your 'partials/'
folder.
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;
}]);
}]);
From https://gist.github.com/ProLoser/6181026
Alternatively compile all of the partials into a single templates.js
file that populates the template cache and then you have no actual http requests for the templates at all. If you use gulp
to build your application then there are various plugin modules to do this (e.g. gulp-angular-templatecache
or gulp-angular-templates
).
Upvotes: 1