Today, I want to show you how I structure all my JavaScript files at a basic level. Putting some thought into how you organize your code makes it easier for you and other developers to read and work with.

To make this simple, let's look at a really contrived example. For all click events that occur within the #app element, we want to log the clicked element to the console.

Immediately-invoked function expression

For most projects, I want my code to run immediately when the page loads. I also want to keep it out of the global scope to avoid naming conflicts with other scripts. To do this, I start with an immediately-invoked function expression (IIFE, pronounced 'iffy'):

;(function () {

// Opt into ES5 strict mode
"use strict";

})();

Variables

At the top of my IIFE, I add all my global variables. It's nice to have them all in one place at the top so you can easily find and change them.

For this example, we just need to get the #app element:

;(function () {

// Opt into ES5 strict mode
"use strict";

//
// Variables
//

// Get the #app element
var app = document.querySelector("#app");

})();

Functions

Next, I add all my functions. Using named, modular functions really helps keep your code more readable and maintainble.

For this example, we'll create a logElement() function that logs the clicked element to the console:

;(function () {

// Opt into ES5 strict mode
"use strict";

//
// Variables
//

// Get the #app element
var app = document.querySelector("#app");


//
// Functions
//

/**
* Log the clicked element to the console
* @param {Object} event The Event object
*/

function logElement (event) {
console.log(event.target);
}

})();

Inits & Event Listeners

Finally, I add my inits and event listeners to the bottom of the IIFE. This is where I put any code that actually initializes the app, as opposed to just creating variables and functions.

For this example, we just need to add our click handler to the #app element:

;(function () {

// Opt into ES5 strict mode
"use strict";

//
// Variables
//

// Get the #app element
var app = document.querySelector("#app");


//
// Functions
//

/**
* Log the clicked element to the console
* @param {Object} event The Event object
*/

function logElement (event) {
console.log(event.target);
}


//
// Inits & Event Listeners
//

// Log all click events that occur inside #app
app.addEventListener("click", logElement);

})();

Wrapping up

And there you have it: how I structure all my JavaScript files on a basic level. I recommend keeping the comments and spacing. These will be stripped out from minified production code anyway, so optimize for readability, not brevity.

I'd like to thank Chris Ferdinandi and Todd Motto for influencing my approach. You can find more boilerplates on The Vanilla JS Toolkit, which Chris maintains. Let me know if you'd like me to write about them. 😊