The changes in version 5.4.0 of the A-Z Directory are worthy of a full version change, but I’ve made a steadfast rule where full versions only take place when the module template changes. In this case, version 5.4.0 was a complete refactoring of the Javascript, eliminating the jQuery and Bootstrap dependencies. The module template remains unchanged.
jQuery and Bootstrap are great libraries. Seriously, the native capabilities of today’s Javascript would not exist without jQuery’s excellent API forging the way so many years ago. And Bootstrap is a great tool for rapidly creating a responsive grid, with common components, in a consistently styled interface. But these libraries are heavy, increasing page load times. Using jQuery slows site performance because all the Javascript has to be interpreted by the API first, instead of directly by the browser’s Javascript engine.
Most of the module Javascript dealt with AJAX calls, click events, and basic DOM manipulation. Converting these functions from jQuery to native Javascript was fairly straightforward. The functionality of displaying a modal if a user clicks on the contact name, and supporting the tabs and sliders within that modal, was where the real challenge lied.
The watershed moment was when I stumbled across a wonderful little library called Native JavaScript for Bootstrap. It’s a well-supported, well-documented, and much smaller library providing parity with the Bootstrap components. With it, I was able to refactor the Javascript to use its components exclusively. There were several gotchas which I’ll share in more detail below:
Modal Content Flicker
Using Bootstrap, I had an issue where the modal content would flicker, briefly displaying previously clicked contact information before displaying the active contact information. To solve this, I added the following line within my click handler:
jQuery( "#modazdirectory__modal" ).removeData( "modal" );
I had the same content flicker with the Native JavaScript for Bootstrap modal, but there is no native Javascript equivalent to jQuery’s .removeData
, which is a way to purge jQuery-defined cached data. The key was to remove the event listeners associated with the modal. So, I invoked the modal with the following:
// instantiate the modal | |
var modazModalInstance = new Modal( modazModal ); | |
modazModalInstance.show(); | |
modazModal.addEventListener( 'shown.bs.modal', function _modazNativeBS() { | |
// AJAX call to get the contact information | |
// Set the HTML as the modal content | |
// Handle Plain, Tabs, and Sliders depending on the display format | |
// Prevent content flickering | |
modazModal.removeEventListener( 'shown.bs.modal', _modazNativeBS ); | |
}); |
The removeEventListener
, once the code within the shown.bs.modal
event had executed, prevented the content flickering.
Joomla Loads jQuery and Bootstrap as Part of the Contact Information
As I described in the version 5 release, adding tmpl=component
to the URL will display only the contents of a page without the surrounding context. However, this still loads the jQuery and Bootstrap libraries. This has been a long-standing issue, especially because if the template loads jQuery and Bootstrap, these libraries get loaded twice. To address this issue, I parsed the returned responseText from the AJAX call using the following code:
var modazParser = new DOMParser(); | |
var modazHtml = modazParser.parseFromString( modazXhr.responseText, 'text/html' ); | |
var modazPerson = modazHtml.querySelectorAll( '.contact' ); |
Joomla wraps a single contact in <div class="contact">
. Now, modazPerson
just contained the contact information as a nodeList and I was able to iterate over that nodeList to set the content of the modal.
Bootstrap and Native JavaScript for Bootstrap
What if a template already loads jQuery and Bootstrap? I couldn’t have any conflicts between them and the Native JavaScript for Bootstrap library. These libraries are well written, and the encapsulation prevented any namespace or variable conflicts. However, in addition to a click listener assigned to the contact names by the Javascript within the A-Z Directory module, jQuery also assigned a click listener. So the click event fired twice causing duplicate tabs and two instances of the modal backdrop. To prevent this, I added event.stopPropagation();
just after the addEventListener
for the name click.
Conclusion
So why do all this? Personally, I had fun with the challenge of removing the jQuery and Bootstrap dependencies, but the real return on investment is the performance improvements.
- Time to render the modal was cut in half. With jQuery and Bootstrap loading the modals, it took on average 2.518 seconds. Without those dependencies, it took on average 1.276 seconds.
- If your template is not loading Bootstrap, page size is reduced by 163 KB. If your template is using Bootstrap, page size is reduced by 134 KB.