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
This section describes what Expire Header caching is, its benefits, and how to configure it for your HPI builds
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:
- Client requests SearchConfig from OC. Last modified date of cached SearchConfig was Oct 13th, 2017 at 10 AM.
- Server checks if SearchConfig has been modified since Oct 13th, 2017 at 10 AM.
- 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-modified304
response. - 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.
- Client checks local cache for
logo.png
. Client sees if current datetime is before or after Expire Header expiration datetime - 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 oflogo.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.
Currently, Expire Headers should only be used with require.js
and any static HPI images, not with any CSS files. This is because:
- Images are rarely modified, so we are safe to cache these
- The
require.js
is given a unique id in every build, so a new HPI deployment will have a newrequire-########.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.
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
- To uglify your require js file, find the requirejs task and change the optimize option from
none
touglify
- 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
- Ex: if you want to remove the dashboard module:
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"}
]