admin管理员组

文章数量:1321827

Per default, Angular fetches the HTML templates from the server when the user navigates to a route. With that in mind, imagine this scenario:

  • User loads the Angular app. The main view has a subpage called "Order".
  • While the user is studying the main view a new version of the app is rolled out in production. The new version has a plete rewrite of the Order page with new Javscript and HTML.
  • The user navigates to the Order page. The Javascript is already loaded by the browser in step 1, so the user is on the old version until app is reloaded. But the new template gets fetched from the server on navigation. So now the Javascript and template are our of sync!

Is my assumption that the Javascript/HTML is out of sync, correct?

If so, are there any best practices related to this issue?

I guess one solution is the make Angular fetch all the templates on app initialization. But this could be a performance penalty if the app has hundreds of HTML views.

Per default, Angular fetches the HTML templates from the server when the user navigates to a route. With that in mind, imagine this scenario:

  • User loads the Angular app. The main view has a subpage called "Order".
  • While the user is studying the main view a new version of the app is rolled out in production. The new version has a plete rewrite of the Order page with new Javscript and HTML.
  • The user navigates to the Order page. The Javascript is already loaded by the browser in step 1, so the user is on the old version until app is reloaded. But the new template gets fetched from the server on navigation. So now the Javascript and template are our of sync!

Is my assumption that the Javascript/HTML is out of sync, correct?

If so, are there any best practices related to this issue?

I guess one solution is the make Angular fetch all the templates on app initialization. But this could be a performance penalty if the app has hundreds of HTML views.

Share Improve this question asked Feb 27, 2015 at 15:34 HoffZHoffZ 7,7296 gold badges39 silver badges40 bronze badges 2
  • How about using html2js (github./karlgoldstein/grunt-html2js) so you don't even have to retrieve HTML from the server? More code to load initially, but way less requests to the server (which could also translate into a performance penalty). – jlowcs Commented Feb 28, 2015 at 15:53
  • Thanks for good answers, everybody. I will try some of them out and report back. – HoffZ Commented Mar 5, 2015 at 11:39
Add a ment  | 

7 Answers 7

Reset to default 2

I've never wondered about that issue myself. One possible idea would be to reuse the pattern known as assets versioning, where upon new release, you rename all your assets.

For instance, instead of login.html you'd use login-xyz.html as a name of a template. xyz could be a random value, or a checksum of the file. Checksum might be a slightly better option because if the new release is small (i.e. you fixed just some small bug in one file), if user loads any page but the fixed one, he/she will not be bothered with a reload - all other files will have the same checksums, they'll work with no interruptions.

This way, when an outdated Anguar app tries to fetch a template, it'd get a HTTP 404 error. As an addition to that, you could write a simple $http interceptor, which would detect a 404 response, and reload page automatically (or offer user an option of doing so).

There are modules which are capable of renaming assets, such as gulp-rev - but I never heard of using that for Angular templates. You might implement something like that on your own, though.

Of course you might want to keep both the new and old versions of files to allow users to work without interrupting them with a refresh. Depends on what your requirements are. I assume you're trying to avoid that, though.


Sample 404 interceptor (CoffeScript, as I have it handy now):

m.factory 'notFoundInterceptor', ($q) ->
  return {
    responseError: (response) ->
        if response?.status == 404
            # Reload, or warn user
            return $q.defer()

        # Not a 404, so handle it elsewhere
        $q.reject response
  }

m.config ($httpProvider) ->
  $httpProvider.interceptors.push 'notFoundInterceptor'

Thanks for good answers.

It turned out that this problem solved itself for us. Every time we roll out a new release all the users sessions gets deleted and users will be sent to the login page. This will trigger a page load and fresh JavaScript/HTML gets loaded.

I've read about this issue long time ago, and one option is to do versioning on changed pages and application.js file.

For example on your version 1 of your application you can on your html file use something like:

<script src="js/angular_app_v1.js"></script>

Inside your routes also version the templateURL

templateUrl: 'templates/view_product_v1.html'

So when you roll out a new version you won't be overwriting templates and users already working will have the old version until they reload the browser but won't have version inconsistences.

Versioning of the assets using the file names would bee unmaintainable for even a medium sided app.

Although it is a heavy weight approach for web assets you could look into content negotiation. This is where the call for a resource, generally a REST api returns the version of the resource, Content-Type: application/vnd.contentful.delivery.v1+json.. On the client you can check that the version matches what it expects. So if the client only knows how to load v1.1 and the resource responses with v1.2 the UI would know it cannot process that and should reload the page.

Another possibility is to load all templates up front in the UI. There are build processes in Grunt you can run such as https://github./ericclemmons/grunt-angular-templates that will bine all of your templates into a single file for delivery and then load them into $templateCache so no requests ever get to the server.

If you have some sort of server-side language you can build a filter in (.NET, Rails, Java or whatever), and pass along a version number with your template requests. If the version requested by the client is older than what's deployed, you'd send an error to the client. Your client would watch for that error ($http interceptor) and force a page-refresh to pull down the newer javascript code. (Maybe show an alert to the user first so they know what's going on).

You can preload all your templates into a $templateCache and serve them as one templates.js file. There is a gulp task for this https://www.npmjs./package/gulp-angular-templatecache. Then your application will load all templates in a single request together with application scripts on start up, thus they will be in sync. Read http://www.johnpapa/angular-and-gulp/ for more info.

It always makes sense to have a version number and use it when syncing resources. It's not only a good practice for the use case you described, but also for other situation, such as rolling back to a specific version or having two versions live and usable (for example in order to let some users preview the next version)

本文标签: AngularJS best practiceTemplates vs JavascriptStack Overflow