6.9. Performance

Yahoo published a list of best practices for improving web application performance.

Click Framework provides a PerformanceFilter which caters for some of these rules. However not all rules can be easily automated.

This section outlines how to apply some important rules which are not covered by the PerformanceFilter namely, Minimize HTTP Requests (by combining files) and Minify JavaScript and CSS.

The Rule, Minimize HTTP Requests, also mentions CSS Sprites, a method for combining multiple images into a single master image. CSS Sprites can boost performance when your application has many images, however it is harder to create and maintain. Note that CSS Sprites is not covered here.

It is worth pointing out that its not necessary to optimize every page in your application. Instead concentrate on popular pages, for example a web site's Home Page would be a good candidate.

There are a couple of tools that are useful in applying the rules "Minimize HTTP Requests" and "Minify JavaScript and CSS":

Below are some articles outlining how to use YUICompressor and Ant to concatenate and compress JavaScript and CSS files:

Using one of the approaches above you can concatenate and compress all JavaScript and CSS for your Pages into two separate files, for example home-page.css and home-page.js. Note that the two files must include all the JavaScript and CSS that is generated by the Page and its Controls. Then you can instruct Click to only include the two compressed files, home-page.css and home-page.js.

The Click Page class exposes the property includeControlHeadElements that indicates whether Controls have their CSS and JavaScript resources included or not.

To optimize Page loading one can override Page.getHeadElements(), and import the JavaScript and CSS files and then set the property includeControlHeadElements to false, indicating that Controls won't contribute their own JavaScript and CSS resources.

Here is an example:

public class HomePage extends Page {

    private Form form = new Form("form");

    public void onInit() {
        // Indicate that Controls should not import their head elements
        setIncludeControlHeadElements(false);

        form.add(new EmailField("email");
        addControl(form);
    }

    public List getHeadElements() {
        if (headElements == null) {
            headElements = super.getHeadElements();

            headElements.add(new CssImport("/assets/css/home-page.css"));
            headElements.add(new JsImport("/assets/js/home-page.js"));
        }
        return headElements;
    }
}

Using the following border-template.htm:

<html>
  <head>
    <title>Click Examples</title>
    ${headElements}
  </head>
  <body>

  ...

  ${jsElements}
  </body>
</html>

the rendered HTML will include one CSS and one JavaScript import:

<html>
  <head>
    <title>Click Examples</title>
    <link type="text/css" rel="stylesheet"
          href="/click-examples/assets/css/home-page.css" title="Style"/>
  </head>
  <body>

  ...

  <script type="text/javascript" src="/click-examples/assets/js/home-page.js"></script>
  </body>
</html>

A live demo is available here