BootsFaces Resource Loading Deep Dive

Many BootsFaces developers want to add third-party code to BootsFaces. Usually, that’s a Bootstrap component, a jQueryUI plugin or another combination of JavaScript and CSS. Almost always, these plugins fail to work if they are loaded in the wrong order. So BootsFaces added a fine-grained mechanism allowing you to control the load order.

To my dismay, the resource ordering still causes a lot of trouble, so it’s high time to describe it in detail.

First principles

We’ve optimized BootsFaces with a couple of goals in mind:

  • Developers are free to use either the bundled or their own version of jQuery, jQueryUI, Bootstrap, and Font Awesome.
  • We want BootsFaces to be compatible with PrimeFaces.
  • We also want it to be compatible with LiferayFaces.
  • Developers are allowed to include any jQuery or Bootstrap plugin they want.
  • The CombinedResourceListener of OmniFaces should also play well with BootsFaces.

As it turns out, some of these goals are not easy to achieve. In order to use PrimeFaces and BootsFaces in the same project, you have to override a couple of Bootstrap CSS rules. I don’t think using your own version of Bootstrap works because we’ve tried to minimize the size of the CSS files. Instead of delivering the standard Bootstrap.min.css file, each component merely adds its own Bootstrap component snippet. And the decision to support Liferay only works out now. Liferay finally migrated to Bootstrap 3.

Adding your own resource files

Standard JSF already has a mechanism to order resource files. It’s limited to JavaScript files. By default, an <h:outputScript /> is generated exactly where it appears in the JSF source code. If you put it into the <h:head /> sections, it’ll be part of the header. If you put it into the body, the JavaScript code will be generated at the position you’ve placed the tag.

Adding the target attribute changes that. target="head" always puts the script in the header. target="body" puts the script at the end of the body. Like so often, Yong Mook Kim, better known as Mkyong, covers the topic in depth with instructive examples.

BootsFaces adds another attribute. position applies to both CSS and JavaScript files, but only to the files in the header. They are loaded in this order:

  • position="first"
  • position="middle"
  • JavaScript resources without a position attribute are sorted and put between middle and last.
  • CSS resources are added between middle and last without being sorted.
  • position="last"

jQuery first!

The third bullet point mentions “sorting”, and that’s where the magic begins. Any file that’s called jquery.js is put first. BootsFaces ignores the character case, and you may add a version number to the file. All that counts is that the lower-case version of the filename contains the substring jquery.

Unless it also contains the suffix -ui. It’s obvious that jQueryUI needs to be added after jQuery.

The next two files are the two files needed to initialize Bootstrap: ui/core.js and ui/widget.js.

After that, every other JavaScript file without a position attribute is added in the original order.

The last file to be added is the AJAX engine of BootsFaces (bsf.js).

Bring your own device

Many developers prefer to bring their own version of jQuery. So BootsFaces examines the names of the resource files added by the developer. It adds its own version of jQuery, jQueryUI and so on if and only if it doesn’t find these files:

  • A JavaScript file containing the substring jquery-ui is considered as jQueryUI. The case is ignored.
  • A JavaScript file containing the substring jquery (but not jquery-ui) is considered as jQuery. The case is ignored.
  • A CSS file containing the substring font-awesome or fontawesome is considered as Font Awesome. The case is ignored.

web.xml parameters

Alternatively, you can configure your web.xml to suppress certain resources:

  • Setting the context parameter net.bootsfaces.get_fontawesome_from_cdn to “yes” or “true” allows you to provide your own Font Awesome file.
  • Setting the context parameter net.bootsfaces.get_jquery_from_cdn to “yes” or “true” allows you to provide your own jQuery file.
  • Setting the context parameter net.bootsfaces.get_jqueryui_from_cdn to “yes” or “true” allows you to provide your own jQueryUI file.
  • Setting the context parameter net.bootsfaces.get_bootstrap_from_cdn to “yes” or “true” allows you to provide your own Bootstrap CSS file. As mentioned above, this option is a bit difficult to get up and running. BootsFaces modifies the original Bootstrap files. That’s only a handful of lines of code, but be warned. Currently, we’re aware of changes in these files:

Implementation hints

Originally, we used the standard JSF annotations (such as @@ResourceDependency) to add resource files. However, we needed more flexibility to support the themes of Bootstrap. Simply overriding the HeadRenderer wasn’t a choice because that’s exactly what both Liferay and PrimeFaces do. So we found another choice. It’s possible to implement an event listener that’s fired each time a resource file is added. It took us several months (maybe even years) to get it right, but currently, our AddResourcesListener works good enough in most cases.