问题
I'm currently running into trouble when releasing new versions of my SPA since the html templates are being cached by the browser.
My SPA uses Angular 1.5, ocLazyload and ui-router. I have configured gulp tasks to use cache-busting technique (with gulp-rev), and it is working pretty well, at least with the script and css files. However, when we have changes on html files the browser keeps loading the old version. Sometimes even refreshing the page with Ctrl+F5 doesn't solve the problem and it keeps showing the old version of html.
In addition, configuring the browser to not make cache of html files isn't desirable (specially for mobile), since html changes may occur not very often.
Is there any good solution that address this problem for fetching html files only when there is new versions of it?
Thanks in advance!
回答1:
As you are using gulp, you could make use of gulp-angular-templateCache, which is a gulp plugin to collect all your html files, concatenate them into a single javascript file and add them to AngularJS' $templateCache based on the file path.
gulp.task('default', function () {
return gulp.src('app/**/*.html')
.pipe(templateCache({
module: 'yourModuleName'
}))
.pipe(gulp.dest('dist'));
});
The resulting JavaScript file contains something like:
angular.module('yourModuleName').run([$templateCache,
function($templateCache) {
$templateCache.put('app/path/to/some-template.html",
// some-template.html content comes here (escaped)
);
}
]);
You could now add this file to your bundle, any changes to your html file will update the content of your bundle hence result in an updated cache buster.
But if you do not want the entire bundle to be updated, you could keep them seperated and ensure the file get's loaded after your bundle.
Note: both of the above approaches do break the cache for all html files once one of them has changed, but all of those html files are retrieved using a single call.
An alternative approach could be to add cache busters to your html files and update all the usages of that file to include the cache buster's hash. But I'm not really a fan of this approach.
Edit: The first approach is the one I use in my gulp-based projects. However, these days I'm using AngularJS with Webpack (See my starter) and I'm using an approach comparable to Midhun Darvin's 3th method (see here), but instead of requirejs
I'm making use of webpack
. However, keep in mind that this approach (using either requirejs
or webpack
) will result in the html files being added to the javascript file containing your angularjs code. This means any change to a javascript file will brake the cache for all your html files as the cache buster will be updated.
回答2:
I had this problem in a project that i worked on. I tried these methods.
Method 1 : Setting cache property false of different states.
var core = angular.module('app.core');
core.cofigure(configure);
configure.$inject = ['$stateProvider'];
// Configuration Function
function configure($stateProvider){
$stateProvider
.state('login', {
url: '/login/:redirect/:viewId',
cache: false, // Here i have set the cache property to false
templateUrl: 'app/layout/login.html'
})
.state('home', {
url: "/home",
cache: false, // Here also
abstract: true,
templateUrl: 'app/layout/container.html'
});
}
Now this method was fine, But it was not working at random times and in the Internet Explorer.
Method 2 : Adding a Timestamp to the template URL.
// I created a timestamp string with the current time.
var date = new Date().getTime().toString();
$stateProvider
.state('login', {
url: '/login/:redirect/:viewId',
cache: false,
// Now i append it here
templateUrl: 'app/layout/login.html' +'?' + date
})
.state('home', {
url: "/home",
cache: false,
abstract: true,
templateUrl: 'app/layout/container.html' + '?' + date // Here also.
});
This method is what we decided on after searching for possible fixes to this problem. However no caching takes place in this case. Each GET Request for the template file is different and it will guarantee that the template loaded will be the updated one. But if you are building a web application that has a lot of templates and client side performance is essential, this method won't be helpful.
Method 3 : require templates
I recommend this method. You can use require.js in your application to load the templates when javascript executes. This will load the templates when the running the application for development purpose and also when you minify your code for production. Since the templates are loaded into the javascript code, you don't have to keep the html template files when deploying to production as well.
$stateProvider
.state('login', {
url: '/login/:redirect/:viewId',
// Note 'template' and not 'templateUrl'
template: require('app/layout/login.html')
})
.state('home', {
url: "/home",
abstract: true,
template: require('app/layout/container.html')
});
回答3:
I recommend an approach similar to option 2 from @Midhun Darvin (so I used their code as a base). Instead of using a date, use a version number. With each release you just need to remember to update the version number and all html files will have their cache busted.
// update this with every release
var version = 0.1.0;
// make make this easier so you don't have to add query strings to all your template calls
var v = "?v=" + version;
$stateProvider
.state('login', {
url: '/login/:redirect/:viewId',
cache: false,
templateUrl: 'app/layout/login.html' + v // version added to bust cache
})
.state('home', {
url: "/home",
cache: false,
abstract: true,
templateUrl: 'app/layout/container.html' + v // version added to bust cache
});
来源:https://stackoverflow.com/questions/42816258/how-to-reload-templates-html-when-releasing-a-new-version-of-a-spa