jQuery to ES6 and what if you don’t need a JS framework…

A few years ago if you needed to add some interactive feature or functionality to your website the chances are you’d reach out for the DOM-centric selector sexiness of jQuery. These days however with the rise of “the modern javascript framework” more and more developers are flocking to these tools, (and for good reason). But what if your site doesn’t require a state and a declarative UI… should we still be using jQuery or is there an alternative way, a better way, an ES6 way?

I want to state = { workInProgress: true } that this is very much a work in progress and more of a high level overview of our build process. It works for our specific needs as an agency but might not fit your own.

A precursor

In our static sites prior to moving to ES6 we would utilise libraries like Bootstrap and customise them accordingly using jQuery for any more complex interactivity. However after a while we found that our JS would quickly become bloated, unstructured, hard to maintain and difficult to pass between developers. While these issues can’t solely be blamed on our use of jQuery some technologies such as BEM, SASS and Twig encourage modularity, structure and maintainability in our codebase whereas jQuery doesn’t, and as a growing agency we wanted to change this.


The plan

We had a clear idea of what we wanted to accomplish with the transition from jQuery to ES6 so we laid out some key features:

  • Modularity
    We wanted to break down our JS file structure to replicate something more similar to our SASS setup, separating functions into separate files and using ES6 import to pull through only what we needed per project.
  • Structure
    To improve cross-project knowledge and the passing of projects between developers we wanted to encourage common structuring of functions, at least at the beginning of a project.
  • Adaptability
    Sometimes our builds are passed onto a client who in turn insert them into their own stack to add more data driven content. Due to this it was important that our JS could be “hooked” (buzzwords yes please) into and updated accordingly, regardless of the client’s stack.
  • Modern
    At Inktrap we also develop more data driven web applications where the use of a framework such as React or Vue.js is required and ES6 is heavily used. We wanted to make sure that building a static site would also utilise the same or similar methods and thought process as our more complex builds, even if it wasn’t using a framework.

The results

We decided to first create a folder structure and split up our functions into files — this consisted of the following:

Within the globals.js we created two global objects, FUNCTIONS & INSTANCES which I’ll briefly go into now:

FUNCTIONS :
An object of, you guessed it – all the function handlers in the site which can be called from the front-end at any time to initialise interactivity on any DOM elements.

INSTANCES :
An object consisting of any initialised class instances (which we call “modules”) containing methods and callbacks that can be accessed by any other JS functions.

We then came up with a common structure for our function handlers, here's an example being used in dropdownsHandler.js:

As you can see within the function handler we are initialising a new instance of our dropdown module. To give you a quick idea of what this does here’s an example of the initialisation and public methods that module provides.


Now — the above might seem a little like overkill just to initialise a simple dropdown. However using this method will give us access to two important abilities when it comes to “hooking” (yes I know) our front-end system into other client environments.

Before I go into that though, here’s a quick view of our load.js file which deals with the overall initialisation of our function handlers on page load:

After using the initialisation method above we now have access to our global FUNCTIONS & INSTANCES objects from the window object and we can see what they contain in the console:

The above visualises those two important abilities I mentioned earlier — the first being we now have a list of our custom function handlers that can be called at any point using:
 window.FUNCTIONS.dropdownHandler(‘.myPassedElement’); 
- this is particularly useful for initialising over dynamic content thats been rendered after page load.

And secondly we now also have a list of any instances that have been initialised, each with their own methods and callbacks available to use elsewhere within our JS, for example:
 window.INSTANCES.dropdowns.helloImADropdown.showDropdown();

Both of these abilities were essential in making our front-end templates more adaptable to any client environment due to the fact they can now “hook” (last time I promise) into almost any aspect of our JS.


Our learnings

After we implemented this approach on a couple of production projects this is what we learnt, aside from the benefits previously mentioned above:

  • Back-porting
    With modularity comes improved maintainability. In other words, by splitting up all of our functions into defined files, whenever we added new functionality or fixed a bug, we could easily back-port it into all other projects using the same system without worrying too much about merge conflicts.
  • Improved cross-project knowledge
    If every function is built using the common initialisation structure it makes it easier to pass between developers as they already have an idea of what they’re looking for and working with.
  • Removing reliance and improving control
    By removing libraries such as bootstrap and jQuery we no longer relied on third party tools so heavily and had complete control over what our clients had access to and utilise from our front-end JS.
  • Fallbacks
    Because we do not use a javascript dependant view (essentially we are using the base stack of HTML, CSS, JS) if for some reason our JS doesn’t load the user will still receive some resemblance of our site with HTML and CSS. Essentially we add the JS as an additional interactive layer, initialised by our markup.

Final thoughts, feelings & emotions

Now many of these practices above have been used before however usually in the context of a framework rather than a static site which is what gave me the idea to write this article. I believe there is a space between a static site and a full blown JS SPA which needs some attention and although I don’t think this is the perfect solution, in my mind its a start.

As I mentioned also in the beginning of this article, this is very much a high level overview of our build process specifically looking at our transition from jQuery to ES6 and the benefits it’s had. There’s plenty more I would like to go into such as how we initialise our JS from markup in a consistent way, our SASS/BEM setup and even potentially open sourcing our boilerplate repo but in the interest of time I wanted to keep this article (relatively) concise.

I do however plan on continuing to report on our learnings as we meander through these ever changing times of JS.

If you’ve got any feedback we’d love to hear from you — please leave a comment here, or drop us a line on Twitter, we’re @InktrapDesign.