Performance Enhancements - tsgrp/HPI GitHub Wiki

This page describes HPI modifications that can improve the responsiveness of HPI for the end user on all browsers

Using Expire Headers for static content

This section describes what Expire Header caching is, its benefits, and how to configure it for your HPI builds

How Expire Header caching works

Caching comes in many flavors, the most common method being checking an object's last modified date against the providing server. This is the methodology used for most OC caching, like when accessing Config files. For example:

  1. Client requests SearchConfig from OC. Last modified date of cached SearchConfig was Oct 13th, 2017 at 10 AM.
  2. Server checks if SearchConfig has been modified since Oct 13th, 2017 at 10 AM.
  3. If SearchConfig has been changed since that date, the newest version is returned to the client with a 200 response. If not, the client just receives a not-modified 304 response.
  4. Client loads the SearchConfig, either the new version from the server or the cached version based on the server's response.

This approach has one issue: it requires the client to reach out to the server to check if the content has changed. For content that might change often and without notice, this makes sense. But for more "static" content like logos and images that technically never change (more on this below), why bother checking with the server? Instead we can use the Expire Header.

The Expire Header tells the Client how long an object can be used from cache before another call needs to be made to the server to check if the object has been modified.

  1. Client checks local cache for logo.png. Client sees if current datetime is before or after Expire Header expiration datetime
  2. If before, client uses local cached copy of logo.png. If after, client will contact server to validate the cached version is the latest version of logo.png

For sites with many static objects (or applications with a few larger static objects), this can reduce a user's total bandwidth usage, making other calls respond sooner and give the end user better response times. This is especially important for users that access a site or application via the Internet rather than their organizations intranet or extranet. For HPI, using Expire Headers removes network calls that ask for icons, logos, even require.js itself.

Caveat

Currently, Expire Headers should only be used with require.js and any static HPI images, not with any CSS files. This is because:

  1. Images are rarely modified, so we are safe to cache these
  2. The require.js is given a unique id in every build, so a new HPI deployment will have a new require-########.js file, forcing the user to download the new file and cache that.

We should make an effort to make all static content (images, CSS, JavaScript) uniquely identified in each build. This will allow us to cache ALL static content locally with Expire Headers, safe knowing that any changes that come with a new HPI deployment will be pulled down by the end users.

How to configure Expire Header caching

Expire header caching can easily be implemented into HPI's web.xml file. To enable it, paste the following into the web.xml between the context-param bean and the filter bean:

  <filter>
    <filter-name>ExpiresFilter</filter-name>
    <filter-class>org.apache.catalina.filters.ExpiresFilter</filter-class>
    <init-param>
      <param-name>ExpiresByType image</param-name>
      <param-value>access plus 5 days</param-value>
    </init-param>
    <init-param>
      <param-name>ExpiresByType application/javascript</param-name>
      <param-value>access plus 5 days</param-value>
    </init-param>
  </filter>

  <filter-mapping>
    <filter-name>ExpiresFilter</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
  </filter-mapping>

Change 5 days to any number and length of time you see fit for your client: year(s), month(s), week(s), day(s), hour(s), minute(s), second(s). For more information on configuring the Expire Headers for tomcat, please visit https://tomcat.apache.org/tomcat-7.0-doc/config/filter.html#Expires_Filter

Gruntfile changes

  1. To uglify your require js file, find the requirejs task and change the optimize option from none to uglify
  2. To exclude unused modules from your requiredjs, find the copy:base task and in the files option for the app source code (should by default have src: "app/**") and change the src option to an array still beginning with "app/**", but then with an ! before each module you would like to remove.
    • Ex: if you want to remove the dashboard module: {expand: true, src: ["app/**", "!app/modules/dashboard/**", "!app/templates/dashboard/**"],dest: "BUILD/"}
    • Note: When you remove a module from the build, you will need to remove the references to it. In the example above removing the dashboard module, you will need to update your configuredrouters.js to remove the DashboardRouter.
    • With our example here is what the entire files option in the copy:base task should look like
    files: [
        {src: "index.html", dest: "BUILD/index.html"},
        {expand: true, src: ["app/**", "!app/modules/dashboard/**", "!app/templates/dashboard/**"],dest: "BUILD/"},
        {expand: true, src: ["assets/**"], dest: "BUILD/"},
        {expand: true, src: "hpi-wrapper/**", dest:"BUILD/"},
        {expand: true, src: "test/**", dest:"BUILD/"},
        {src: "test/mockjquery.js", dest: "BUILD/test/mockjquery.js"}
    ]
⚠️ **GitHub.com Fallback** ⚠️