How we like to write our JavaScript

We like to keep things simple, lean, and fast which means we usually just write vanilla JavaScript. We find this helps us keep our code easy to read and expressive. While jQuery can be great in some situations it’s usually not absolutely necessary, and it can make it very easy to write JavaScript that degrades performance.

In jQuery, almost everything is based around the DOM and it effects the way you write code. When calling methods on elements, it can be difficult to write modules that are extensible and re-usable. We find vanilla JavaScript makes it a lot easier to think about the logic path of your code and pass in data (elements, nodes etc) rather than ‘attaching’ code to specific elements.

Of course, this is not a hard and fast rule, these are only guidelines. Many libraries out there require jQuery as a dependency, but by not having jQuery included by default, it adds that extra stop and thinking point. Here you can take a step back and ask yourself, is adding this library necessary or worthwhile for the sake of the project? Is there something better out there? Something vanilla based? Open source? Maintained? So far, we’ve managed to find Vanilla libraries for pretty much everything we’ve required: GSAP (Animation), Barba.js (Page Transitions), Waypoints.js (Scroll triggers) etc.

As for the JavaScript version we like to write, we prefer to use ES5 (ECMAScript 5) as it’s supported in all the browsers we support. There is currently a big push to use new features that can be found in ES6 (ES2015, yes it’s confusing) things like const, let and () => {} (arrow functions). We haven’t adopted ES6 yet as it still requires things like babel to process your code and convert it back into ES5 and make it compatible with Internet Explorer.

Components for all the things – main.js sucks!

We like to split our JavaScript code into components – groups of code that work together to do one thing well. We try to write these components in a specific structure. This means any developer at Crowd can pick the code up, read it, and know how it works. Here’s a real world example taken from Aramex 2016’s codebase:

var animate = (function() {
    'use strict';

    var elements  = [],
        waypoints = [],
        selectors = [
            '.fade-in-up'
        ];

    function setWaypoint(element, index) {
        waypoints[index] = new Waypoint({
            element: element,
            handler: function() {
                this.element.classList.add('animate');
                waypoints[index].destroy();
            },
            offset: '90%'
        });
    }

    function init() {
        elements = [].slice.call(document.querySelectorAll(selectors.join(',')));

        if(!elements.length) {
            return;
        }

        elements.forEach(setWaypoint);
    }

    document.addEventListener('DOMContentLoaded', init);

    return {
        init: init
    }
}());

The whole component is wrapped in a self executing function that gets assigned to a variable. By wrapping our code like this, we can decide what code is ‘public’ (global scope) and what’s ‘private’ (local scope) and hidden away from the rest of the JavaScript on the page. In the example component above, the init function is made public by the return statement and the setWaypoint function is private.

Technically, this pattern is actually called ‘The revealing module pattern’ 🤓 and has loads of useful explanations and articles all over the web, feel free to have a look around.

We like our variable definitions easy to understand and at the top!

At the top we declare the variables that we use in the component, this way they’re accessible from anywhere within the local scope of the component. We think using shorthand is good – it’s up to you whether you leave variables unassigned (see elements & waypoints above), or set their default values (see the selectors array above).

Bring order to spaghetti functions 🍝

Our linter likes functions to be defined before they’re used and so do we.

In the example above we have an init function that is set up to be executed on the DOMContentLoaded event. The init function queries some elements in the DOM and then calls the setWaypoint function on each element it found.

Ordering the code so functions are defined before they’re called means the DOMContentLoaded event listener needs to be at the bottom, the init function above it, and the setWaypoint function above that.

This ordering technique can be applied to even the largest of components and makes picking through code easier and developers happier.

Writing APIs for components

At the bottom of the component we return an object that contains functions and variables that we want to make accessible from outside of our component. You can think of this bit as a way of defining an API for your component which allows it to be used in conjunction with other JavaScript.

Making components work together

Some components don’t initialise automatically and instead need to be triggered by other JavaScript code. Often these components need to be passed configuration objects – like a carousel component that allows you to turn features on and off.

As long as the function you want to execute is returned in the object at the bottom of the component, you can trigger it in another file. The returned objects can be accessed using the component’s assigned variable (this is called a ‘namespace’ in some languages). In the example above, it’s possible to trigger the init function with the following syntax:

animate.init();

Let’s say you’re looking to trigger animate.init() in the callback from a tab system. The code for that might look like this:

// tab-system-implementation.js
(function() {
    'use strict';

    var config;

    function initTabSystem() {
        config = {
            element: document.querySelector('.tab-container'),
            tabChangeCallback: function() {
                animate.init();
            }
        };

        myTabSystem.init(config);
    }

    document.addEventListener('DOMContentLoaded', initTabSystem, false);
}());

In this example, an implementation file initialises a tab system component, and makes use of the animate component.

Gulp, jshint, concat, uglify, magic.js, < insert more buzzwords here>, done. Oh and Webpack, maybe?

Our standard Gulp file will process all JavaScript files you add to your src/js folder. Here you can write your modules, in separate files and know they will be handled by the build process.

Each file will be ‘linted’ or ‘hinted’ via JSHint with some very basic rules. Our current JSHint setup will only ever warn you, so it’s a good idea to keep an eye on your terminal, but it won’t ever break your build or stop it from working.

Be part of the Crowd

We're always on the lookout for talent, and currently have offices in the USA, Canada, UK, Dubai, and China.

If you fancy being a part of a global multicultural development team that strives to do the best work possible, email us at results@thisiscrowd.com